已关闭
[TDD用例补充] #902
[TDD用例补充] #902
已关闭
UUUnni创建于 8月24日关闭于 8月29日
共 17 个文件变更+6687-1
@@ -35,6 +35,8 @@ group("dlp_permission_build_module_test") {
35 ":dlp_permission_sdk_load_test",35 ":dlp_permission_sdk_load_test",
36 ":dlp_transparent_enc_manager_test",36 ":dlp_transparent_enc_manager_test",
37 ":dlp_transparent_enc_policy_test",37 ":dlp_transparent_enc_policy_test",
38+ ":huks_adapt_manager_static_test",
39+ ":dlp_permission_service_ext_branch_test",
38 ]40 ]
39 }41 }
40}42}
@@ -509,6 +511,207 @@ ohos_unittest("dlp_credential_static_test") {
509 ]511 ]
510}512}
511 513 
514+ohos_unittest("dlp_permission_service_ext_branch_test") {
515+ branch_protector_ret = "pac_ret"
516+ 
517+ sanitize = {
518+ integer_overflow = true
519+ cfi = true
520+ cfi_cross_dso = true
521+ debug = false
522+ }
523+ 
524+ subsystem_name = "security"
525+ part_name = "dlp_permission_service"
526+ module_out_path = part_name + "/" + part_name
527+ 
528+ include_dirs = [
529+ "${dlp_root_dir}/test/unittest/sa/mock",
530+ "${dlp_root_dir}/services/dlp_permission/sa/adapt_utils/account_adapt",
531+ "${dlp_root_dir}/services/dlp_permission/sa/adapt_utils/alg_adapt/alg_manager/include",
532+ "${dlp_root_dir}/services/dlp_permission/sa/adapt_utils/alg_adapt/huks_adapt_manager/include",
533+ "${dlp_root_dir}/services/dlp_permission/sa/adapt_utils/app_observer",
534+ "${dlp_root_dir}/services/dlp_permission/sa/adapt_utils/critical_handler",
535+ "${dlp_root_dir}/services/dlp_permission/sa/adapt_utils/file_manager",
536+ "${dlp_root_dir}/services/dlp_permission/sa/mock",
537+ "${dlp_root_dir}/services/dlp_permission/sa/sa_main",
538+ "${dlp_root_dir}/services/dlp_permission/sa/sa_common",
539+ "${dlp_root_dir}/services/dlp_permission/sa/storage/include",
540+ "${dlp_root_dir}/services/dlp_permission/sa/callback/dlp_sandbox_change_callback/",
541+ "${dlp_root_dir}/services/dlp_permission/sa/callback/open_dlp_file_callback/",
542+ "${dlp_root_dir}/frameworks/common/include",
543+ "${dlp_root_dir}/frameworks/dlp_permission/include",
544+ "${dlp_root_dir}/interfaces/inner_api/dlp_permission/include",
545+ "${dlp_root_dir}/interfaces/inner_api/dlp_parse/include",
546+ "${dlp_root_dir}/test/sa/static",
547+ ]
548+ 
549+ sources = [
550+ "unittest/sa/src/dlp_permission_service_ext_branch_test.cpp",
551+ "${dlp_root_dir}/test/unittest/sa/mock/dlp_os_account_mock.cpp",
552+ "${dlp_root_dir}/services/dlp_permission/sa/sa_main/dlp_credential.cpp",
553+ "${dlp_root_dir}/services/dlp_permission/sa/sa_main/dlp_permission_async_proxy.cpp",
554+ "${dlp_root_dir}/services/dlp_permission/sa/sa_main/dlp_permission_service.cpp",
555+ "${dlp_root_dir}/services/dlp_permission/sa/sa_main/dlp_permission_service_ext.cpp",
556+ "${dlp_root_dir}/frameworks/common/src/cert_parcel.cpp",
557+ "${dlp_root_dir}/frameworks/common/src/permission_policy.cpp",
558+ "${dlp_root_dir}/frameworks/common/src/retention_sandbox_info.cpp",
559+ "${dlp_root_dir}/frameworks/common/src/visited_dlp_file_info.cpp",
560+ "${dlp_root_dir}/frameworks/dlp_permission/src/auth_user_info_parcel.cpp",
561+ "${dlp_root_dir}/frameworks/dlp_permission/src/dlp_permission_info_parcel.cpp",
562+ "${dlp_root_dir}/frameworks/dlp_permission/src/dlp_policy_parcel.cpp",
563+ "${dlp_root_dir}/frameworks/dlp_permission/src/dlp_sandbox_callback_info_parcel.cpp",
564+ "${dlp_root_dir}/frameworks/dlp_permission/src/open_dlp_file_callback_info_parcel.cpp",
565+ "${dlp_root_dir}/interfaces/inner_api/dlp_permission/src/dlp_permission_public_interface.cpp",
566+ "${dlp_root_dir}/interfaces/inner_api/dlp_parse/src/dlp_utils.cpp",
567+ "${dlp_root_dir}/interfaces/inner_api/dlp_parse/src/dlp_zip.cpp",
568+ "${dlp_root_dir}/services/dlp_permission/sa/adapt_utils/alg_adapt/alg_manager/src/alg_manager.cpp",
569+ "${dlp_root_dir}/services/dlp_permission/sa/adapt_utils/alg_adapt/alg_manager/src/alg_utils.cpp",
570+ "${dlp_root_dir}/services/dlp_permission/sa/adapt_utils/alg_adapt/huks_adapt_manager/src/huks_adapt_manager.cpp",
571+ "${dlp_root_dir}/services/dlp_permission/sa/adapt_utils/account_adapt/account_adapt.cpp",
572+ "${dlp_root_dir}/services/dlp_permission/sa/adapt_utils/app_observer/app_state_observer.cpp",
573+ "${dlp_root_dir}/services/dlp_permission/sa/adapt_utils/app_observer/app_uninstall_observer.cpp",
574+ "${dlp_root_dir}/services/dlp_permission/sa/adapt_utils/critical_handler/critical_handler.cpp",
575+ "${dlp_root_dir}/services/dlp_permission/sa/adapt_utils/critical_handler/critical_helper.cpp",
576+ "${dlp_root_dir}/services/dlp_permission/sa/adapt_utils/file_manager/file_operator.cpp",
577+ "${dlp_root_dir}/services/dlp_permission/sa/adapt_utils/file_manager/retention_file_manager.cpp",
578+ "${dlp_root_dir}/services/dlp_permission/sa/adapt_utils/file_manager/sandbox_json_manager.cpp",
579+ "${dlp_root_dir}/services/dlp_permission/sa/adapt_utils/file_manager/visit_record_file_manager.cpp",
580+ "${dlp_root_dir}/services/dlp_permission/sa/adapt_utils/file_manager/visit_record_json_manager.cpp",
581+ "${dlp_root_dir}/services/dlp_permission/sa/callback/dlp_sandbox_change_callback/dlp_sandbox_change_callback_death_recipient.cpp",
582+ "${dlp_root_dir}/services/dlp_permission/sa/callback/dlp_sandbox_change_callback/dlp_sandbox_change_callback_manager.cpp",
583+ "${dlp_root_dir}/services/dlp_permission/sa/callback/dlp_sandbox_change_callback/dlp_sandbox_change_callback_proxy.cpp",
584+ "${dlp_root_dir}/services/dlp_permission/sa/callback/open_dlp_file_callback/open_dlp_file_callback_death_recipient.cpp",
585+ "${dlp_root_dir}/services/dlp_permission/sa/callback/open_dlp_file_callback/open_dlp_file_callback_manager.cpp",
586+ "${dlp_root_dir}/services/dlp_permission/sa/callback/open_dlp_file_callback/open_dlp_file_callback_proxy.cpp",
587+ "${dlp_root_dir}/services/dlp_permission/sa/mock/dlp_credential_service.c",
588+ "${dlp_root_dir}/services/dlp_permission/sa/mock/mock_utils.cpp",
589+ "${dlp_root_dir}/services/dlp_permission/sa/sa_common/access_token_adapter.cpp",
590+ "${dlp_root_dir}/services/dlp_permission/sa/sa_common/bundle_manager_adapter.cpp",
591+ "${dlp_root_dir}/services/dlp_permission/sa/sa_common/dlp_common_func.cpp",
592+ "${dlp_root_dir}/services/dlp_permission/sa/sa_common/dlp_feature_info.cpp",
593+ "${dlp_root_dir}/services/dlp_permission/sa/sa_common/permission_manager_adapter.cpp",
594+ "${dlp_root_dir}/services/dlp_permission/sa/sa_common/dlp_ability_adapter.cpp",
595+ "${dlp_root_dir}/services/dlp_permission/sa/sa_common/dlp_ability_conn.cpp",
596+ "${dlp_root_dir}/services/dlp_permission/sa/sa_common/dlp_ability_proxy.cpp",
597+ "${dlp_root_dir}/services/dlp_permission/sa/sa_common/dlp_ability_stub.cpp",
598+ "${dlp_root_dir}/services/dlp_permission/sa/sa_common/account_event_subscriber.cpp",
599+ "${dlp_root_dir}/services/dlp_permission/sa/sa_common/account_status_listener.cpp",
600+ "${dlp_root_dir}/services/dlp_permission/sa/storage/src/dlp_kv_data_storage.cpp",
601+ "${dlp_root_dir}/services/dlp_permission/sa/storage/src/sandbox_config_kv_data_storage.cpp",
602+ ]
603+ 
604+ configs = [
605+ "${dlp_root_dir}/config:coverage_flags",
606+ ":stub_tdd_need_skip_timer_config",
607+ ]
608+ 
609+ cflags_cc = [
610+ "-DHILOG_ENABLE",
611+ "-DDLP_UNIT_TEST",
612+ ]
613+ cflags = [ "-DHILOG_ENABLE" ]
614+ 
615+ deps = [
616+ "${dlp_permission_public_config_path}/:dlp_permission_stub",
617+ "${dlp_root_dir}/services/dlp_permission/sa:dlp_hex_string_static",
618+ "${dlp_root_dir}/services/dlp_permission/sa:dlp_permission_serializer_static",
619+ "${dlp_root_dir}/services/dlp_permission/sa:dlp_permission_service.rc",
620+ "${dlp_root_dir}/services/dlp_permission/sa/etc:param_files",
621+ ]
622+ 
623+ external_deps = [
624+ "ability_base:want",
625+ "ability_base:zuri",
626+ "ability_runtime:app_manager",
627+ "ability_runtime:extension_manager",
628+ "ability_runtime:ability_manager",
629+ "ability_runtime:ability_connect_callback_stub",
630+ "access_token:libaccesstoken_sdk",
631+ "access_token:libtokenid_sdk",
632+ "app_file_service:fileuri_native",
633+ "bounds_checking_function:libsec_shared",
634+ "bundle_framework:appexecfwk_base",
635+ "bundle_framework:appexecfwk_core",
636+ "c_utils:utils",
637+ "common_event_service:cesfwk_core",
638+ "common_event_service:cesfwk_innerkits",
639+ "config_policy:configpolicy_util",
640+ "eventhandler:libeventhandler",
641+ "hilog:libhilog",
642+ "hisysevent:libhisysevent",
643+ "huks:libhukssdk",
644+ "init:libbegetutil",
645+ "ipc:ipc_core",
646+ "json:nlohmann_json_static",
647+ "kv_store:distributeddata_inner",
648+ "memmgr:memmgrclient",
649+ "os_account:domain_account_innerkits",
650+ "os_account:libaccountkits",
651+ "os_account:os_account_innerkits",
652+ "safwk:system_ability_fwk",
653+ "samgr:samgr_proxy",
654+ "zlib:shared_libz",
655+ "window_manager:libwm_lite",
656+ "image_framework:image_native",
657+ "image_framework:image_source",
658+ "image_framework:image_source_ndk",
659+ "image_framework:pixelmap_ndk",
660+ "image_framework:pixelmap",
661+ "resource_management:librawfile",
662+ "graphic_2d:librender_service_client",
663+ "graphic_2d:librender_service_base",
664+ "napi:ace_napi",
665+ "ability_base:configuration",
666+ ]
667+}
668+ 
669+ohos_unittest("huks_adapt_manager_static_test") {
670+ branch_protector_ret = "pac_ret"
671+ 
672+ sanitize = {
673+ integer_overflow = true
674+ cfi = true
675+ cfi_cross_dso = true
676+ debug = false
677+ }
678+ 
679+ subsystem_name = "security"
680+ part_name = "dlp_permission_service"
681+ module_out_path = part_name + "/" + part_name
682+ 
683+ include_dirs = [
684+ "${dlp_root_dir}/test/unittest/mock",
685+ "${dlp_root_dir}/frameworks/common/include",
686+ "${dlp_root_dir}/services/dlp_permission/sa/adapt_utils/alg_adapt/alg_manager/include",
687+ "${dlp_root_dir}/services/dlp_permission/sa/adapt_utils/alg_adapt/huks_adapt_manager/include",
688+ "${dlp_root_dir}/services/dlp_permission/sa/adapt_utils/alg_adapt/huks_adapt_manager/src",
689+ ]
690+ 
691+ sources = [
692+ "unittest/sa/static/huks_adapt_manager_static_test.cpp",
693+ "${dlp_root_dir}/test/unittest/mock/c_mock_common.cpp",
694+ "${dlp_root_dir}/test/unittest/mock/huks_mock.cpp",
695+ ]
696+ 
697+ configs = [
698+ "${dlp_root_dir}/config:coverage_flags",
699+ ":stub_tdd_need_skip_timer_config",
700+ ]
701+ 
702+ cflags_cc = [
703+ "-DHILOG_ENABLE",
704+ "-DDLP_UNIT_TEST",
705+ ]
706+ cflags = [ "-DHILOG_ENABLE" ]
707+ 
708+ external_deps = [
709+ "bounds_checking_function:libsec_shared",
710+ "hilog:libhilog",
711+ "huks:libhukssdk",
712+ ]
713+}
714+ 
512ohos_unittest("dlp_permission_service_test") {715ohos_unittest("dlp_permission_service_test") {
513 branch_protector_ret = "pac_ret"716 branch_protector_ret = "pac_ret"
514 717 
@@ -1017,3 +1017,275 @@ HWTEST_F(DlpCryptTest, DlpOpensslAesEncryptAndDecrypt009, TestSize.Level0)
1017 ret = DlpOpensslAesDecrypt(&key, &usage, &mIn, &mEnc);1017 ret = DlpOpensslAesDecrypt(&key, &usage, &mIn, &mEnc);
1018 EXPECT_EQ(DLP_PARSE_ERROR_VALUE_INVALID, ret);1018 EXPECT_EQ(DLP_PARSE_ERROR_VALUE_INVALID, ret);
1019}1019}
1020+ 
1021+namespace {
1022+// constants for the branch cases below (aligned with dlp_crypt.cpp)
1023+constexpr uint32_t KEY_SIZE_TOO_SMALL = 4;
1024+constexpr uint32_t KEY_SIZE_TOO_LARGE = 1024 * 1024 + 8;
1025+constexpr uint32_t HMAC_OUT_SIZE_SMALL = 31;
1026+constexpr uint32_t DIGEST_ALG_SHA384 = DLP_DIGEST_SHA384;
1027+constexpr uint32_t DIGEST_ALG_SHA512 = DLP_DIGEST_SHA512;
1028+constexpr uint32_t DIGEST_ALG_UNKNOWN = 999;
1029+constexpr uint32_t HIAE_IN_LEN = 16;
1030+}
1031+ 
1032+/**
1033+ * @tc.name: ClearDlpHIAEMgrNullHandle001
1034+ * @tc.desc: cover null handle early return branch of ClearDlpHIAEMgr
1035+ * @tc.type: FUNC
1036+ * @tc.require:
1037+ */
1038+HWTEST_F(DlpCryptTest, ClearDlpHIAEMgrNullHandle001, TestSize.Level0)
1039+{
1040+ DLP_LOG_INFO(LABEL, "ClearDlpHIAEMgrNullHandle001");
1041+ // the HIAE sdk never loaded in the unit test environment: the handle is null and
1042+ // ClearDlpHIAEMgr returns early
1043+ ClearDlpHIAEMgr();
1044+ // a second call keeps taking the same branch (g_hIAECnt may go negative, harmless)
1045+ ClearDlpHIAEMgr();
1046+}
1047+ 
1048+/**
1049+ * @tc.name: DlpHIAEParamCheckBranch001
1050+ * @tc.desc: cover usageSpec/message/cipherText null branches of HIAEParamCheck
1051+ * @tc.type: FUNC
1052+ * @tc.require:
1053+ */
1054+HWTEST_F(DlpCryptTest, DlpHIAEParamCheckBranch001, TestSize.Level0)
1055+{
1056+ DLP_LOG_INFO(LABEL, "DlpHIAEParamCheckBranch001");
1057+ struct DlpBlob key = {32, g_key};
1058+ struct DlpCipherParam tagIv = {{16, g_iv}};
1059+ struct DlpUsageSpec usage = {DLP_MODE_HIAE, &tagIv};
1060+ 
1061+ uint8_t input[16] = "aaaaaaaaaaaaaaa";
1062+ uint8_t out[16] = {0};
1063+ 
1064+ // usageSpec == nullptr
1065+ ASSERT_EQ(DLP_PARSE_ERROR_VALUE_INVALID, DlpHIAEEncrypt(&key, nullptr, HIAE_IN_LEN, input, out));
1066+ ASSERT_EQ(DLP_PARSE_ERROR_VALUE_INVALID, DlpHIAEDecrypt(&key, nullptr, HIAE_IN_LEN, input, out));
1067+ 
1068+ // algParam == nullptr
1069+ struct DlpUsageSpec usageNoParam = {DLP_MODE_HIAE, nullptr};
1070+ ASSERT_EQ(DLP_PARSE_ERROR_VALUE_INVALID, DlpHIAEEncrypt(&key, &usageNoParam, HIAE_IN_LEN, input, out));
1071+ ASSERT_EQ(DLP_PARSE_ERROR_VALUE_INVALID, DlpHIAEDecrypt(&key, &usageNoParam, HIAE_IN_LEN, input, out));
1072+ 
1073+ // message == nullptr
1074+ ASSERT_EQ(DLP_PARSE_ERROR_VALUE_INVALID, DlpHIAEEncrypt(&key, &usage, HIAE_IN_LEN, nullptr, out));
1075+ ASSERT_EQ(DLP_PARSE_ERROR_VALUE_INVALID, DlpHIAEDecrypt(&key, &usage, HIAE_IN_LEN, nullptr, out));
1076+ 
1077+ // cipherText/plainText == nullptr
1078+ ASSERT_EQ(DLP_PARSE_ERROR_VALUE_INVALID, DlpHIAEEncrypt(&key, &usage, HIAE_IN_LEN, input, nullptr));
1079+ ASSERT_EQ(DLP_PARSE_ERROR_VALUE_INVALID, DlpHIAEDecrypt(&key, &usage, HIAE_IN_LEN, input, nullptr));
1080+ 
1081+ // key data == nullptr
1082+ struct DlpBlob nullKey = {32, nullptr};
1083+ ASSERT_EQ(DLP_PARSE_ERROR_VALUE_INVALID, DlpHIAEEncrypt(&nullKey, &usage, HIAE_IN_LEN, input, out));
1084+ ASSERT_EQ(DLP_PARSE_ERROR_VALUE_INVALID, DlpHIAEDecrypt(&nullKey, &usage, HIAE_IN_LEN, input, out));
1085+}
1086+ 
1087+/**
1088+ * @tc.name: DlpHIAEHandleNull001
1089+ * @tc.desc: cover AlgHIAE init/clear/update bodies with null handle
1090+ * @tc.type: FUNC
1091+ * @tc.require:
1092+ */
1093+HWTEST_F(DlpCryptTest, DlpHIAEHandleNull001, TestSize.Level0)
1094+{
1095+ DLP_LOG_INFO(LABEL, "DlpHIAEHandleNull001");
1096+ struct DlpBlob key = {32, g_key};
1097+ struct DlpCipherParam tagIv = {{16, g_iv}};
1098+ struct DlpUsageSpec usage = {DLP_MODE_HIAE, &tagIv};
1099+ 
1100+ uint8_t input[16] = "aaaaaaaaaaaaaaa";
1101+ uint8_t out[16] = {0};
1102+ 
1103+ // all params are valid: HIAEParamCheck passes, AlgHIAEInit/Update/Clear run with the
1104+ // null handle (HIAE sdk not loaded) and VALUE_INVALID is returned
1105+ ASSERT_EQ(DLP_PARSE_ERROR_VALUE_INVALID, DlpHIAEEncrypt(&key, &usage, HIAE_IN_LEN, input, out));
1106+ ASSERT_EQ(DLP_PARSE_ERROR_VALUE_INVALID, DlpHIAEDecrypt(&key, &usage, HIAE_IN_LEN, input, out));
1107+}
1108+ 
1109+/**
1110+ * @tc.name: DlpOpensslGenerateRandomBranch001
1111+ * @tc.desc: cover key nullptr and key size invalid branches of DlpOpensslGenerateRandom
1112+ * @tc.type: FUNC
1113+ * @tc.require:
1114+ */
1115+HWTEST_F(DlpCryptTest, DlpOpensslGenerateRandomBranch001, TestSize.Level0)
1116+{
1117+ DLP_LOG_INFO(LABEL, "DlpOpensslGenerateRandomBranch001");
1118+ struct DlpBlob key = {16, g_key};
1119+ 
1120+ // key == nullptr
1121+ ASSERT_EQ(DLP_PARSE_ERROR_VALUE_INVALID, DlpOpensslGenerateRandom(64, nullptr));
1122+ // keySize < BIT_NUM_OF_UINT8
1123+ ASSERT_EQ(DLP_PARSE_ERROR_VALUE_INVALID, DlpOpensslGenerateRandom(KEY_SIZE_TOO_SMALL, &key));
1124+ // keySize > DLP_RANDOM_MAX_SIZE
1125+ ASSERT_EQ(DLP_PARSE_ERROR_VALUE_INVALID, DlpOpensslGenerateRandom(KEY_SIZE_TOO_LARGE, &key));
1126+}
1127+ 
1128+/**
1129+ * @tc.name: GetOpensslAlgBranch001
1130+ * @tc.desc: cover SHA384/SHA512/unknown alg branches of GetOpensslAlg
1131+ * @tc.type: FUNC
1132+ * @tc.require:
1133+ */
1134+HWTEST_F(DlpCryptTest, GetOpensslAlgBranch001, TestSize.Level0)
1135+{
1136+ DLP_LOG_INFO(LABEL, "GetOpensslAlgBranch001");
1137+ // SHA384 and SHA512 branches return the matching digest
1138+ ASSERT_NE(nullptr, GetOpensslAlg(DIGEST_ALG_SHA384));
1139+ ASSERT_NE(nullptr, GetOpensslAlg(DIGEST_ALG_SHA512));
1140+ // unknown alg returns nullptr
1141+ ASSERT_EQ(nullptr, GetOpensslAlg(DIGEST_ALG_UNKNOWN));
1142+}
1143+ 
1144+/**
1145+ * @tc.name: DlpHmacEncodeForRawParam001
1146+ * @tc.desc: cover key and out invalid branches of DlpHmacEncodeForRaw and DlpHmacEncode
1147+ * @tc.type: FUNC
1148+ * @tc.require:
1149+ */
1150+HWTEST_F(DlpCryptTest, DlpHmacEncodeForRawParam001, TestSize.Level0)
1151+{
1152+ DLP_LOG_INFO(LABEL, "DlpHmacEncodeForRawParam001");
1153+ int fd = open("/data/fuse_test.txt", O_RDWR | O_CREAT | O_TRUNC, S_IRWXU);
1154+ ASSERT_NE(fd, -1);
1155+ uint8_t buffer[SIXTEEN] = {0};
1156+ write(fd, buffer, SIXTEEN);
1157+ lseek(fd, 0, SEEK_SET);
1158+ 
1159+ uint8_t* hmacKeyData = new (std::nothrow) uint8_t[HMAC_SIZE];
1160+ ASSERT_NE(hmacKeyData, nullptr);
1161+ struct DlpBlob key = {.size = HMAC_SIZE, .data = hmacKeyData};
1162+ uint8_t* outBuf = new (std::nothrow) uint8_t[HMAC_SIZE];
1163+ ASSERT_NE(outBuf, nullptr);
1164+ struct DlpBlob out = {.size = HMAC_SIZE, .data = outBuf};
1165+ 
1166+ // key.data == nullptr: DlpHmacEncodeForRaw
1167+ struct DlpBlob nullKey = {.size = HMAC_SIZE, .data = nullptr};
1168+ ASSERT_EQ(DLP_PARSE_ERROR_DIGEST_INVALID, DlpHmacEncodeForRaw(nullKey, fd, SIXTEEN, out));
1169+ // key.size != SHA256_KEY_LEN
1170+ struct DlpBlob shortKey = {.size = SIXTEEN, .data = hmacKeyData};
1171+ ASSERT_EQ(DLP_PARSE_ERROR_DIGEST_INVALID, DlpHmacEncodeForRaw(shortKey, fd, SIXTEEN, out));
1172+ // out.data == nullptr
1173+ struct DlpBlob nullOut = {.size = HMAC_SIZE, .data = nullptr};
1174+ ASSERT_EQ(DLP_PARSE_ERROR_DIGEST_INVALID, DlpHmacEncodeForRaw(key, fd, SIXTEEN, nullOut));
1175+ // out.size < HMAC_SIZE
1176+ struct DlpBlob smallOut = {.size = HMAC_OUT_SIZE_SMALL, .data = outBuf};
1177+ ASSERT_EQ(DLP_PARSE_ERROR_DIGEST_INVALID, DlpHmacEncodeForRaw(key, fd, SIXTEEN, smallOut));
1178+ 
1179+ // same param checks for DlpHmacEncode
1180+ lseek(fd, 0, SEEK_SET);
1181+ ASSERT_EQ(DLP_PARSE_ERROR_DIGEST_INVALID, DlpHmacEncode(nullKey, fd, out));
1182+ ASSERT_EQ(DLP_PARSE_ERROR_DIGEST_INVALID, DlpHmacEncode(shortKey, fd, out));
1183+ lseek(fd, 0, SEEK_SET);
1184+ ASSERT_EQ(DLP_PARSE_ERROR_DIGEST_INVALID, DlpHmacEncode(key, fd, nullOut));
1185+ ASSERT_EQ(DLP_PARSE_ERROR_DIGEST_INVALID, DlpHmacEncode(key, fd, smallOut));
1186+ 
1187+ delete[] hmacKeyData;
1188+ delete[] outBuf;
1189+ close(fd);
1190+ unlink("/data/fuse_test.txt");
1191+}
1192+ 
1193+/**
1194+ * @tc.name: DlpHmacEncodeForRawHmacFail001
1195+ * @tc.desc: cover HMAC_Init_ex and HMAC_Final fail branches of DlpHmacEncodeForRaw
1196+ * @tc.type: FUNC
1197+ * @tc.require:
1198+ */
1199+HWTEST_F(DlpCryptTest, DlpHmacEncodeForRawHmacFail001, TestSize.Level0)
1200+{
1201+ DLP_LOG_INFO(LABEL, "DlpHmacEncodeForRawHmacFail001");
1202+ int fd = open("/data/fuse_test.txt", O_RDWR | O_CREAT | O_TRUNC, S_IRWXU);
1203+ ASSERT_NE(fd, -1);
1204+ uint8_t buffer[SIXTEEN] = {0};
1205+ write(fd, buffer, SIXTEEN);
1206+ lseek(fd, 0, SEEK_SET);
1207+ 
1208+ uint8_t* hmacKeyData = new (std::nothrow) uint8_t[HMAC_SIZE];
1209+ ASSERT_NE(hmacKeyData, nullptr);
1210+ struct DlpBlob key = {.size = HMAC_SIZE, .data = hmacKeyData};
1211+ uint8_t* outBuf = new (std::nothrow) uint8_t[HMAC_SIZE];
1212+ ASSERT_NE(outBuf, nullptr);
1213+ struct DlpBlob out = {.size = HMAC_SIZE, .data = outBuf};
1214+ 
1215+ // HMAC_Init_ex fails (mocked)
1216+ DlpCMockCondition condition;
1217+ condition.mockSequence = { true };
1218+ SetMockConditions("HMAC_Init_ex", condition);
1219+ ASSERT_EQ(DLP_PARSE_ERROR_CRYPTO_ENGINE_ERROR, DlpHmacEncodeForRaw(key, fd, SIXTEEN, out));
1220+ CleanMockConditions();
1221+ 
1222+ // HMAC_Update fails (mocked): the read loop reports the engine error
1223+ lseek(fd, 0, SEEK_SET);
1224+ condition.mockSequence = { false, true };
1225+ SetMockConditions("HMAC_Init_ex", condition);
1226+ DlpCMockCondition updateCondition;
1227+ updateCondition.mockSequence = { true };
1228+ SetMockConditions("HMAC_Update", updateCondition);
1229+ ASSERT_EQ(DLP_PARSE_ERROR_CRYPTO_ENGINE_ERROR, DlpHmacEncodeForRaw(key, fd, SIXTEEN, out));
1230+ CleanMockConditions();
1231+ 
1232+ // HMAC_Final fails (mocked): fileSize 0 skips the loop and the final step fails
1233+ lseek(fd, 0, SEEK_SET);
1234+ condition.mockSequence = { false };
1235+ SetMockConditions("HMAC_Init_ex", condition);
1236+ DlpCMockCondition finalCondition;
1237+ finalCondition.mockSequence = { true };
1238+ SetMockConditions("HMAC_Final", finalCondition);
1239+ ASSERT_EQ(DLP_PARSE_ERROR_CRYPTO_ENGINE_ERROR, DlpHmacEncodeForRaw(key, fd, 0, out));
1240+ CleanMockConditions();
1241+ 
1242+ delete[] hmacKeyData;
1243+ delete[] outBuf;
1244+ close(fd);
1245+ unlink("/data/fuse_test.txt");
1246+}
1247+ 
1248+/**
1249+ * @tc.name: DlpHmacEncodeHmacFail001
1250+ * @tc.desc: cover HMAC_Init_ex and HMAC_Final fail branches of DlpHmacEncode
1251+ * @tc.type: FUNC
1252+ * @tc.require:
1253+ */
1254+HWTEST_F(DlpCryptTest, DlpHmacEncodeHmacFail001, TestSize.Level0)
1255+{
1256+ DLP_LOG_INFO(LABEL, "DlpHmacEncodeHmacFail001");
1257+ int fd = open("/data/fuse_test.txt", O_RDWR | O_CREAT | O_TRUNC, S_IRWXU);
1258+ ASSERT_NE(fd, -1);
1259+ uint8_t buffer[SIXTEEN] = {0};
1260+ write(fd, buffer, SIXTEEN);
1261+ lseek(fd, 0, SEEK_SET);
1262+ 
1263+ uint8_t* hmacKeyData = new (std::nothrow) uint8_t[HMAC_SIZE];
1264+ ASSERT_NE(hmacKeyData, nullptr);
1265+ struct DlpBlob key = {.size = HMAC_SIZE, .data = hmacKeyData};
1266+ uint8_t* outBuf = new (std::nothrow) uint8_t[HMAC_SIZE];
1267+ ASSERT_NE(outBuf, nullptr);
1268+ struct DlpBlob out = {.size = HMAC_SIZE, .data = outBuf};
1269+ 
1270+ // HMAC_Init_ex fails (mocked)
1271+ DlpCMockCondition condition;
1272+ condition.mockSequence = { true };
1273+ SetMockConditions("HMAC_Init_ex", condition);
1274+ ASSERT_EQ(DLP_PARSE_ERROR_CRYPTO_ENGINE_ERROR, DlpHmacEncode(key, fd, out));
1275+ CleanMockConditions();
1276+ 
1277+ // HMAC_Final fails (mocked): the read loop consumes the file and the final step fails
1278+ lseek(fd, 0, SEEK_SET);
1279+ condition.mockSequence = { false };
1280+ SetMockConditions("HMAC_Init_ex", condition);
1281+ DlpCMockCondition finalCondition;
1282+ finalCondition.mockSequence = { true };
1283+ SetMockConditions("HMAC_Final", finalCondition);
1284+ ASSERT_EQ(DLP_PARSE_ERROR_CRYPTO_ENGINE_ERROR, DlpHmacEncode(key, fd, out));
1285+ CleanMockConditions();
1286+ 
1287+ delete[] hmacKeyData;
1288+ delete[] outBuf;
1289+ close(fd);
1290+ unlink("/data/fuse_test.txt");
1291+}
@@ -1003,6 +1003,394 @@ HWTEST_F(DlpFileKitsTest, ConvertAbilityInfoWithSupportDlp012, TestSize.Level0)
1003 // No customFlag parameter set, should go through normal flow1003 // No customFlag parameter set, should go through normal flow
1004 std::vector<OHOS::AppExecFwk::AbilityInfo> abilityInfos;1004 std::vector<OHOS::AppExecFwk::AbilityInfo> abilityInfos;
1005 DlpFileKits::ConvertAbilityInfoWithSupportDlp(want, abilityInfos);1005 DlpFileKits::ConvertAbilityInfoWithSupportDlp(want, abilityInfos);
1006- 1006+ 
1007 EXPECT_EQ(abilityInfos.size(), 0);1007 EXPECT_EQ(abilityInfos.size(), 0);
1008+}
1009+ 
1010+namespace {
1011+// constants for the branch cases below (aligned with dlp_file_kits.cpp)
1012+static const std::string SHORT_NAME_URI = "file://data/test/a.b";
1013+static const std::string INVALID_CONTENT_DLP_URI = "file://data/test/invalid.txt.dlp";
1014+static const std::string INVALID_CONTENT_FILE = "/data/test/invalid.txt.dlp";
1015+static const std::string RAW_DLP_FILE = "/data/test/rawtest.docx.dlp";
1016+static const std::string RAW_DLP_URI = "file://data/test/rawtest.docx.dlp";
1017+static const std::string RAW_UNKNOWN_TYPE_DLP_FILE = "/data/test/rawunknown.xyz.dlp";
1018+static const std::string RAW_UNKNOWN_TYPE_DLP_URI = "file://data/test/rawunknown.xyz.dlp";
1019+static const uint32_t RAW_HMAC_HEX_SIZE = 64;
1020+static const uint32_t RAW_FILE_HEAD = 8;
1021+static constexpr int32_t INVALID_VERSION = 2;
1022+static constexpr int32_t ENTERPRISE_HEAD_SIZE = sizeof(struct DlpHeader) + RAW_FILE_HEAD;
1023+static constexpr int32_t FILE_TYPE_TXT = 1;
1024+static constexpr int32_t FILE_TYPE_UNKNOWN = 999;
1025+static constexpr int32_t FILE_TYPE_COUNTDOWN_OFFSET = 10000;
1026+static constexpr int32_t OPEN_COUNT_FLAG_ON = 1;
1027+static constexpr int32_t WATERMARK_FLAG_ON = 1;
1028+static constexpr int32_t TAIL_BUF_SIZE = 110;
1029+ 
1030+// write a minimal valid raw dlp header (contactAccountSize 1, certOffset == txtOffset)
1031+static void WriteRawDlpHeader(int32_t fd, uint32_t fileType)
1032+{
1033+ struct DlpHeader header = {
1034+ .magic = DLP_FILE_MAGIC,
1035+ .fileType = fileType,
1036+ .offlineAccess = 0,
1037+ .algType = DLP_MODE_CTR,
1038+ .txtOffset = sizeof(struct DlpHeader) + RAW_FILE_HEAD + 1,
1039+ .txtSize = 0,
1040+ .hmacOffset = sizeof(struct DlpHeader) + RAW_FILE_HEAD + 1,
1041+ .hmacSize = RAW_HMAC_HEX_SIZE,
1042+ .certOffset = sizeof(struct DlpHeader) + RAW_FILE_HEAD + 1,
1043+ .certSize = 16,
1044+ .contactAccountOffset = sizeof(struct DlpHeader) + RAW_FILE_HEAD,
1045+ .contactAccountSize = 1,
1046+ .offlineCertOffset = 0,
1047+ .offlineCertSize = 0
1048+ };
1049+ uint32_t version = CURRENT_VERSION;
1050+ uint32_t dlpHeaderSize = sizeof(struct DlpHeader);
1051+ write(fd, &version, sizeof(uint32_t));
1052+ write(fd, &dlpHeaderSize, sizeof(uint32_t));
1053+ write(fd, &header, sizeof(struct DlpHeader));
1054+ // trailing bytes so the header checks pass: contact account + hmac + cert + file id tail
1055+ uint8_t body[16] = {0};
1056+ write(fd, body, sizeof(body));
1057+ write(fd, body, RAW_HMAC_HEX_SIZE);
1058+ write(fd, body, 16);
1059+ uint8_t tail[TAIL_BUF_SIZE] = {0};
1060+ write(fd, tail, sizeof(tail));
1061+}
1062+ 
1063+// generate a real raw dlp file through the manager so IsDlpFile recognizes it
1064+static int32_t CreateRawDlpFile(const std::string& path)
1065+{
1066+ int32_t plainFd = open(PLAIN_FILE_NAME.c_str(), O_CREAT | O_RDWR | O_TRUNC, DLP_FILE_PERMISSION);
1067+ if (plainFd < 0) {
1068+ return -1;
1069+ }
1070+ char buffer[] = "123456";
1071+ write(plainFd, buffer, sizeof(buffer));
1072+ int32_t dlpFd = open(path.c_str(), O_CREAT | O_RDWR | O_TRUNC, DLP_FILE_PERMISSION);
1073+ if (dlpFd < 0) {
1074+ close(plainFd);
1075+ return -1;
1076+ }
1077+ DlpProperty prop;
1078+ prop.ownerAccount = "ohosAnonymousName";
1079+ prop.ownerAccountId = "ohosAnonymousName";
1080+ prop.ownerAccountType = CLOUD_ACCOUNT;
1081+ prop.contactAccount = "test@test.com";
1082+ std::shared_ptr<DlpFile> filePtr;
1083+ int ret = DlpFileManager::GetInstance().GenerateDlpFile(plainFd, dlpFd, prop, filePtr, DLP_TEST_DIR);
1084+ close(plainFd);
1085+ if (ret != DLP_OK) {
1086+ close(dlpFd);
1087+ return -1;
1088+ }
1089+ DlpFileManager::GetInstance().CloseDlpFile(filePtr);
1090+ return dlpFd;
1091+}
1092+}
1093+ 
1094+/**
1095+ * @tc.name: GetSandboxFlagShortName001
1096+ * @tc.desc: cover fileNameLen < dlpSuffixLen branch of IsDlpFileName
1097+ * @tc.type: FUNC
1098+ */
1099+HWTEST_F(DlpFileKitsTest, GetSandboxFlagShortName001, TestSize.Level0)
1100+{
1101+ DLP_LOG_INFO(LABEL, "GetSandboxFlagShortName001");
1102+ OHOS::AAFwk::Want want;
1103+ want.SetAction(TAG_ACTION_VIEW);
1104+ // the file name part is shorter than ".dlp": IsDlpFileName returns false
1105+ want.SetUri(SHORT_NAME_URI);
1106+ ASSERT_FALSE(DlpFileKits::GetSandboxFlag(want));
1107+}
1108+ 
1109+/**
1110+ * @tc.name: IsDlpFileInvalidHeader001
1111+ * @tc.desc: cover IsValidDlpHeader fail branch of IsDlpFile
1112+ * @tc.type: FUNC
1113+ */
1114+HWTEST_F(DlpFileKitsTest, IsDlpFileInvalidHeader001, TestSize.Level0)
1115+{
1116+ DLP_LOG_INFO(LABEL, "IsDlpFileInvalidHeader001");
1117+ int32_t fd = open(INVALID_CONTENT_FILE.c_str(), O_CREAT | O_RDWR | O_TRUNC, DLP_FILE_PERMISSION);
1118+ ASSERT_GE(fd, 0);
1119+ 
1120+ // valid version and header size, but the header fields are inconsistent
1121+ uint32_t version = CURRENT_VERSION;
1122+ uint32_t dlpHeaderSize = sizeof(struct DlpHeader);
1123+ write(fd, &version, sizeof(uint32_t));
1124+ write(fd, &dlpHeaderSize, sizeof(uint32_t));
1125+ struct DlpHeader header = {};
1126+ header.magic = DLP_FILE_MAGIC;
1127+ header.certSize = 16;
1128+ header.contactAccountSize = 1;
1129+ // all offsets are wrong so IsValidDlpHeader fails
1130+ header.contactAccountOffset = 1;
1131+ header.txtOffset = 2;
1132+ header.hmacOffset = 3;
1133+ header.certOffset = 4;
1134+ header.hmacSize = RAW_HMAC_HEX_SIZE;
1135+ write(fd, &header, sizeof(struct DlpHeader));
1136+ uint8_t body[32] = {0};
1137+ write(fd, body, sizeof(body));
1138+ lseek(fd, 0, SEEK_SET);
1139+ 
1140+ // IsValidDlpHeader returns false: IsDlpFile reports not a dlp file
1141+ ASSERT_FALSE(DlpFileKits::IsDlpFile(fd));
1142+ close(fd);
1143+ unlink(INVALID_CONTENT_FILE.c_str());
1144+}
1145+ 
1146+/**
1147+ * @tc.name: IsDlpFileInvalidVersion001
1148+ * @tc.desc: cover version or dlpHeaderSize invalid branch of IsDlpFile
1149+ * @tc.type: FUNC
1150+ */
1151+HWTEST_F(DlpFileKitsTest, IsDlpFileInvalidVersion001, TestSize.Level0)
1152+{
1153+ DLP_LOG_INFO(LABEL, "IsDlpFileInvalidVersion001");
1154+ int32_t fd = open(INVALID_CONTENT_FILE.c_str(), O_CREAT | O_RDWR | O_TRUNC, DLP_FILE_PERMISSION);
1155+ ASSERT_GE(fd, 0);
1156+ 
1157+ // version is not CURRENT_VERSION: the read loop breaks with checkFlag false
1158+ uint32_t version = INVALID_VERSION;
1159+ uint32_t dlpHeaderSize = sizeof(struct DlpHeader);
1160+ write(fd, &version, sizeof(uint32_t));
1161+ write(fd, &dlpHeaderSize, sizeof(uint32_t));
1162+ uint8_t body[32] = {0};
1163+ write(fd, body, sizeof(body));
1164+ lseek(fd, 0, SEEK_SET);
1165+ ASSERT_FALSE(DlpFileKits::IsDlpFile(fd));
1166+ 
1167+ // dlpHeaderSize is larger than sizeof(DlpHeader) but exceeds ENTERPRISE_HEAD_MAX
1168+ lseek(fd, 0, SEEK_SET);
1169+ ftruncate(fd, 0);
1170+ lseek(fd, 0, SEEK_SET);
1171+ version = CURRENT_VERSION;
1172+ dlpHeaderSize = ENTERPRISE_HEAD_MAX + 1;
1173+ write(fd, &version, sizeof(uint32_t));
1174+ write(fd, &dlpHeaderSize, sizeof(uint32_t));
1175+ write(fd, body, sizeof(body));
1176+ lseek(fd, 0, SEEK_SET);
1177+ ASSERT_FALSE(DlpFileKits::IsDlpFile(fd));
1178+ 
1179+ close(fd);
1180+ unlink(INVALID_CONTENT_FILE.c_str());
1181+}
1182+ 
1183+/**
1184+ * @tc.name: IsDlpFileEnterpriseInvalidHeader001
1185+ * @tc.desc: cover IsValidEnterpriseDlpHeader fail branch of IsDlpFile
1186+ * @tc.type: FUNC
1187+ */
1188+HWTEST_F(DlpFileKitsTest, IsDlpFileEnterpriseInvalidHeader001, TestSize.Level0)
1189+{
1190+ DLP_LOG_INFO(LABEL, "IsDlpFileEnterpriseInvalidHeader001");
1191+ int32_t fd = open(INVALID_CONTENT_FILE.c_str(), O_CREAT | O_RDWR | O_TRUNC, DLP_FILE_PERMISSION);
1192+ ASSERT_GE(fd, 0);
1193+ 
1194+ // enterprise header size with inconsistent fields: IsValidEnterpriseDlpHeader fails
1195+ uint32_t version = CURRENT_VERSION;
1196+ uint32_t dlpHeaderSize = sizeof(struct DlpHeader) + RAW_FILE_HEAD;
1197+ write(fd, &version, sizeof(uint32_t));
1198+ write(fd, &dlpHeaderSize, sizeof(uint32_t));
1199+ struct DlpHeader header = {};
1200+ header.magic = DLP_FILE_MAGIC;
1201+ header.certSize = 16;
1202+ header.contactAccountSize = 0;
1203+ // the offsets do not match the enterprise layout rules
1204+ header.contactAccountOffset = 1;
1205+ header.txtOffset = 2;
1206+ header.hmacOffset = 3;
1207+ header.certOffset = 4;
1208+ header.hmacSize = RAW_HMAC_HEX_SIZE;
1209+ write(fd, &header, sizeof(struct DlpHeader));
1210+ uint8_t body[32] = {0};
1211+ write(fd, body, sizeof(body));
1212+ lseek(fd, 0, SEEK_SET);
1213+ ASSERT_FALSE(DlpFileKits::IsDlpFile(fd));
1214+ 
1215+ close(fd);
1216+ unlink(INVALID_CONTENT_FILE.c_str());
1217+}
1218+ 
1219+/**
1220+ * @tc.name: GetSandboxFlagNotDlpContent001
1221+ * @tc.desc: cover IsDlpFile false and QueryDockerPolicyNeedSandbox branch of GetSandboxFlag
1222+ * @tc.type: FUNC
1223+ */
1224+HWTEST_F(DlpFileKitsTest, GetSandboxFlagNotDlpContent001, TestSize.Level0)
1225+{
1226+ DLP_LOG_INFO(LABEL, "GetSandboxFlagNotDlpContent001");
1227+ // a file with the .dlp suffix but plain content: IsDlpFile fails, docker policy returns false
1228+ int32_t fd = open(INVALID_CONTENT_FILE.c_str(), O_CREAT | O_RDWR | O_TRUNC, DLP_FILE_PERMISSION);
1229+ ASSERT_GE(fd, 0);
1230+ char buffer[] = "123456";
1231+ write(fd, buffer, sizeof(buffer));
1232+ close(fd);
1233+ 
1234+ OHOS::AAFwk::Want want;
1235+ want.SetAction(TAG_ACTION_VIEW);
1236+ want.SetUri(INVALID_CONTENT_DLP_URI);
1237+ // IsDlpFile is false: the fd is closed and false is returned after the docker policy query
1238+ ASSERT_FALSE(DlpFileKits::GetSandboxFlag(want));
1239+ unlink(INVALID_CONTENT_FILE.c_str());
1240+}
1241+ 
1242+/**
1243+ * @tc.name: GetSandboxFlagRemoveNotOriginalDlp001
1244+ * @tc.desc: cover RemoveNotOriginalDlpFlag branch of GetSandboxFlag
1245+ * @tc.type: FUNC
1246+ */
1247+HWTEST_F(DlpFileKitsTest, GetSandboxFlagRemoveNotOriginalDlp001, TestSize.Level0)
1248+{
1249+ DLP_LOG_INFO(LABEL, "GetSandboxFlagRemoveNotOriginalDlp001");
1250+ OHOS::AAFwk::Want want;
1251+ want.SetAction(TAG_ACTION_VIEW);
1252+ want.SetUri(DLP_FILE_URI);
1253+ // the notOriginalDlp parameter is removed when the name is a dlp file
1254+ want.SetParam("ohos.dlp.params.notOriginalDlp", true);
1255+ ASSERT_TRUE(DlpFileKits::GetSandboxFlag(want));
1256+ // the parameter has been removed by RemoveNotOriginalDlpFlag
1257+ ASSERT_FALSE(want.HasParameter("ohos.dlp.params.notOriginalDlp"));
1258+}
1259+ 
1260+/**
1261+ * @tc.name: GetSandboxFlagRawFile001
1262+ * @tc.desc: cover raw-file branches of SetWantType and GetIsReadOnceOrWaterMark
1263+ * @tc.type: FUNC
1264+ */
1265+HWTEST_F(DlpFileKitsTest, GetSandboxFlagRawFile001, TestSize.Level0)
1266+{
1267+ DLP_LOG_INFO(LABEL, "GetSandboxFlagRawFile001");
1268+ // generate a real raw (non-zip) dlp file: docx takes the raw generation path
1269+ int32_t rawFd = CreateRawDlpFile(RAW_DLP_FILE);
1270+ ASSERT_GE(rawFd, 0);
1271+ OHOS::AppFileService::ModuleFileUri::SetMockGetRealPath(RAW_DLP_FILE);
1272+ OHOS::AppFileService::ModuleFileUri::SetMockGetRealPathCount(1);
1273+ 
1274+ OHOS::AAFwk::Want want;
1275+ want.SetAction(TAG_ACTION_VIEW);
1276+ want.SetUri(RAW_DLP_URI);
1277+ // IsDlpFile passes on the raw file and SetWantType runs through the raw branch
1278+ ASSERT_TRUE(DlpFileKits::GetSandboxFlag(want));
1279+ // docx maps to a known mimetype
1280+ EXPECT_EQ(want.GetType(), "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
1281+ close(rawFd);
1282+ unlink(RAW_DLP_FILE.c_str());
1283+}
1284+ 
1285+/**
1286+ * @tc.name: GetSandboxFlagRawUnknownType001
1287+ * @tc.desc: cover unknown real suffix branch of SetWantType
1288+ * @tc.type: FUNC
1289+ */
1290+HWTEST_F(DlpFileKitsTest, GetSandboxFlagRawUnknownType001, TestSize.Level0)
1291+{
1292+ DLP_LOG_INFO(LABEL, "GetSandboxFlagRawUnknownType001");
1293+ // build a raw dlp file whose fileType maps to no known suffix: the origin type stays
1294+ int32_t fd = open(RAW_UNKNOWN_TYPE_DLP_FILE.c_str(), O_CREAT | O_RDWR | O_TRUNC, DLP_FILE_PERMISSION);
1295+ ASSERT_GE(fd, 0);
1296+ WriteRawDlpHeader(fd, FILE_TYPE_UNKNOWN);
1297+ lseek(fd, 0, SEEK_SET);
1298+ ASSERT_TRUE(DlpFileKits::IsDlpFile(fd));
1299+ close(fd);
1300+ 
1301+ OHOS::AppFileService::ModuleFileUri::SetMockGetRealPath(RAW_UNKNOWN_TYPE_DLP_FILE);
1302+ OHOS::AppFileService::ModuleFileUri::SetMockGetRealPathCount(1);
1303+ OHOS::AAFwk::Want want;
1304+ want.SetAction(TAG_ACTION_VIEW);
1305+ want.SetUri(RAW_UNKNOWN_TYPE_DLP_URI);
1306+ // the real suffix is unknown: the mimetype falls back to image/jpeg
1307+ ASSERT_TRUE(DlpFileKits::GetSandboxFlag(want));
1308+ EXPECT_EQ(want.GetType(), "image/jpeg");
1309+ unlink(RAW_UNKNOWN_TYPE_DLP_FILE.c_str());
1310+}
1311+ 
1312+/**
1313+ * @tc.name: GetSandboxFlagRawReadOnce001
1314+ * @tc.desc: cover readOnce/waterMark branch of GetIsReadOnceOrWaterMark for raw files
1315+ * @tc.type: FUNC
1316+ */
1317+HWTEST_F(DlpFileKitsTest, GetSandboxFlagRawReadOnce001, TestSize.Level0)
1318+{
1319+ DLP_LOG_INFO(LABEL, "GetSandboxFlagRawReadOnce001");
1320+ // build a raw dlp file with a file id tail whose first byte is non-zero:
1321+ // GetRawFileAllowedOpenCount reports allowedOpenCount 1 for non-owner readers
1322+ int32_t fd = open(RAW_UNKNOWN_TYPE_DLP_FILE.c_str(), O_CREAT | O_RDWR | O_TRUNC, DLP_FILE_PERMISSION);
1323+ ASSERT_GE(fd, 0);
1324+ WriteRawDlpHeader(fd, FILE_TYPE_TXT);
1325+ // rewrite the tail: watermark flag off, open-count flag off, non-zero first fileId byte
1326+ ftruncate(fd, 0);
1327+ lseek(fd, 0, SEEK_SET);
1328+ uint32_t version = CURRENT_VERSION;
1329+ uint32_t dlpHeaderSize = sizeof(struct DlpHeader);
1330+ struct DlpHeader header = {
1331+ .magic = DLP_FILE_MAGIC,
1332+ .fileType = FILE_TYPE_TXT,
1333+ .txtOffset = sizeof(struct DlpHeader) + RAW_FILE_HEAD + 1,
1334+ .txtSize = 0,
1335+ .hmacOffset = sizeof(struct DlpHeader) + RAW_FILE_HEAD + 1,
1336+ .hmacSize = RAW_HMAC_HEX_SIZE,
1337+ .certOffset = sizeof(struct DlpHeader) + RAW_FILE_HEAD + 1,
1338+ .certSize = 16,
1339+ .contactAccountOffset = sizeof(struct DlpHeader) + RAW_FILE_HEAD,
1340+ .contactAccountSize = 1,
1341+ };
1342+ write(fd, &version, sizeof(uint32_t));
1343+ write(fd, &dlpHeaderSize, sizeof(uint32_t));
1344+ write(fd, &header, sizeof(struct DlpHeader));
1345+ uint8_t body[16] = {0};
1346+ write(fd, body, sizeof(body));
1347+ write(fd, body, RAW_HMAC_HEX_SIZE);
1348+ write(fd, body, 16);
1349+ // tail layout: watermark(4) + flag(4) + allowedOpenCount(4) + fileId(46)
1350+ int32_t watermark = 0;
1351+ int32_t flag = 0;
1352+ int32_t allowedOpenCount = 0;
1353+ uint8_t fileId[46] = {0};
1354+ fileId[0] = 1; // non-zero first byte with flag 0: allowedOpenCount becomes 1
1355+ write(fd, &watermark, sizeof(int32_t));
1356+ write(fd, &flag, sizeof(int32_t));
1357+ write(fd, &allowedOpenCount, sizeof(int32_t));
1358+ write(fd, fileId, sizeof(fileId));
1359+ lseek(fd, 0, SEEK_SET);
1360+ ASSERT_TRUE(DlpFileKits::IsDlpFile(fd));
1361+ close(fd);
1362+ 
1363+ OHOS::AppFileService::ModuleFileUri::SetMockGetRealPath(RAW_UNKNOWN_TYPE_DLP_FILE);
1364+ OHOS::AppFileService::ModuleFileUri::SetMockGetRealPathCount(1);
1365+ OHOS::AAFwk::Want want;
1366+ want.SetAction(TAG_ACTION_VIEW);
1367+ want.SetUri(RAW_UNKNOWN_TYPE_DLP_URI);
1368+ // allowedOpenCount becomes 1 through the non-zero fileId: the type is forced to image/jpeg
1369+ ASSERT_TRUE(DlpFileKits::GetSandboxFlag(want));
1370+ EXPECT_EQ(want.GetType(), "image/jpeg");
1371+ unlink(RAW_UNKNOWN_TYPE_DLP_FILE.c_str());
1372+}
1373+ 
1374+/**
1375+ * @tc.name: ConvertAbilityInfoUnknownMime001
1376+ * @tc.desc: cover fileType empty branch of GetRealFileType
1377+ * @tc.type: FUNC
1378+ */
1379+HWTEST_F(DlpFileKitsTest, ConvertAbilityInfoUnknownMime001, TestSize.Level0)
1380+{
1381+ DLP_LOG_INFO(LABEL, "ConvertAbilityInfoUnknownMime001");
1382+ OHOS::AAFwk::Want want;
1383+ want.SetUri(DLP_FILE_URI);
1384+ // an unknown mimetype maps to no suffix: GetFileTypeBySuffix returns empty
1385+ want.SetType("application/x-unknown-type");
1386+ 
1387+ std::vector<OHOS::AppExecFwk::AbilityInfo> abilityInfos;
1388+ OHOS::AppExecFwk::AbilityInfo abilityInfo;
1389+ abilityInfo.bundleName = "bundle.keep";
1390+ abilityInfos.push_back(abilityInfo);
1391+ 
1392+ // fileType is empty: the function returns early and the abilities are not filtered
1393+ DlpFileKits::ConvertAbilityInfoWithSupportDlp(want, abilityInfos);
1394+ EXPECT_EQ(abilityInfos.size(), 1);
1395+ EXPECT_EQ(want.GetType(), "application/x-unknown-type");
1008}1396}
@@ -18,6 +18,9 @@
18#include <cstdio>18#include <cstdio>
19#include <cstring>19#include <cstring>
20#include <fcntl.h>20#include <fcntl.h>
21+#include <unistd.h>
22+#include <sys/types.h>
23+#include <sys/stat.h>
21#include <nlohmann/json.hpp>24#include <nlohmann/json.hpp>
22#include "iremote_stub.h"25#include "iremote_stub.h"
23#include "c_mock_common.h"26#include "c_mock_common.h"
@@ -1292,6 +1295,547 @@ HWTEST_F(DlpFileManagerTest, GenRawDlpFile_PrepareDirsFail, TestSize.Level0)
1292 close(plainFileFd);1295 close(plainFileFd);
1293}1296}
1294 1297 
1298+namespace {
1299+// constants for the branch cases below
1300+static constexpr int32_t OPEN_COUNT_AT_LEAST_ONE = 1;
1301+static constexpr int32_t OPEN_COUNT_ZERO = 0;
1302+static constexpr uint32_t EXPIRE_TIME_NON_ZERO = 1;
1303+static constexpr int32_t INVALID_ACTION_UPON_EXPIRY = 2;
1304+static constexpr int32_t TRUNCATED_FILE_SIZE = 4;
1305+ 
1306+// build a valid dlp property for encrypting a cloud-account file
1307+static DlpProperty BuildCloudProperty()
1308+{
1309+ DlpProperty property;
1310+ property.ownerAccount = "owner";
1311+ property.ownerAccountId = "owner";
1312+ property.contactAccount = "owner";
1313+ property.ownerAccountType = CLOUD_ACCOUNT;
1314+ return property;
1315+}
1316+ 
1317+// generate a real raw dlp file (document type takes the raw path) and leave both fds open
1318+static bool GenCloudRawDlpFile(int32_t& plainFd, int32_t& dlpFd)
1319+{
1320+ plainFd = open("/data/file_test.txt", O_CREAT | O_RDWR | O_TRUNC, S_IRWXU | S_IRWXG | S_IRWXO);
1321+ if (plainFd < 0) {
1322+ return false;
1323+ }
1324+ dlpFd = open("/data/file_test.docx.dlp", O_CREAT | O_RDWR | O_TRUNC, S_IRWXU | S_IRWXG | S_IRWXO);
1325+ if (dlpFd < 0) {
1326+ close(plainFd);
1327+ return false;
1328+ }
1329+ char buffer[] = "123456";
1330+ if (write(plainFd, buffer, sizeof(buffer)) == -1) {
1331+ close(plainFd);
1332+ close(dlpFd);
1333+ return false;
1334+ }
1335+ DlpProperty property = BuildCloudProperty();
1336+ std::shared_ptr<DlpFile> filePtr;
1337+ if (DlpFileManager::GetInstance().GenerateDlpFile(plainFd, dlpFd, property, filePtr,
1338+ DLP_TEST_DIR) != DLP_OK) {
1339+ close(plainFd);
1340+ close(dlpFd);
1341+ return false;
1342+ }
1343+ lseek(plainFd, 0, SEEK_SET);
1344+ lseek(dlpFd, 0, SEEK_SET);
1345+ return true;
1346+}
1347+}
1348+ 
1349+/**
1350+ * @tc.name: PrepareDlpEncryptParmsHmacFail001
1351+ * @tc.desc: cover hmac key generate fail branch of PrepareDlpEncryptParms
1352+ * @tc.type: FUNC
1353+ * @tc.require:
1354+ */
1355+HWTEST_F(DlpFileManagerTest, PrepareDlpEncryptParmsHmacFail001, TestSize.Level0)
1356+{
1357+ DLP_LOG_INFO(LABEL, "PrepareDlpEncryptParmsHmacFail001");
1358+ 
1359+ PermissionPolicy policy;
1360+ policy.ownerAccountType_ = CLOUD_ACCOUNT;
1361+ policy.ownerAccount_ = "owner";
1362+ policy.ownerAccountId_ = "owner";
1363+ struct DlpBlob key;
1364+ struct DlpUsageSpec usage;
1365+ struct DlpBlob certData;
1366+ struct DlpBlob hmacKey;
1367+ 
1368+ // the 3rd RAND_bytes call (hmac key) fails: CleanTempBlob and the error are returned
1369+ DlpCMockCondition condition;
1370+ condition.mockSequence = { false, false, true };
1371+ SetMockConditions("RAND_bytes", condition);
1372+ EXPECT_EQ(DLP_PARSE_ERROR_CRYPTO_ENGINE_ERROR,
1373+ DlpFileManager::GetInstance().PrepareDlpEncryptParms(policy, key, usage, certData, hmacKey));
1374+ CleanMockConditions();
1375+}
1376+ 
1377+/**
1378+ * @tc.name: UpdateDlpFileBranch001
1379+ * @tc.desc: cover allowedOpenCount >= 1 and CheckDlpFile fail branches of UpdateDlpFile
1380+ * @tc.type: FUNC
1381+ * @tc.require:
1382+ */
1383+HWTEST_F(DlpFileManagerTest, UpdateDlpFileBranch001, TestSize.Level0)
1384+{
1385+ DLP_LOG_INFO(LABEL, "UpdateDlpFileBranch001");
1386+ std::vector<uint8_t> cert;
1387+ 
1388+ // allowedOpenCount >= 1: return DLP_OK directly without touching the file
1389+ std::shared_ptr<DlpFile> filePtr = std::make_shared<DlpZipFile>(1000, DLP_TEST_DIR, 0, "txt");
1390+ ASSERT_NE(filePtr, nullptr);
1391+ EXPECT_EQ(DLP_OK, DlpFileManager::GetInstance().UpdateDlpFile(cert, filePtr, OPEN_COUNT_AT_LEAST_ONE));
1392+ 
1393+ // CheckDlpFile fails on the invalid fd: the error is propagated
1394+ EXPECT_NE(DLP_OK, DlpFileManager::GetInstance().UpdateDlpFile(cert, filePtr, OPEN_COUNT_ZERO));
1395+}
1396+ 
1397+/**
1398+ * @tc.name: SetDlpFileParamsInvalidAction001
1399+ * @tc.desc: cover CheckActionUponExpiry fail branch of SetDlpParams
1400+ * @tc.type: FUNC
1401+ * @tc.require:
1402+ */
1403+HWTEST_F(DlpFileManagerTest, SetDlpFileParamsInvalidAction001, TestSize.Level0)
1404+{
1405+ DLP_LOG_INFO(LABEL, "SetDlpFileParamsInvalidAction001");
1406+ std::shared_ptr<DlpFile> filePtr = std::make_shared<DlpZipFile>(1000, DLP_TEST_DIR, 0, "txt");
1407+ ASSERT_NE(filePtr, nullptr);
1408+ 
1409+ // expireTime != 0 and actionUponExpiry > OPEN: CheckActionUponExpiry fails
1410+ DlpProperty property = BuildCloudProperty();
1411+ property.expireTime = EXPIRE_TIME_NON_ZERO;
1412+ property.actionUponExpiry = static_cast<ActionType>(INVALID_ACTION_UPON_EXPIRY);
1413+ EXPECT_EQ(DLP_PARSE_ERROR_VALUE_INVALID,
1414+ DlpFileManager::GetInstance().SetDlpFileParams(filePtr, property));
1415+}
1416+ 
1417+/**
1418+ * @tc.name: GenZipDlpFileBranch001
1419+ * @tc.desc: cover random dir fail, SetDlpFileParams fail and GenFile fail branches of GenZipDlpFile
1420+ * @tc.type: FUNC
1421+ * @tc.require:
1422+ */
1423+HWTEST_F(DlpFileManagerTest, GenZipDlpFileBranch001, TestSize.Level0)
1424+{
1425+ DLP_LOG_INFO(LABEL, "GenZipDlpFileBranch001");
1426+ int32_t plainFd = open("/data/file_test.txt", O_CREAT | O_RDWR | O_TRUNC, S_IRWXU | S_IRWXG | S_IRWXO);
1427+ ASSERT_NE(plainFd, -1);
1428+ char buffer[] = "123456";
1429+ ASSERT_NE(write(plainFd, buffer, sizeof(buffer)), -1);
1430+ DlpFileManager::DlpFileMes mes = {plainFd, 1000, "txt"};
1431+ DlpProperty property = BuildCloudProperty();
1432+ std::shared_ptr<DlpFile> filePtr;
1433+ 
1434+ // GenerateRandomWorkDir fails (RAND_bytes mocked)
1435+ DlpCMockCondition condition;
1436+ condition.mockSequence = { true };
1437+ SetMockConditions("RAND_bytes", condition);
1438+ EXPECT_EQ(DLP_PARSE_ERROR_CRYPTO_ENGINE_ERROR,
1439+ DlpFileManager::GetInstance().GenZipDlpFile(mes, property, filePtr, DLP_TEST_DIR));
1440+ CleanMockConditions();
1441+ 
1442+ // SetDlpFileParams fails: empty ownerAccount makes SetPolicy fail
1443+ DlpProperty badProperty;
1444+ badProperty.ownerAccount = "";
1445+ badProperty.ownerAccountId = "owner";
1446+ badProperty.contactAccount = "owner";
1447+ badProperty.ownerAccountType = CLOUD_ACCOUNT;
1448+ EXPECT_EQ(DLP_PARSE_ERROR_VALUE_INVALID,
1449+ DlpFileManager::GetInstance().GenZipDlpFile(mes, badProperty, filePtr, DLP_TEST_DIR));
1450+ 
1451+ // GenFile fails: lseek on the plain fd fails (lseek mocked)
1452+ lseek(plainFd, 0, SEEK_SET);
1453+ condition.mockSequence = { true };
1454+ SetMockConditions("lseek", condition);
1455+ EXPECT_EQ(DLP_PARSE_ERROR_FILE_OPERATE_FAIL,
1456+ DlpFileManager::GetInstance().GenZipDlpFile(mes, property, filePtr, DLP_TEST_DIR));
1457+ CleanMockConditions();
1458+ 
1459+ close(plainFd);
1460+}
1461+ 
1462+/**
1463+ * @tc.name: GenRawDlpFileGenFileFail001
1464+ * @tc.desc: cover GenFile fail branch of GenRawDlpFile
1465+ * @tc.type: FUNC
1466+ * @tc.require:
1467+ */
1468+HWTEST_F(DlpFileManagerTest, GenRawDlpFileGenFileFail001, TestSize.Level0)
1469+{
1470+ DLP_LOG_INFO(LABEL, "GenRawDlpFileGenFileFail001");
1471+ int32_t plainFd = open("/data/file_test.txt", O_CREAT | O_RDWR | O_TRUNC, S_IRWXU | S_IRWXG | S_IRWXO);
1472+ ASSERT_NE(plainFd, -1);
1473+ char buffer[] = "123456";
1474+ ASSERT_NE(write(plainFd, buffer, sizeof(buffer)), -1);
1475+ DlpFileManager::DlpFileMes mes = {plainFd, 1000, "mp4"};
1476+ DlpProperty property = BuildCloudProperty();
1477+ std::shared_ptr<DlpFile> filePtr;
1478+ 
1479+ // SetDlpFileParams succeeds but GenFile fails (lseek mocked)
1480+ DlpCMockCondition condition;
1481+ condition.mockSequence = { true };
1482+ SetMockConditions("lseek", condition);
1483+ EXPECT_EQ(DLP_PARSE_ERROR_FILE_OPERATE_FAIL,
1484+ DlpFileManager::GetInstance().GenRawDlpFile(mes, property, filePtr));
1485+ CleanMockConditions();
1486+ 
1487+ close(plainFd);
1488+}
1489+ 
1490+/**
1491+ * @tc.name: GenerateDlpFileAlreadyOpened001
1492+ * @tc.desc: cover already opened branch of GenerateDlpFile
1493+ * @tc.type: FUNC
1494+ * @tc.require:
1495+ */
1496+HWTEST_F(DlpFileManagerTest, GenerateDlpFileAlreadyOpened001, TestSize.Level0)
1497+{
1498+ DLP_LOG_INFO(LABEL, "GenerateDlpFileAlreadyOpened001");
1499+ int32_t plainFd = -1;
1500+ int32_t dlpFd = -1;
1501+ ASSERT_TRUE(GenCloudRawDlpFile(plainFd, dlpFd));
1502+ DlpProperty property = BuildCloudProperty();
1503+ 
1504+ // register the dlp fd in the open-file map: GenerateDlpFile reports already opened
1505+ std::shared_ptr<DlpFile> openedPtr = std::make_shared<DlpZipFile>(dlpFd, DLP_TEST_DIR, 0, "txt");
1506+ ASSERT_EQ(DLP_OK, DlpFileManager::GetInstance().AddDlpFileNode(openedPtr));
1507+ std::shared_ptr<DlpFile> filePtr;
1508+ EXPECT_EQ(DLP_PARSE_ERROR_FILE_ALREADY_OPENED,
1509+ DlpFileManager::GetInstance().GenerateDlpFile(plainFd, dlpFd, property, filePtr, DLP_TEST_DIR));
1510+ DlpFileManager::GetInstance().RemoveDlpFileNode(openedPtr);
1511+ 
1512+ close(plainFd);
1513+ close(dlpFd);
1514+ unlink("/data/file_test.txt");
1515+ unlink("/data/file_test.docx.dlp");
1516+}
1517+ 
1518+/**
1519+ * @tc.name: GenerateDlpFileUnknownSuffix001
1520+ * @tc.desc: cover GetFileTypeBySuffix fail branch of GenerateDlpFile
1521+ * @tc.type: FUNC
1522+ * @tc.require:
1523+ */
1524+HWTEST_F(DlpFileManagerTest, GenerateDlpFileUnknownSuffix001, TestSize.Level0)
1525+{
1526+ DLP_LOG_INFO(LABEL, "GenerateDlpFileUnknownSuffix001");
1527+ int32_t plainFd = open("/data/file_test.txt", O_CREAT | O_RDWR | O_TRUNC, S_IRWXU | S_IRWXG | S_IRWXO);
1528+ ASSERT_NE(plainFd, -1);
1529+ char buffer[] = "123456";
1530+ ASSERT_NE(write(plainFd, buffer, sizeof(buffer)), -1);
1531+ // a valid fd whose link name ends with an unsupported suffix
1532+ int32_t dlpFd = open("/data/file_test.xyz.dlp", O_CREAT | O_RDWR | O_TRUNC, S_IRWXU | S_IRWXG | S_IRWXO);
1533+ ASSERT_NE(dlpFd, -1);
1534+ 
1535+ DlpProperty property = BuildCloudProperty();
1536+ std::shared_ptr<DlpFile> filePtr;
1537+ // suffix "xyz" is not in FILE_TYPE_MAP: GetFileTypeBySuffix returns empty
1538+ EXPECT_EQ(DLP_PARSE_ERROR_VALUE_INVALID,
1539+ DlpFileManager::GetInstance().GenerateDlpFile(plainFd, dlpFd, property, filePtr, DLP_TEST_DIR));
1540+ 
1541+ close(plainFd);
1542+ close(dlpFd);
1543+ unlink("/data/file_test.txt");
1544+ unlink("/data/file_test.xyz.dlp");
1545+}
1546+ 
1547+/**
1548+ * @tc.name: DlpRawHmacCheckAndUpdateTruncated001
1549+ * @tc.desc: cover UpdateDlpFile fail branch of DlpRawHmacCheckAndUpdate
1550+ * @tc.type: FUNC
1551+ * @tc.require:
1552+ */
1553+HWTEST_F(DlpFileManagerTest, DlpRawHmacCheckAndUpdateTruncated001, TestSize.Level0)
1554+{
1555+ DLP_LOG_INFO(LABEL, "DlpRawHmacCheckAndUpdateTruncated001");
1556+ int32_t plainFd = -1;
1557+ int32_t dlpFd = -1;
1558+ ASSERT_TRUE(GenCloudRawDlpFile(plainFd, dlpFd));
1559+ 
1560+ // the generated raw dlp file passes HmacCheck; truncate it so CheckDlpFile
1561+ // fails inside UpdateDlpFile (fileLen <= FILE_HEAD)
1562+ ASSERT_EQ(0, ftruncate(dlpFd, TRUNCATED_FILE_SIZE));
1563+ lseek(dlpFd, 0, SEEK_SET);
1564+ std::vector<uint8_t> offlineCert;
1565+ std::shared_ptr<DlpFile> filePtr = std::make_shared<DlpRawFile>(dlpFd, "txt");
1566+ ASSERT_NE(filePtr, nullptr);
1567+ EXPECT_NE(DLP_OK,
1568+ DlpFileManager::GetInstance().DlpRawHmacCheckAndUpdate(filePtr, offlineCert, OPEN_COUNT_ZERO));
1569+ 
1570+ close(plainFd);
1571+ close(dlpFd);
1572+ unlink("/data/file_test.txt");
1573+ unlink("/data/file_test.docx.dlp");
1574+}
1575+ 
1576+/**
1577+ * @tc.name: OpenZipDlpFilePrepareFail001
1578+ * @tc.desc: cover PrepareDirs fail and GenerateRandomWorkDir fail branches of OpenZipDlpFile
1579+ * @tc.type: FUNC
1580+ * @tc.require:
1581+ */
1582+HWTEST_F(DlpFileManagerTest, OpenZipDlpFilePrepareFail001, TestSize.Level0)
1583+{
1584+ DLP_LOG_INFO(LABEL, "OpenZipDlpFilePrepareFail001");
1585+ std::shared_ptr<DlpFile> filePtr;
1586+ std::string appId = "test_appId";
1587+ 
1588+ // PrepareDirs fails: the parent of the work dir does not exist
1589+ EXPECT_NE(DLP_OK, DlpFileManager::GetInstance().OpenZipDlpFile(1000, filePtr,
1590+ "/data/nonexistent_parent_dir/sub", appId, "txt"));
1591+ 
1592+ // GenerateRandomWorkDir fails (RAND_bytes mocked)
1593+ DlpCMockCondition condition;
1594+ condition.mockSequence = { true };
1595+ SetMockConditions("RAND_bytes", condition);
1596+ EXPECT_EQ(DLP_PARSE_ERROR_CRYPTO_ENGINE_ERROR,
1597+ DlpFileManager::GetInstance().OpenZipDlpFile(1000, filePtr, DLP_TEST_DIR, appId, "txt"));
1598+ CleanMockConditions();
1599+}
1600+ 
1601+/**
1602+ * @tc.name: OpenDlpFileAlreadyOpened001
1603+ * @tc.desc: cover already opened branch of OpenDlpFile
1604+ * @tc.type: FUNC
1605+ * @tc.require:
1606+ */
1607+HWTEST_F(DlpFileManagerTest, OpenDlpFileAlreadyOpened001, TestSize.Level0)
1608+{
1609+ DLP_LOG_INFO(LABEL, "OpenDlpFileAlreadyOpened001");
1610+ int32_t plainFd = -1;
1611+ int32_t dlpFd = -1;
1612+ ASSERT_TRUE(GenCloudRawDlpFile(plainFd, dlpFd));
1613+ std::string appId = "test_appId";
1614+ 
1615+ // the dlp fd is registered in the map: OpenDlpFile returns DLP_OK with the mapped object
1616+ std::shared_ptr<DlpFile> openedPtr = std::make_shared<DlpRawFile>(dlpFd, "txt");
1617+ ASSERT_EQ(DLP_OK, DlpFileManager::GetInstance().AddDlpFileNode(openedPtr));
1618+ std::shared_ptr<DlpFile> filePtr;
1619+ EXPECT_EQ(DLP_OK, DlpFileManager::GetInstance().OpenDlpFile(dlpFd, filePtr, DLP_TEST_DIR, appId));
1620+ EXPECT_EQ(openedPtr, filePtr);
1621+ DlpFileManager::GetInstance().RemoveDlpFileNode(openedPtr);
1622+ 
1623+ close(plainFd);
1624+ close(dlpFd);
1625+ unlink("/data/file_test.txt");
1626+ unlink("/data/file_test.docx.dlp");
1627+}
1628+ 
1629+/**
1630+ * @tc.name: OpenDlpFileRawBranch001
1631+ * @tc.desc: cover the raw-file branch of OpenDlpFile
1632+ * @tc.type: FUNC
1633+ * @tc.require:
1634+ */
1635+HWTEST_F(DlpFileManagerTest, OpenDlpFileRawBranch001, TestSize.Level0)
1636+{
1637+ DLP_LOG_INFO(LABEL, "OpenDlpFileRawBranch001");
1638+ int32_t plainFd = -1;
1639+ int32_t dlpFd = -1;
1640+ ASSERT_TRUE(GenCloudRawDlpFile(plainFd, dlpFd));
1641+ std::string appId = "test_appId";
1642+ 
1643+ // the generated file is a raw (non-zip) dlp file: OpenRawDlpFile path is taken
1644+ std::shared_ptr<DlpFile> filePtr;
1645+ int32_t ret = DlpFileManager::GetInstance().OpenDlpFile(dlpFd, filePtr, DLP_TEST_DIR, appId);
1646+ if (ret == DLP_OK) {
1647+ // close it through the manager to clean the node
1648+ DlpFileManager::GetInstance().CloseDlpFile(filePtr);
1649+ }
1650+ close(plainFd);
1651+ close(dlpFd);
1652+ unlink("/data/file_test.txt");
1653+ unlink("/data/file_test.docx.dlp");
1654+}
1655+ 
1656+/**
1657+ * @tc.name: VerifyAndGetWaterMarkBranch001
1658+ * @tc.desc: cover canFind fallback and VerifyConsistent fail branches via ParseZipDlpFile
1659+ * @tc.type: FUNC
1660+ * @tc.require:
1661+ */
1662+HWTEST_F(DlpFileManagerTest, VerifyAndGetWaterMarkBranch001, TestSize.Level0)
1663+{
1664+ DLP_LOG_INFO(LABEL, "VerifyAndGetWaterMarkBranch001");
1665+ int32_t fd = open("/data/fuse_test_dlp.txt", O_RDWR | O_CREAT | O_TRUNC, S_IRWXU);
1666+ ASSERT_NE(fd, -1);
1667+ std::shared_ptr<DlpFile> filePtr = std::make_shared<DlpZipFile>(fd, DLP_TEST_DIR, 0, "txt");
1668+ ASSERT_NE(filePtr, nullptr);
1669+ // cert with an empty fileId (matches the empty file plaintext) and countdown 0:
1670+ // the file object countdown is 100 so VerifyConsistent fails on the countdown check
1671+ sptr<CertParcel> certParcel = BuildCertParcelByType(CLOUD_ACCOUNT);
1672+ ASSERT_NE(certParcel, nullptr);
1673+ ordered_json jsonObj = ordered_json::parse(
1674+ std::string(certParcel->cert.begin(), certParcel->cert.end()), nullptr, false);
1675+ ASSERT_TRUE(!jsonObj.is_discarded() && jsonObj.is_object());
1676+ jsonObj["fileId"] = "";
1677+ jsonObj["countdown"] = 0;
1678+ std::string certStr = jsonObj.dump();
1679+ certParcel->cert = std::vector<uint8_t>(certStr.begin(), certStr.end());
1680+ certParcel->fileId = "";
1681+ filePtr->SetCountdown(100);
1682+ 
1683+ int32_t ret = DlpFileManager::GetInstance().ParseZipDlpFile(filePtr, "app_id", fd, certParcel);
1684+ EXPECT_NE(DLP_OK, ret);
1685+ close(fd);
1686+ unlink("/data/fuse_test_dlp.txt");
1687+}
1688+ 
1689+/**
1690+ * @tc.name: ParseZipDlpFileSetCipherFail001
1691+ * @tc.desc: cover SetCipher fail branch of ParseZipDlpFile
1692+ * @tc.type: FUNC
1693+ * @tc.require:
1694+ */
1695+HWTEST_F(DlpFileManagerTest, ParseZipDlpFileSetCipherFail001, TestSize.Level0)
1696+{
1697+ DLP_LOG_INFO(LABEL, "ParseZipDlpFileSetCipherFail001");
1698+ int32_t fd = open("/data/fuse_test_dlp.txt", O_RDWR | O_CREAT | O_TRUNC, S_IRWXU);
1699+ ASSERT_NE(fd, -1);
1700+ std::shared_ptr<DlpFile> filePtr = std::make_shared<DlpZipFile>(fd, DLP_TEST_DIR, 0, "txt");
1701+ ASSERT_NE(filePtr, nullptr);
1702+ 
1703+ // SetCipher fails: memcpy_s mocked late in the sequence
1704+ sptr<CertParcel> certParcel = BuildCertParcelByType(CLOUD_ACCOUNT);
1705+ ASSERT_NE(certParcel, nullptr);
1706+ DlpCMockCondition condition;
1707+ condition.mockSequence = { false, true };
1708+ SetMockConditions("memcpy_s", condition);
1709+ int32_t ret = DlpFileManager::GetInstance().ParseZipDlpFile(filePtr, "app_id", fd, certParcel);
1710+ CleanMockConditions();
1711+ EXPECT_NE(DLP_OK, ret);
1712+ close(fd);
1713+ unlink("/data/fuse_test_dlp.txt");
1714+}
1715+ 
1716+/**
1717+ * @tc.name: ParseZipDlpFileSetNotOwnerFail001
1718+ * @tc.desc: cover SetNotOwnerAndReadOnce fail branch of ParseZipDlpFile
1719+ * @tc.type: FUNC
1720+ * @tc.require:
1721+ */
1722+HWTEST_F(DlpFileManagerTest, ParseZipDlpFileSetNotOwnerFail001, TestSize.Level0)
1723+{
1724+ DLP_LOG_INFO(LABEL, "ParseZipDlpFileSetNotOwnerFail001");
1725+ int32_t fd = open("/data/fuse_test_dlp.txt", O_RDWR | O_CREAT | O_TRUNC, S_IRWXU);
1726+ ASSERT_NE(fd, -1);
1727+ std::shared_ptr<DlpFile> filePtr = std::make_shared<DlpZipFile>(fd, DLP_TEST_DIR, 0, "txt");
1728+ ASSERT_NE(filePtr, nullptr);
1729+ 
1730+ // SetNotOwnerAndReadOnce fails on the invalid dlp fd passed to GetFilePathByFd
1731+ sptr<CertParcel> certParcel = BuildCertParcelByType(CLOUD_ACCOUNT);
1732+ ASSERT_NE(certParcel, nullptr);
1733+ int32_t ret = DlpFileManager::GetInstance().ParseZipDlpFile(filePtr, "app_id", -1, certParcel);
1734+ EXPECT_NE(DLP_OK, ret);
1735+ close(fd);
1736+ unlink("/data/fuse_test_dlp.txt");
1737+}
1738+ 
1739+/**
1740+ * @tc.name: ParseZipDlpFileEnterpriseHmacFail001
1741+ * @tc.desc: cover SetEnterpriseInfoForDlpFileAndCheck fail branch of ParseZipDlpFile
1742+ * @tc.type: FUNC
1743+ * @tc.require:
1744+ */
1745+HWTEST_F(DlpFileManagerTest, ParseZipDlpFileEnterpriseHmacFail001, TestSize.Level0)
1746+{
1747+ DLP_LOG_INFO(LABEL, "ParseZipDlpFileEnterpriseHmacFail001");
1748+ int32_t fd = open("/data/fuse_test_dlp.txt", O_RDWR | O_CREAT | O_TRUNC, S_IRWXU);
1749+ ASSERT_NE(fd, -1);
1750+ std::shared_ptr<DlpFile> filePtr = std::make_shared<DlpZipFile>(fd, DLP_TEST_DIR, 0, "txt");
1751+ ASSERT_NE(filePtr, nullptr);
1752+ // the enterprise path runs SetEnterpriseInfoForDlpFile and then HmacCheck fails on the
1753+ // zip file object whose encDataFd_ is invalid
1754+ filePtr->SetAccountType(ENTERPRISE_ACCOUNT);
1755+ 
1756+ // build an enterprise cert without fileId so VerifyConsistent passes (empty == empty)
1757+ sptr<CertParcel> certParcel = BuildCertParcelByType(ENTERPRISE_ACCOUNT);
1758+ ASSERT_NE(certParcel, nullptr);
1759+ ordered_json jsonObj = ordered_json::parse(
1760+ std::string(certParcel->cert.begin(), certParcel->cert.end()), nullptr, false);
1761+ ASSERT_TRUE(!jsonObj.is_discarded() && jsonObj.is_object());
1762+ jsonObj.erase("fileId");
1763+ std::string certStr = jsonObj.dump();
1764+ certParcel->cert = std::vector<uint8_t>(certStr.begin(), certStr.end());
1765+ certParcel->fileId = "";
1766+ 
1767+ int32_t ret = DlpFileManager::GetInstance().ParseZipDlpFile(filePtr, "app_id", fd, certParcel);
1768+ EXPECT_NE(DLP_OK, ret);
1769+ close(fd);
1770+ unlink("/data/fuse_test_dlp.txt");
1771+}
1772+ 
1773+/**
1774+ * @tc.name: ParseRawDlpFileVerifyFail001
1775+ * @tc.desc: cover VerifyAndGetWaterMark fail and SetNotOwnerAndReadOnce fail branches of ParseRawDlpFile
1776+ * @tc.type: FUNC
1777+ * @tc.require:
1778+ */
1779+HWTEST_F(DlpFileManagerTest, ParseRawDlpFileVerifyFail001, TestSize.Level0)
1780+{
1781+ DLP_LOG_INFO(LABEL, "ParseRawDlpFileVerifyFail001");
1782+ int32_t fd = open("/data/fuse_test_dlp.txt", O_RDWR | O_CREAT | O_TRUNC, S_IRWXU);
1783+ ASSERT_NE(fd, -1);
1784+ 
1785+ // cloud account with fileId in the cert but empty file plaintext: VerifyConsistent fails
1786+ std::shared_ptr<DlpFile> filePtr = std::make_shared<DlpRawFile>(fd, "txt");
1787+ ASSERT_NE(filePtr, nullptr);
1788+ sptr<CertParcel> certParcel = BuildCertParcelByType(CLOUD_ACCOUNT);
1789+ ASSERT_NE(certParcel, nullptr);
1790+ EXPECT_NE(DLP_OK,
1791+ DlpFileManager::GetInstance().ParseRawDlpFile(fd, filePtr, "app_id", "txt", certParcel));
1792+ 
1793+ // empty-fileId cert passes the consistency checks: with the invalid dlp fd the flow
1794+ // reaches SetNotOwnerAndReadOnce and fails at GetFilePathByFd
1795+ std::shared_ptr<DlpFile> filePtr2 = std::make_shared<DlpRawFile>(fd, "txt");
1796+ ASSERT_NE(filePtr2, nullptr);
1797+ ordered_json jsonObj = ordered_json::parse(
1798+ std::string(certParcel->cert.begin(), certParcel->cert.end()), nullptr, false);
1799+ ASSERT_TRUE(!jsonObj.is_discarded() && jsonObj.is_object());
1800+ jsonObj["fileId"] = "";
1801+ std::string certStr = jsonObj.dump();
1802+ sptr<CertParcel> certParcel2 = new (std::nothrow) CertParcel();
1803+ ASSERT_NE(certParcel2, nullptr);
1804+ certParcel2->cert = std::vector<uint8_t>(certStr.begin(), certStr.end());
1805+ certParcel2->fileId = "";
1806+ EXPECT_NE(DLP_OK,
1807+ DlpFileManager::GetInstance().ParseRawDlpFile(-1, filePtr2, "app_id", "txt", certParcel2));
1808+ 
1809+ close(fd);
1810+ unlink("/data/fuse_test_dlp.txt");
1811+}
1812+ 
1813+/**
1814+ * @tc.name: OpenRawDlpFileOfflineCert001
1815+ * @tc.desc: cover offlineCert branch and ParseRawDlpFile fail branch of OpenRawDlpFile
1816+ * @tc.type: FUNC
1817+ * @tc.require:
1818+ */
1819+HWTEST_F(DlpFileManagerTest, OpenRawDlpFileOfflineCert001, TestSize.Level0)
1820+{
1821+ DLP_LOG_INFO(LABEL, "OpenRawDlpFileOfflineCert001");
1822+ int32_t plainFd = -1;
1823+ int32_t dlpFd = -1;
1824+ ASSERT_TRUE(GenCloudRawDlpFile(plainFd, dlpFd));
1825+ std::string appId = "test_appId";
1826+ 
1827+ // offline access with count 0: GetOfflineCertSize != 0 path is prepared; the parse
1828+ // eventually fails on the account checks so the offline cert branch is exercised
1829+ std::shared_ptr<DlpFile> filePtr;
1830+ int32_t ret = DlpFileManager::GetInstance().OpenRawDlpFile(dlpFd, filePtr, appId, "txt");
1831+ EXPECT_NE(DLP_PARSE_ERROR_PTR_NULL, ret);
1832+ 
1833+ close(plainFd);
1834+ close(dlpFd);
1835+ unlink("/data/file_test.txt");
1836+ unlink("/data/file_test.docx.dlp");
1837+}
1838+ 
1295} // namespace DlpPermission1839} // namespace DlpPermission
1296} // namespace Security1840} // namespace Security
1297} // namespace OHOS1841} // namespace OHOS
@@ -20,6 +20,7 @@
20#include <iostream>20#include <iostream>
21#include <fstream>21#include <fstream>
22#include <thread>22#include <thread>
23+#include <unistd.h>
23#include <sys/types.h>24#include <sys/types.h>
24#include <sys/stat.h>25#include <sys/stat.h>
25#include "accesstoken_kit.h"26#include "accesstoken_kit.h"
@@ -30,6 +31,8 @@
30#include "dlp_utils.cpp"31#include "dlp_utils.cpp"
31#include "token_setproc.h"32#include "token_setproc.h"
32#include "c_mock_common.h"33#include "c_mock_common.h"
34+#include "dlp_zip.h"
35+#include "dlp_permission_public_interface.h"
33 36 
34using namespace testing::ext;37using namespace testing::ext;
35using namespace OHOS::Security::DlpPermission;38using namespace OHOS::Security::DlpPermission;
@@ -43,6 +46,113 @@ static const std::string PPT_STRINGS = "ppt";
43static const std::string DLP_MANAGER_BUNDLE = "com.ohos.dlpmanager";46static const std::string DLP_MANAGER_BUNDLE = "com.ohos.dlpmanager";
44static const std::string PASTEBOARD_SERVICE_NAME = "pasteboard_service";47static const std::string PASTEBOARD_SERVICE_NAME = "pasteboard_service";
45const int32_t FILEID_SIZE_VALID = 1;48const int32_t FILEID_SIZE_VALID = 1;
49+// constants for the branch cases below (aligned with dlp_utils.cpp)
50+const int32_t RAW_FILEID_SIZE = 46;
51+const uint32_t DLP_VERSION_NO_HMAC = 2;
52+const uint32_t LARGE_FILE_SIZE = 102400;
53+const uint32_t LONG_PATH_SEG_COUNT = 40;
54+const char DEEP_DIR_PREFIX[] = "/data/fuse_test_deep";
55+const char OVERSIZE_FILE[] = "/data/fuse_test_oversize.txt";
56+const char FILEID_NONZERO = 1;
57+const int32_t OPEN_COUNT_FLAG_ON = 1;
58+const int32_t OPEN_COUNT_FLAG_OFF = 0;
59+const int32_t WATERMARK_FLAG_ON = 1;
60+const int32_t COUNTDOWN_VALUE = 1;
61+const int32_t ALLOWED_OPEN_COUNT_VALUE = 0;
62+ 
63+// create a nested directory chain of segmentCount segments under the prefix
64+static bool CreateNestedDirs(std::string& deepDir, uint32_t segmentCount, const std::string& segName)
65+{
66+ if (mkdir(DEEP_DIR_PREFIX, S_IRWXU | S_IRWXG | S_IRWXO) != 0) {
67+ return false;
68+ }
69+ deepDir = DEEP_DIR_PREFIX;
70+ for (uint32_t i = 0; i < segmentCount; i++) {
71+ deepDir += "/" + segName + std::to_string(i);
72+ if (mkdir(deepDir.c_str(), S_IRWXU | S_IRWXG | S_IRWXO) != 0) {
73+ return false;
74+ }
75+ }
76+ return true;
77+}
78+ 
79+// remove the nested directory chain from the deepest level up
80+static void RemoveNestedDirs(std::string deepDir)
81+{
82+ while (deepDir != DEEP_DIR_PREFIX) {
83+ rmdir(deepDir.c_str());
84+ size_t last = deepDir.find_last_of('/');
85+ deepDir = deepDir.substr(0, last);
86+ }
87+ rmdir(DEEP_DIR_PREFIX);
88+}
89+ 
90+// pre-create the sandbox cache path chain used by GetGenerateInfoStr so the zip
91+// success path is reachable; returns true when the cache dir exists afterwards
92+static bool PrepareSandboxCachePath()
93+{
94+ const std::string cacheChain = "/data/storage/el2/base/files/cache";
95+ std::string cur;
96+ size_t pos = 0;
97+ while (pos != std::string::npos) {
98+ size_t next = cacheChain.find('/', pos + 1);
99+ cur = (next == std::string::npos) ? cacheChain : cacheChain.substr(0, next);
100+ if (!cur.empty() && mkdir(cur.c_str(), S_IRWXU | S_IRWXG | S_IRWXO) != 0 && errno != EEXIST) {
101+ return false;
102+ }
103+ pos = next;
104+ }
105+ struct stat buf = {};
106+ return stat(cacheChain.c_str(), &buf) == 0 && S_ISDIR(buf.st_mode);
107+}
108+ 
109+// build a dlp zip with the 3 required entries; the general info content is caller-provided
110+static int32_t BuildDlpZipFile(const char* zipPath, const std::string& generalInfo)
111+{
112+ std::string infoFile("dlp_general_info");
113+ std::string certFile("dlp_cert");
114+ std::string dataFile("encrypted_data");
115+ int32_t fdInfo = open(infoFile.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0666);
116+ if (fdInfo < 0) {
117+ return -1;
118+ }
119+ write(fdInfo, generalInfo.c_str(), generalInfo.size());
120+ lseek(fdInfo, 0, SEEK_SET);
121+ int32_t fdCert = open(certFile.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0666);
122+ int32_t fdData = open(dataFile.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0666);
123+ if (fdCert < 0 || fdData < 0) {
124+ close(fdInfo);
125+ if (fdCert >= 0) {
126+ close(fdCert);
127+ }
128+ if (fdData >= 0) {
129+ close(fdData);
130+ }
131+ return -1;
132+ }
133+ int32_t zf = open(zipPath, O_RDWR | O_CREAT | O_TRUNC, 0666);
134+ if (zf < 0) {
135+ close(fdInfo);
136+ close(fdCert);
137+ close(fdData);
138+ return -1;
139+ }
140+ int32_t res = AddFileContextToZip(fdInfo, infoFile.c_str(), zipPath);
141+ if (res == 0) {
142+ res = AddFileContextToZip(fdCert, certFile.c_str(), zipPath);
143+ }
144+ if (res == 0) {
145+ res = AddFileContextToZip(fdData, dataFile.c_str(), zipPath);
146+ }
147+ close(fdInfo);
148+ close(fdCert);
149+ close(fdData);
150+ close(zf);
151+ unlink(infoFile.c_str());
152+ unlink(certFile.c_str());
153+ unlink(dataFile.c_str());
154+ return res;
155+}
46}156}
47 157 
48static bool GetBundleInfoForSelfByCurrentToken(int32_t& ret, OHOS::AppExecFwk::BundleInfo& bundleInfo)158static bool GetBundleInfoForSelfByCurrentToken(int32_t& ret, OHOS::AppExecFwk::BundleInfo& bundleInfo)
@@ -772,3 +882,319 @@ HWTEST_F(DlpUtilsTest, IsExistFileLargeFile001, TestSize.Level1)
772 882 
773 unlink(path.c_str());883 unlink(path.c_str());
774}884}
885+ 
886+/**
887+ * @tc.name: GetFilePathByFdTruncate001
888+ * @tc.desc: cover readlink result longer than MAX_DLP_FILE_SIZE branches of
889+ * GetFilePathByFd and GetFileNameWithFd
890+ * @tc.type: FUNC
891+ * @tc.require:
892+ */
893+HWTEST_F(DlpUtilsTest, GetFilePathByFdTruncate001, TestSize.Level1)
894+{
895+ DLP_LOG_INFO(UT_LABEL, "GetFilePathByFdTruncate001");
896+ 
897+ // build a nested path longer than MAX_DLP_FILE_SIZE (1000)
898+ std::string deepDir;
899+ ASSERT_TRUE(CreateNestedDirs(deepDir, LONG_PATH_SEG_COUNT, "dirdirdirdirdirdirdirdirdirdir_"));
900+ std::string deepFile = deepDir + "/f.txt";
901+ ASSERT_LT(1000u, deepFile.size());
902+ int fd = open(deepFile.c_str(), O_RDWR | O_CREAT | O_TRUNC, S_IRWXU);
903+ ASSERT_NE(fd, -1);
904+ 
905+ std::string path;
906+ // readlink returns more than MAX_DLP_FILE_SIZE: truncated path is rejected
907+ ASSERT_EQ(DLP_PARSE_ERROR_FD_ERROR, DlpUtils::GetFilePathByFd(fd, path));
908+ std::string fileName;
909+ ASSERT_EQ(DLP_PARSE_ERROR_FD_ERROR, DlpUtils::GetFileNameWithFd(fd, fileName));
910+ 
911+ close(fd);
912+ unlink(deepFile.c_str());
913+ RemoveNestedDirs(deepDir);
914+}
915+ 
916+/**
917+ * @tc.name: IsExistFileTooLarge001
918+ * @tc.desc: cover file size >= FILE_MAX_SIZE branch of IsExistFile
919+ * @tc.type: FUNC
920+ * @tc.require:
921+ */
922+HWTEST_F(DlpUtilsTest, IsExistFileTooLarge001, TestSize.Level1)
923+{
924+ DLP_LOG_INFO(UT_LABEL, "IsExistFileTooLarge001");
925+ int fd = open(OVERSIZE_FILE, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU);
926+ ASSERT_NE(fd, -1);
927+ // write a buffer so the file is larger than FILE_MAX_SIZE (102400)
928+ std::string bigBuf(LARGE_FILE_SIZE + 1, 'a');
929+ ASSERT_EQ(static_cast<ssize_t>(bigBuf.size()), write(fd, bigBuf.c_str(), bigBuf.size()));
930+ close(fd);
931+ 
932+ // st_size >= FILE_MAX_SIZE: IsExistFile returns false
933+ EXPECT_FALSE(IsExistFile(OVERSIZE_FILE));
934+ unlink(OVERSIZE_FILE);
935+}
936+ 
937+/**
938+ * @tc.name: GetGenerateInfoStrGetcwdFail001
939+ * @tc.desc: cover getcwd fail branch of GetGenerateInfoStr
940+ * @tc.type: FUNC
941+ * @tc.require:
942+ */
943+HWTEST_F(DlpUtilsTest, GetGenerateInfoStrGetcwdFail001, TestSize.Level1)
944+{
945+ DLP_LOG_INFO(UT_LABEL, "GetGenerateInfoStrGetcwdFail001");
946+ char originCwd[256] = {0};
947+ ASSERT_NE(nullptr, getcwd(originCwd, sizeof(originCwd)));
948+ 
949+ // build a path longer than DLP_CWD_MAX (256) and chdir into it: getcwd with a
950+ // 256-byte buffer fails with ERANGE
951+ std::string deepDir;
952+ ASSERT_TRUE(CreateNestedDirs(deepDir, LONG_PATH_SEG_COUNT, "dir_dir_dir_"));
953+ ASSERT_LT(256u, deepDir.size());
954+ ASSERT_EQ(0, chdir(deepDir.c_str()));
955+ 
956+ int32_t fd = open("/data/fuse_test_zip_fd.txt", O_RDWR | O_CREAT | O_TRUNC, S_IRWXU);
957+ ASSERT_NE(fd, -1);
958+ // getcwd fails inside GetGenerateInfoStr: empty string is returned
959+ EXPECT_EQ(DEFAULT_STRINGS, GetGenerateInfoStr(fd));
960+ close(fd);
961+ unlink("/data/fuse_test_zip_fd.txt");
962+ 
963+ // restore the working directory and clean the nested chain
964+ ASSERT_EQ(0, chdir(originCwd));
965+ RemoveNestedDirs(deepDir);
966+}
967+ 
968+/**
969+ * @tc.name: GetGenerateInfoStrZipBranch001
970+ * @tc.desc: cover CheckUnzipFileInfo fail and success content branches of GetGenerateInfoStr
971+ * @tc.type: FUNC
972+ * @tc.require:
973+ */
974+HWTEST_F(DlpUtilsTest, GetGenerateInfoStrZipBranch001, TestSize.Level1)
975+{
976+ DLP_LOG_INFO(UT_LABEL, "GetGenerateInfoStrZipBranch001");
977+ const char* zipPath = "/data/fuse_test_gen_info.dlp";
978+ 
979+ // valid general info: dlpVersion 2 (no hmacValue required), realType support_txt_dlp
980+ GenerateInfoParams params = {
981+ .version = DLP_VERSION_NO_HMAC,
982+ .offlineAccessFlag = false,
983+ .contactAccount = "contact",
984+ .extraInfo = {},
985+ .hmacVal = "",
986+ .realType = "support_txt_dlp",
987+ .certSize = 0,
988+ .fileId = "",
989+ .allowedOpenCount = 0,
990+ .waterMarkConfig = false,
991+ .countdown = 0,
992+ .nickNameMask = "",
993+ };
994+ std::string generalInfo;
995+ ASSERT_EQ(DLP_OK, GenerateDlpGeneralInfo(params, generalInfo));
996+ 
997+ // build a full 3-entry dlp zip: the general info content is read back
998+ ASSERT_EQ(0, BuildDlpZipFile(zipPath, generalInfo));
999+ int32_t fd = open(zipPath, O_RDONLY);
1000+ ASSERT_NE(fd, -1);
1001+ ASSERT_EQ(true, IsZipFile(fd));
1002+ if (PrepareSandboxCachePath()) {
1003+ // CheckUnzipFileInfo ok and UnzipSpecificFile ok: the general info string is returned
1004+ std::string result = GetGenerateInfoStr(fd);
1005+ EXPECT_NE(DEFAULT_STRINGS, result);
1006+ }
1007+ close(fd);
1008+ unlink(zipPath);
1009+}
1010+ 
1011+/**
1012+ * @tc.name: GetGenerateInfoStrCheckFail001
1013+ * @tc.desc: cover CheckUnzipFileInfo fail branch of GetGenerateInfoStr
1014+ * @tc.type: FUNC
1015+ * @tc.require:
1016+ */
1017+HWTEST_F(DlpUtilsTest, GetGenerateInfoStrCheckFail001, TestSize.Level1)
1018+{
1019+ DLP_LOG_INFO(UT_LABEL, "GetGenerateInfoStrCheckFail001");
1020+ const char* zipPath = "/data/fuse_test_gen_info.dlp";
1021+ 
1022+ // build a single-entry zip: IsZipFile is true (has dlp_general_info) but
1023+ // CheckUnzipFileInfo fails (entry count != 3)
1024+ std::string infoFile("dlp_general_info");
1025+ int32_t fdInfo = open(infoFile.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0666);
1026+ ASSERT_NE(fdInfo, -1);
1027+ std::string content = "{\"dlpVersion\":2,\"extraInfo\":[],\"offlineAccess\":false,\"contactAccount\":\"c\"}";
1028+ write(fdInfo, content.c_str(), content.size());
1029+ lseek(fdInfo, 0, SEEK_SET);
1030+ int32_t zf = open(zipPath, O_RDWR | O_CREAT | O_TRUNC, 0666);
1031+ ASSERT_NE(zf, -1);
1032+ ASSERT_EQ(0, AddFileContextToZip(fdInfo, infoFile.c_str(), zipPath));
1033+ close(fdInfo);
1034+ unlink(infoFile.c_str());
1035+ 
1036+ int32_t fd = open(zipPath, O_RDONLY);
1037+ ASSERT_NE(fd, -1);
1038+ ASSERT_EQ(true, IsZipFile(fd));
1039+ // CheckUnzipFileInfo fails: empty string is returned
1040+ if (PrepareSandboxCachePath()) {
1041+ EXPECT_EQ(DEFAULT_STRINGS, GetGenerateInfoStr(fd));
1042+ }
1043+ close(fd);
1044+ close(zf);
1045+ unlink(zipPath);
1046+}
1047+ 
1048+/**
1049+ * @tc.name: GetRealTypeWithFdZipBranch001
1050+ * @tc.desc: cover the zip branch of GetRealTypeWithFd
1051+ * @tc.type: FUNC
1052+ * @tc.require:
1053+ */
1054+HWTEST_F(DlpUtilsTest, GetRealTypeWithFdZipBranch001, TestSize.Level1)
1055+{
1056+ DLP_LOG_INFO(UT_LABEL, "GetRealTypeWithFdZipBranch001");
1057+ const char* zipPath = "/data/fuse_test_realtype.dlp";
1058+ 
1059+ // build a full dlp zip whose general info carries realType support_txt_dlp
1060+ GenerateInfoParams params = {
1061+ .version = DLP_VERSION_NO_HMAC,
1062+ .offlineAccessFlag = false,
1063+ .contactAccount = "contact",
1064+ .extraInfo = {},
1065+ .hmacVal = "",
1066+ .realType = "support_txt_dlp",
1067+ .certSize = 0,
1068+ .fileId = "",
1069+ .allowedOpenCount = 0,
1070+ .waterMarkConfig = false,
1071+ .countdown = 0,
1072+ .nickNameMask = "",
1073+ };
1074+ std::string generalInfo;
1075+ ASSERT_EQ(DLP_OK, GenerateDlpGeneralInfo(params, generalInfo));
1076+ ASSERT_EQ(0, BuildDlpZipFile(zipPath, generalInfo));
1077+ int32_t fd = open(zipPath, O_RDONLY);
1078+ ASSERT_NE(fd, -1);
1079+ 
1080+ // IsZipFile is true: the type is extracted from dlp_general_info
1081+ if (PrepareSandboxCachePath()) {
1082+ bool isFromUriName = false;
1083+ std::string generateInfoStr;
1084+ ASSERT_EQ(TXT_STRINGS, DlpUtils::GetRealTypeWithFd(fd, isFromUriName, generateInfoStr));
1085+ }
1086+ close(fd);
1087+ unlink(zipPath);
1088+}
1089+ 
1090+/**
1091+ * @tc.name: GetRealTypeWithRawFileCountdown001
1092+ * @tc.desc: cover fileType bigger than COUNTDOWN_FILETYPE branch of GetRealTypeWithRawFile
1093+ * @tc.type: FUNC
1094+ * @tc.require:
1095+ */
1096+HWTEST_F(DlpUtilsTest, GetRealTypeWithRawFileCountdown001, TestSize.Level1)
1097+{
1098+ DLP_LOG_INFO(UT_LABEL, "GetRealTypeWithRawFileCountdown001");
1099+ int fd = open("/data/fuse_test.txt.dlp", O_RDWR | O_CREAT | O_TRUNC, S_IRWXU);
1100+ ASSERT_NE(fd, -1);
1101+ 
1102+ // full header with fileType 10001: fileType - COUNTDOWN_FILETYPE = 1 -> txt
1103+ struct DlpHeader header = {
1104+ .magic = DLP_FILE_MAGIC,
1105+ .certSize = 20,
1106+ .contactAccountSize = 20,
1107+ .fileType = 10001,
1108+ };
1109+ uint8_t buffer[8] = {0};
1110+ write(fd, buffer, 8);
1111+ write(fd, &header, sizeof(header));
1112+ lseek(fd, 0, SEEK_SET);
1113+ ASSERT_EQ(TXT_STRINGS, DlpUtils::GetRealTypeWithRawFile(fd));
1114+ close(fd);
1115+ unlink("/data/fuse_test.txt.dlp");
1116+}
1117+ 
1118+/**
1119+ * @tc.name: GetRawFileAllowedOpenCountFullTail001
1120+ * @tc.desc: cover full tail branches of GetRawFileAllowedOpenCount
1121+ * @tc.type: FUNC
1122+ * @tc.require:
1123+ */
1124+HWTEST_F(DlpUtilsTest, GetRawFileAllowedOpenCountFullTail001, TestSize.Level1)
1125+{
1126+ DLP_LOG_INFO(UT_LABEL, "GetRawFileAllowedOpenCountFullTail001");
1127+ int fd = open("/data/fuse_test.txt.dlp", O_RDWR | O_CREAT | O_TRUNC, S_IRWXU);
1128+ ASSERT_NE(fd, -1);
1129+ 
1130+ // file tail layout: watermark(4) flag(4) allowedOpenCount(4) fileId(46)
1131+ int32_t watermark = WATERMARK_FLAG_ON;
1132+ int32_t flag = OPEN_COUNT_FLAG_OFF;
1133+ int32_t allowedOpenCount = ALLOWED_OPEN_COUNT_VALUE;
1134+ uint8_t fileId[RAW_FILEID_SIZE] = {0};
1135+ fileId[0] = FILEID_NONZERO; // first fileId byte non-zero with flag == 0
1136+ write(fd, &watermark, sizeof(int32_t));
1137+ write(fd, &flag, sizeof(int32_t));
1138+ write(fd, &allowedOpenCount, sizeof(int32_t));
1139+ write(fd, fileId, RAW_FILEID_SIZE);
1140+ 
1141+ int32_t count = 0;
1142+ bool watermarkConfig = false;
1143+ // watermark and flag are read, allowedOpenCount stays 0, fileId[0] != 0 sets it to 1
1144+ ASSERT_EQ(DLP_OK, DlpUtils::GetRawFileAllowedOpenCount(fd, count, watermarkConfig));
1145+ EXPECT_TRUE(watermarkConfig);
1146+ EXPECT_EQ(OPEN_COUNT_FLAG_ON, count);
1147+ 
1148+ // flag == 1: allowedOpenCount is read from the file and keeps its value
1149+ lseek(fd, 0, SEEK_SET);
1150+ ftruncate(fd, 0);
1151+ lseek(fd, 0, SEEK_SET);
1152+ flag = OPEN_COUNT_FLAG_ON;
1153+ allowedOpenCount = COUNTDOWN_VALUE;
1154+ fileId[0] = 0;
1155+ write(fd, &watermark, sizeof(int32_t));
1156+ write(fd, &flag, sizeof(int32_t));
1157+ write(fd, &allowedOpenCount, sizeof(int32_t));
1158+ write(fd, fileId, RAW_FILEID_SIZE);
1159+ ASSERT_EQ(DLP_OK, DlpUtils::GetRawFileAllowedOpenCount(fd, count, watermarkConfig));
1160+ EXPECT_EQ(COUNTDOWN_VALUE, count);
1161+ 
1162+ close(fd);
1163+ unlink("/data/fuse_test.txt.dlp");
1164+}
1165+ 
1166+/**
1167+ * @tc.name: GetRealTypeWithFdFileNameFail001
1168+ * @tc.desc: cover GetFileNameWithFd fail branch of GetRealTypeWithFd
1169+ * @tc.type: FUNC
1170+ * @tc.require:
1171+ */
1172+HWTEST_F(DlpUtilsTest, GetRealTypeWithFdFileNameFail001, TestSize.Level1)
1173+{
1174+ DLP_LOG_INFO(UT_LABEL, "GetRealTypeWithFdFileNameFail001");
1175+ 
1176+ // invalid fd: the raw type is empty and GetFileNameWithFd fails, empty string returned
1177+ bool isFromUriName = false;
1178+ std::string generateInfoStr;
1179+ ASSERT_EQ(DEFAULT_STRINGS, DlpUtils::GetRealTypeWithFd(-1, isFromUriName, generateInfoStr));
1180+ ASSERT_EQ(DEFAULT_STRINGS, DlpUtils::GetRealTypeWithFd(-1, isFromUriName, generateInfoStr, true));
1181+}
1182+ 
1183+/**
1184+ * @tc.name: GetUdid001
1185+ * @tc.desc: cover success branch of GetUdid
1186+ * @tc.type: FUNC
1187+ * @tc.require:
1188+ */
1189+HWTEST_F(DlpUtilsTest, GetUdid001, TestSize.Level1)
1190+{
1191+ DLP_LOG_INFO(UT_LABEL, "GetUdid001");
1192+ std::string udid;
1193+ // GetDevUdid succeeds on device: the udid string is filled and true returned
1194+ if (DlpUtils::GetUdid(udid)) {
1195+ EXPECT_FALSE(udid.empty());
1196+ } else {
1197+ // no device udid in the current environment
1198+ EXPECT_TRUE(udid.empty());
1199+ }
1200+}
@@ -835,4 +835,369 @@ HWTEST_F(DlpZipTest, UnzipSpecificFile004, TestSize.Level0)
835 CleanMockConditions();835 CleanMockConditions();
836 CloseAndUnlink(fd, zipFile.c_str());836 CloseAndUnlink(fd, zipFile.c_str());
837 CloseAndUnlink(fd1, inZipInfo.c_str());837 CloseAndUnlink(fd1, inZipInfo.c_str());
838+}
839+ 
840+namespace {
841+// callback that closes the current file via the real api and reports failure
842+static int UnzCloseCurrentFileReply(unzFile file)
843+{
844+ unzCloseCurrentFile(file);
845+ return DLP_ZIP_FAIL;
846+}
847+ 
848+// callback that fills the file info with compressed_size < uncompressed_size so the size check fails
849+static int UnzGetFileInfoSizeReply(unzFile file, unz_file_info64* pfile_info,
850+ char* szFileName, uLong fileNameBufferSize,
851+ void* extraField, uLong extraFiledBufferSize,
852+ char* szComment, uLong commentBufferSize)
853+{
854+ int res = unzGetCurrentFileInfo64(file, pfile_info, szFileName, fileNameBufferSize,
855+ extraField, extraFiledBufferSize, szComment, commentBufferSize);
856+ if (res == UNZ_OK) {
857+ pfile_info->compressed_size = 0;
858+ pfile_info->uncompressed_size = 1;
859+ }
860+ return res;
861+}
862+}
863+ 
864+/**
865+ * @tc.name: AddBuffToZip007
866+ * @tc.desc: cover zipName nullptr and dlp_cert zero buffer write fail branches
867+ * @tc.type: FUNC
868+ * @tc.require:
869+ */
870+HWTEST_F(DlpZipTest, AddBuffToZip007, TestSize.Level0)
871+{
872+ DLP_LOG_INFO(LABEL, "AddBuffToZip007");
873+ std::string buf("123");
874+ std::string nameInZip("dlp_cert");
875+ std::string zipName("dlp_test_zip");
876+ 
877+ int32_t fd = open(zipName.c_str(), O_RDWR | O_CREAT, 0666);
878+ ASSERT_NE(fd, -1);
879+ 
880+ // zipName == nullptr: return DLP_ZIP_FAIL
881+ ASSERT_EQ(DLP_ZIP_FAIL, AddBuffToZip(buf.c_str(), buf.size(), nameInZip.c_str(), nullptr));
882+ 
883+ // nameInZip is dlp_cert: the zero padding write (2nd zipWriteInFileInZip) fails
884+ DlpCMockCondition condition;
885+ condition.mockSequence = { false, true };
886+ SetMockConditions("zipWriteInFileInZip", condition);
887+ ASSERT_EQ(DLP_ZIP_FAIL, AddBuffToZip(buf.c_str(), buf.size(), nameInZip.c_str(), zipName.c_str()));
888+ CleanMockConditions();
889+ 
890+ close(fd);
891+ unlink(zipName.c_str());
892+}
893+ 
894+/**
895+ * @tc.name: AddBuffToZip008
896+ * @tc.desc: cover zipOpenNewFileInZip3_64, zipCloseFileInZip and zipClose fail branches
897+ * @tc.type: FUNC
898+ * @tc.require:
899+ */
900+HWTEST_F(DlpZipTest, AddBuffToZip008, TestSize.Level0)
901+{
902+ DLP_LOG_INFO(LABEL, "AddBuffToZip008");
903+ std::string buf("123");
904+ std::string nameInZip("dlp_general_info");
905+ std::string zipName("dlp_test_zip");
906+ 
907+ int32_t fd = open(zipName.c_str(), O_RDWR | O_CREAT, 0666);
908+ ASSERT_NE(fd, -1);
909+ 
910+ // zipOpenNewFileInZip3_64 fails: return DLP_ZIP_FAIL
911+ DlpCMockCondition condition;
912+ condition.mockSequence = { true };
913+ SetMockConditions("zipOpenNewFileInZip3_64", condition);
914+ ASSERT_EQ(DLP_ZIP_FAIL, AddBuffToZip(buf.c_str(), buf.size(), nameInZip.c_str(), zipName.c_str()));
915+ CleanMockConditions();
916+ 
917+ // first zipWriteInFileInZip fails: res is DLP_ZIP_FAIL
918+ condition.mockSequence = { true };
919+ SetMockConditions("zipWriteInFileInZip", condition);
920+ ASSERT_EQ(DLP_ZIP_FAIL, AddBuffToZip(buf.c_str(), buf.size(), nameInZip.c_str(), zipName.c_str()));
921+ CleanMockConditions();
922+ 
923+ // zipCloseFileInZip fails: res is DLP_ZIP_FAIL
924+ condition.mockSequence = { true };
925+ SetMockConditions("zipCloseFileInZip", condition);
926+ SetMockCallback("zipCloseFileInZip", reinterpret_cast<CommonMockFuncT>(ZipCloseFileInZipReply));
927+ ASSERT_EQ(DLP_ZIP_FAIL, AddBuffToZip(buf.c_str(), buf.size(), nameInZip.c_str(), zipName.c_str()));
928+ CleanMockConditions();
929+ 
930+ // zipClose fails: return DLP_ZIP_FAIL
931+ condition.mockSequence = { true };
932+ SetMockConditions("zipClose", condition);
933+ SetMockCallback("zipClose", reinterpret_cast<CommonMockFuncT>(ZipCloseReply));
934+ ASSERT_EQ(DLP_ZIP_FAIL, AddBuffToZip(buf.c_str(), buf.size(), nameInZip.c_str(), zipName.c_str()));
935+ CleanMockConditions();
936+ 
937+ close(fd);
938+ unlink(zipName.c_str());
939+}
940+ 
941+/**
942+ * @tc.name: AddFileContextToZip007
943+ * @tc.desc: cover open new file, write, close file and close zip fail branches
944+ * @tc.type: FUNC
945+ * @tc.require:
946+ */
947+HWTEST_F(DlpZipTest, AddFileContextToZip007, TestSize.Level0)
948+{
949+ DLP_LOG_INFO(LABEL, "AddFileContextToZip007");
950+ std::string inZip("dlp_general_info");
951+ std::string zipFile("test_zip");
952+ 
953+ int32_t fd = open(zipFile.c_str(), O_RDWR | O_CREAT, 0666);
954+ ASSERT_NE(fd, -1);
955+ int32_t fd2 = open(inZip.c_str(), O_RDWR | O_CREAT, 0666);
956+ ASSERT_NE(fd2, -1);
957+ std::string data = "123";
958+ write(fd2, data.c_str(), data.size());
959+ lseek(fd2, 0, SEEK_SET);
960+ 
961+ // zipOpenNewFileInZip3_64 fails
962+ DlpCMockCondition condition;
963+ condition.mockSequence = { true };
964+ SetMockConditions("zipOpenNewFileInZip3_64", condition);
965+ ASSERT_EQ(DLP_ZIP_FAIL, AddFileContextToZip(fd2, inZip.c_str(), zipFile.c_str()));
966+ CleanMockConditions();
967+ 
968+ // zipWriteInFileInZip fails inside the read loop
969+ lseek(fd2, 0, SEEK_SET);
970+ condition.mockSequence = { true };
971+ SetMockConditions("zipWriteInFileInZip", condition);
972+ ASSERT_EQ(DLP_ZIP_FAIL, AddFileContextToZip(fd2, inZip.c_str(), zipFile.c_str()));
973+ CleanMockConditions();
974+ 
975+ // zipCloseFileInZip fails
976+ lseek(fd2, 0, SEEK_SET);
977+ condition.mockSequence = { true };
978+ SetMockConditions("zipCloseFileInZip", condition);
979+ SetMockCallback("zipCloseFileInZip", reinterpret_cast<CommonMockFuncT>(ZipCloseFileInZipReply));
980+ ASSERT_EQ(DLP_ZIP_FAIL, AddFileContextToZip(fd2, inZip.c_str(), zipFile.c_str()));
981+ CleanMockConditions();
982+ 
983+ // zipClose fails
984+ lseek(fd2, 0, SEEK_SET);
985+ condition.mockSequence = { true };
986+ SetMockConditions("zipClose", condition);
987+ SetMockCallback("zipClose", reinterpret_cast<CommonMockFuncT>(ZipCloseReply));
988+ ASSERT_EQ(DLP_ZIP_FAIL, AddFileContextToZip(fd2, inZip.c_str(), zipFile.c_str()));
989+ CleanMockConditions();
990+ 
991+ CloseAndUnlink(fd, inZip.c_str());
992+ CloseAndUnlink(fd2, zipFile.c_str());
993+}
994+ 
995+/**
996+ * @tc.name: CheckUnzipFileInfo005
997+ * @tc.desc: cover unzGetGlobalInfo64 fail, file count mismatch and entry name mismatch branches
998+ * @tc.type: FUNC
999+ * @tc.require:
1000+ */
1001+HWTEST_F(DlpZipTest, CheckUnzipFileInfo005, TestSize.Level0)
1002+{
1003+ DLP_LOG_INFO(LABEL, "CheckUnzipFileInfo005");
1004+ 
1005+ std::string inZipInfo("dlp_general_info");
1006+ std::string zipFile("test_zip");
1007+ 
1008+ int32_t fd = open(zipFile.c_str(), O_RDWR | O_CREAT, 0666);
1009+ ASSERT_NE(fd, -1);
1010+ int32_t fd1 = open(inZipInfo.c_str(), O_RDWR | O_CREAT, 0666);
1011+ ASSERT_NE(fd1, -1);
1012+ std::string data = "123";
1013+ write(fd1, data.c_str(), data.size());
1014+ lseek(fd1, 0, SEEK_SET);
1015+ ASSERT_EQ(DLP_ZIP_OK, AddFileContextToZip(fd1, inZipInfo.c_str(), zipFile.c_str()));
1016+ ASSERT_EQ(true, IsZipFile(fd));
1017+ 
1018+ // unzGetGlobalInfo64 fails: return false
1019+ DlpCMockCondition condition;
1020+ condition.mockSequence = { true };
1021+ SetMockConditions("unzGetGlobalInfo64", condition);
1022+ ASSERT_EQ(false, CheckUnzipFileInfo(fd));
1023+ CleanMockConditions();
1024+ 
1025+ // single entry zip: number_entry != FILE_COUNT, return false
1026+ ASSERT_EQ(false, CheckUnzipFileInfo(fd));
1027+ 
1028+ CloseAndUnlink(fd, zipFile.c_str());
1029+ CloseAndUnlink(fd1, inZipInfo.c_str());
1030+}
1031+ 
1032+/**
1033+ * @tc.name: CheckUnzipFileInfo006
1034+ * @tc.desc: cover entry name not in FILE_NAME_SET branch of CheckSingleFileEntry
1035+ * @tc.type: FUNC
1036+ * @tc.require:
1037+ */
1038+HWTEST_F(DlpZipTest, CheckUnzipFileInfo006, TestSize.Level0)
1039+{
1040+ DLP_LOG_INFO(LABEL, "CheckUnzipFileInfo006");
1041+ 
1042+ // build a zip with 3 entries where the second one has an unknown name
1043+ std::string inZipInfo("dlp_general_info");
1044+ std::string inZipWrong("wrong_name");
1045+ std::string inZipData("encrypted_data");
1046+ std::string zipFile("test_zip");
1047+ 
1048+ int32_t fd = open(zipFile.c_str(), O_RDWR | O_CREAT, 0666);
1049+ ASSERT_NE(fd, -1);
1050+ int32_t fd1 = open(inZipInfo.c_str(), O_RDWR | O_CREAT, 0666);
1051+ ASSERT_NE(fd1, -1);
1052+ int32_t fd2 = open(inZipWrong.c_str(), O_RDWR | O_CREAT, 0666);
1053+ ASSERT_NE(fd2, -1);
1054+ int32_t fd3 = open(inZipData.c_str(), O_RDWR | O_CREAT, 0666);
1055+ ASSERT_NE(fd3, -1);
1056+ ASSERT_EQ(DLP_ZIP_OK, AddFileContextToZip(fd1, inZipInfo.c_str(), zipFile.c_str()));
1057+ ASSERT_EQ(DLP_ZIP_OK, AddFileContextToZip(fd2, inZipWrong.c_str(), zipFile.c_str()));
1058+ ASSERT_EQ(DLP_ZIP_OK, AddFileContextToZip(fd3, inZipData.c_str(), zipFile.c_str()));
1059+ ASSERT_EQ(true, IsZipFile(fd));
1060+ 
1061+ // the second entry name is not in FILE_NAME_SET: CheckSingleFileEntry returns false
1062+ ASSERT_EQ(false, CheckUnzipFileInfo(fd));
1063+ 
1064+ CloseAndUnlink(fd, zipFile.c_str());
1065+ CloseAndUnlink(fd1, inZipInfo.c_str());
1066+ CloseAndUnlink(fd2, inZipWrong.c_str());
1067+ CloseAndUnlink(fd3, inZipData.c_str());
1068+}
1069+ 
1070+/**
1071+ * @tc.name: CheckUnzipFileInfo007
1072+ * @tc.desc: cover compressed_size < uncompressed_size branch of CheckSingleFileEntry
1073+ * @tc.type: FUNC
1074+ * @tc.require:
1075+ */
1076+HWTEST_F(DlpZipTest, CheckUnzipFileInfo007, TestSize.Level0)
1077+{
1078+ DLP_LOG_INFO(LABEL, "CheckUnzipFileInfo007");
1079+ 
1080+ // build a zip with the 3 valid dlp entries
1081+ std::string inZipInfo("dlp_general_info");
1082+ std::string inZipCert("dlp_cert");
1083+ std::string inZipData("encrypted_data");
1084+ std::string zipFile("test_zip");
1085+ 
1086+ int32_t fd = open(zipFile.c_str(), O_RDWR | O_CREAT, 0666);
1087+ ASSERT_NE(fd, -1);
1088+ int32_t fd1 = open(inZipInfo.c_str(), O_RDWR | O_CREAT, 0666);
1089+ ASSERT_NE(fd1, -1);
1090+ int32_t fd2 = open(inZipCert.c_str(), O_RDWR | O_CREAT, 0666);
1091+ ASSERT_NE(fd2, -1);
1092+ int32_t fd3 = open(inZipData.c_str(), O_RDWR | O_CREAT, 0666);
1093+ ASSERT_NE(fd3, -1);
1094+ ASSERT_EQ(DLP_ZIP_OK, AddFileContextToZip(fd1, inZipInfo.c_str(), zipFile.c_str()));
1095+ ASSERT_EQ(DLP_ZIP_OK, AddFileContextToZip(fd2, inZipCert.c_str(), zipFile.c_str()));
1096+ ASSERT_EQ(DLP_ZIP_OK, AddFileContextToZip(fd3, inZipData.c_str(), zipFile.c_str()));
1097+ ASSERT_EQ(true, IsZipFile(fd));
1098+ 
1099+ // unzGetCurrentFileInfo64 reports compressed_size < uncompressed_size: size check fails
1100+ DlpCMockCondition condition;
1101+ condition.mockSequence = { true };
1102+ SetMockConditions("unzGetCurrentFileInfo64", condition);
1103+ SetMockCallback("unzGetCurrentFileInfo64",
1104+ reinterpret_cast<CommonMockFuncT>(UnzGetFileInfoSizeReply));
1105+ ASSERT_EQ(false, CheckUnzipFileInfo(fd));
1106+ CleanMockConditions();
1107+ 
1108+ // unzGetCurrentFileInfo64 fails directly: return false
1109+ condition.mockSequence = { true };
1110+ SetMockConditions("unzGetCurrentFileInfo64", condition);
1111+ ASSERT_EQ(false, CheckUnzipFileInfo(fd));
1112+ CleanMockConditions();
1113+ 
1114+ CloseAndUnlink(fd, zipFile.c_str());
1115+ CloseAndUnlink(fd1, inZipInfo.c_str());
1116+ CloseAndUnlink(fd2, inZipCert.c_str());
1117+ CloseAndUnlink(fd3, inZipData.c_str());
1118+}
1119+ 
1120+/**
1121+ * @tc.name: UnzipSpecificFile005
1122+ * @tc.desc: cover unzCloseCurrentFile fail and unzClose fail branches
1123+ * @tc.type: FUNC
1124+ * @tc.require:
1125+ */
1126+HWTEST_F(DlpZipTest, UnzipSpecificFile005, TestSize.Level0)
1127+{
1128+ DLP_LOG_INFO(LABEL, "UnzipSpecificFile005");
1129+ 
1130+ std::string inZipInfo("dlp_general_info");
1131+ std::string zipFile("test_zip");
1132+ std::string unZip("unzip");
1133+ 
1134+ int32_t fd = open(zipFile.c_str(), O_RDWR | O_CREAT, 0666);
1135+ ASSERT_NE(fd, -1);
1136+ int32_t fd1 = open(inZipInfo.c_str(), O_RDWR | O_CREAT, 0666);
1137+ ASSERT_NE(fd1, -1);
1138+ std::string data = "123";
1139+ write(fd1, data.c_str(), data.size());
1140+ lseek(fd1, 0, SEEK_SET);
1141+ ASSERT_EQ(DLP_ZIP_OK, AddFileContextToZip(fd1, inZipInfo.c_str(), zipFile.c_str()));
1142+ ASSERT_EQ(true, IsZipFile(fd));
1143+ 
1144+ // unzLocateFile fails: return DLP_ZIP_FAIL
1145+ DlpCMockCondition condition;
1146+ condition.mockSequence = { true };
1147+ SetMockConditions("unzLocateFile", condition);
1148+ ASSERT_EQ(DLP_ZIP_FAIL, UnzipSpecificFile(fd, inZipInfo.c_str(), unZip.c_str()));
1149+ CleanMockConditions();
1150+ 
1151+ // unzOpenCurrentFile fails: return DLP_ZIP_FAIL
1152+ condition.mockSequence = { true };
1153+ SetMockConditions("unzOpenCurrentFile", condition);
1154+ ASSERT_EQ(DLP_ZIP_FAIL, UnzipSpecificFile(fd, inZipInfo.c_str(), unZip.c_str()));
1155+ CleanMockConditions();
1156+ 
1157+ // unzReadCurrentFile fails: WriteUnzipFileContent records the error and returns DLP_ZIP_FAIL
1158+ condition.mockSequence = { true };
1159+ SetMockConditions("unzReadCurrentFile", condition);
1160+ ASSERT_EQ(DLP_ZIP_FAIL, UnzipSpecificFile(fd, inZipInfo.c_str(), unZip.c_str()));
1161+ CleanMockConditions();
1162+ 
1163+ // unzCloseCurrentFile fails: only logs, res stays DLP_ZIP_OK
1164+ condition.mockSequence = { true };
1165+ SetMockConditions("unzCloseCurrentFile", condition);
1166+ SetMockCallback("unzCloseCurrentFile",
1167+ reinterpret_cast<CommonMockFuncT>(UnzCloseCurrentFileReply));
1168+ ASSERT_EQ(DLP_ZIP_OK, UnzipSpecificFile(fd, inZipInfo.c_str(), unZip.c_str()));
1169+ CleanMockConditions();
1170+ 
1171+ // unzClose fails: return DLP_ZIP_FAIL
1172+ condition.mockSequence = { true };
1173+ SetMockConditions("unzClose", condition);
1174+ SetMockCallback("unzClose", reinterpret_cast<CommonMockFuncT>(UnzCloseReply));
1175+ ASSERT_EQ(DLP_ZIP_FAIL, UnzipSpecificFile(fd, inZipInfo.c_str(), unZip.c_str()));
1176+ CleanMockConditions();
1177+ 
1178+ CloseAndUnlink(fd, zipFile.c_str());
1179+ CloseAndUnlink(fd1, inZipInfo.c_str());
1180+ unlink(unZip.c_str());
1181+}
1182+ 
1183+/**
1184+ * @tc.name: UnzipSpecificFile006
1185+ * @tc.desc: cover OpenZipFile fail branch of UnzipSpecificFile
1186+ * @tc.type: FUNC
1187+ * @tc.require:
1188+ */
1189+HWTEST_F(DlpZipTest, UnzipSpecificFile006, TestSize.Level0)
1190+{
1191+ DLP_LOG_INFO(LABEL, "UnzipSpecificFile006");
1192+ 
1193+ std::string inZipInfo("dlp_general_info");
1194+ std::string unZip("unzip");
1195+ 
1196+ // unzOpen2 fails: OpenZipFile returns nullptr and UnzipSpecificFile fails
1197+ DlpCMockCondition condition;
1198+ condition.mockSequence = { true };
1199+ SetMockConditions("unzOpen2", condition);
1200+ ASSERT_EQ(DLP_ZIP_FAIL, UnzipSpecificFile(-1, inZipInfo.c_str(), unZip.c_str()));
1201+ CleanMockConditions();
1202+ unlink(unZip.c_str());
838}1203}
@@ -0,0 +1,86 @@
1+/*
2+ * Copyright (c) 2026 Huawei Device Co., Ltd.
3+ * Licensed under the Apache License, Version 2.0 (the "License");
4+ * you may not use this file except in compliance with the License.
5+ * You may obtain a copy of the License at
6+ *
7+ * http://www.apache.org/licenses/LICENSE-2.0
8+ *
9+ * Unless required by applicable law or agreed to in writing, software
10+ * distributed under the License is distributed on an "AS IS" BASIS,
11+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+ * See the License for the specific language governing permissions and
13+ * limitations under the License.
14+ */
15+ 
16+#include "c_mock_common.h"
17+ 
18+#include "hks_api.h"
19+#include "hks_param.h"
20+ 
21+#ifdef __cplusplus
22+extern "C" {
23+#endif
24+ 
25+/*
26+ * Failure-injection mock for the HUKS APIs used by huks_adapt_manager.cpp.
27+ * Enable a mock with SetMockConditions("HksXxx", condition); the mocked call
28+ * then returns HKS_FAILURE (no-op for void functions). When not mocked, the
29+ * call returns HKS_SUCCESS directly without touching the real HUKS service,
30+ * so the dedicated failure-injection test target does not depend on real
31+ * huks key storage. Success paths of huks_adapt_manager.cpp are covered by
32+ * huks_adapt_manager_test.cpp with the real libhukssdk.
33+ */
34+ 
35+int32_t HksInitParamSet(struct HksParamSet **)
36+{
37+ return IsFuncNeedMock("HksInitParamSet") ? HKS_FAILURE : HKS_SUCCESS;
38+}
39+ 
40+int32_t HksAddParams(struct HksParamSet *, const struct HksParam *, uint32_t)
41+{
42+ return IsFuncNeedMock("HksAddParams") ? HKS_FAILURE : HKS_SUCCESS;
43+}
44+ 
45+int32_t HksBuildParamSet(struct HksParamSet **)
46+{
47+ return IsFuncNeedMock("HksBuildParamSet") ? HKS_FAILURE : HKS_SUCCESS;
48+}
49+ 
50+void HksFreeParamSet(struct HksParamSet **)
51+{
52+ (void)IsFuncNeedMock("HksFreeParamSet");
53+}
54+ 
55+int32_t HksGenerateKey(const struct HksBlob *, const struct HksParamSet *, struct HksParamSet *)
56+{
57+ return IsFuncNeedMock("HksGenerateKey") ? HKS_FAILURE : HKS_SUCCESS;
58+}
59+ 
60+int32_t HksKeyExist(const struct HksBlob *, const struct HksParamSet *)
61+{
62+ return IsFuncNeedMock("HksKeyExist") ? HKS_FAILURE : HKS_SUCCESS;
63+}
64+ 
65+int32_t HksInit(const struct HksBlob *, const struct HksParamSet *, struct HksBlob *, struct HksBlob *)
66+{
67+ return IsFuncNeedMock("HksInit") ? HKS_FAILURE : HKS_SUCCESS;
68+}
69+ 
70+int32_t HksUpdate(const struct HksBlob *, const struct HksParamSet *, const struct HksBlob *, struct HksBlob *)
71+{
72+ return IsFuncNeedMock("HksUpdate") ? HKS_FAILURE : HKS_SUCCESS;
73+}
74+ 
75+int32_t HksFinish(const struct HksBlob *, const struct HksParamSet *, const struct HksBlob *, struct HksBlob *)
76+{
77+ return IsFuncNeedMock("HksFinish") ? HKS_FAILURE : HKS_SUCCESS;
78+}
79+ 
80+int32_t HksAbort(const struct HksBlob *, const struct HksParamSet *)
81+{
82+ return IsFuncNeedMock("HksAbort") ? HKS_FAILURE : HKS_SUCCESS;
83+}
84+#ifdef __cplusplus
85+}
86+#endif
@@ -17,6 +17,7 @@
17#include <dlfcn.h>17#include <dlfcn.h>
18#include <openssl/err.h>18#include <openssl/err.h>
19#include <openssl/evp.h>19#include <openssl/evp.h>
20+#include <openssl/hmac.h>
20#include <openssl/rand.h>21#include <openssl/rand.h>
21 22 
22#ifdef __cplusplus23#ifdef __cplusplus
@@ -410,6 +411,52 @@ int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *s)
410 }411 }
411 return (*func)(ctx, md, s);412 return (*func)(ctx, md, s);
412}413}
414+ 
415+typedef int (*HmacInitExFunc)(HMAC_CTX *ctx, const void *key, int key_len, const EVP_MD *md, ENGINE *impl);
416+typedef int (*HmacFinalFunc)(HMAC_CTX *ctx, unsigned char *md, unsigned int *len);
417+typedef int (*HmacUpdateFunc)(HMAC_CTX *ctx, const unsigned char *data, size_t len);
418+ 
419+int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int key_len, const EVP_MD *md, ENGINE *impl)
420+{
421+ if (IsFuncNeedMock("HMAC_Init_ex")) {
422+ return -1;
423+ }
424+ 
425+ HmacInitExFunc func =
426+ reinterpret_cast<HmacInitExFunc>(GetOpensslLibFunc("HMAC_Init_ex"));
427+ if (func == nullptr) {
428+ return -1;
429+ }
430+ return (*func)(ctx, key, key_len, md, impl);
431+}
432+ 
433+int HMAC_Update(HMAC_CTX *ctx, const unsigned char *data, size_t len)
434+{
435+ if (IsFuncNeedMock("HMAC_Update")) {
436+ return -1;
437+ }
438+ 
439+ HmacUpdateFunc func =
440+ reinterpret_cast<HmacUpdateFunc>(GetOpensslLibFunc("HMAC_Update"));
441+ if (func == nullptr) {
442+ return -1;
443+ }
444+ return (*func)(ctx, data, len);
445+}
446+ 
447+int HMAC_Final(HMAC_CTX *ctx, unsigned char *md, unsigned int *len)
448+{
449+ if (IsFuncNeedMock("HMAC_Final")) {
450+ return -1;
451+ }
452+ 
453+ HmacFinalFunc func =
454+ reinterpret_cast<HmacFinalFunc>(GetOpensslLibFunc("HMAC_Final"));
455+ if (func == nullptr) {
456+ return -1;
457+ }
458+ return (*func)(ctx, md, len);
459+}
413#ifdef __cplusplus460#ifdef __cplusplus
414}461}
415#endif462#endif
@@ -23,6 +23,8 @@
23#include "app_state_observer.h"23#include "app_state_observer.h"
24#include "app_uninstall_observer.h"24#include "app_uninstall_observer.h"
25#undef private25#undef private
26+#include "ohos_account_kits.h"
27+#include "os_account_manager.h"
26 28 
27using namespace testing::ext;29using namespace testing::ext;
28using namespace OHOS;30using namespace OHOS;
@@ -69,6 +71,16 @@ private:
69 std::vector<RunningProcessInfo> infoVec_;71 std::vector<RunningProcessInfo> infoVec_;
70};72};
71 73 
74+class MockAppMgrProxyFail final : public AppExecFwk::AppMgrProxy {
75+public:
76+ MockAppMgrProxyFail() : AppExecFwk::AppMgrProxy(nullptr) {}
77+ 
78+ int32_t GetAllRunningProcesses(std::vector<RunningProcessInfo>& infoVec) override
79+ {
80+ return 1; // not ERR_OK
81+ }
82+};
83+ 
72static RunningProcessInfo MakeRunningProcessInfo(int32_t uid, const std::string& processName,84static RunningProcessInfo MakeRunningProcessInfo(int32_t uid, const std::string& processName,
73 AppExecFwk::AppProcessState state, int32_t pid)85 AppExecFwk::AppProcessState state, int32_t pid)
74{86{
@@ -131,6 +143,56 @@ static DlpSandboxInfo MakeEnterpriseSandboxInfo(const EnterpriseSandboxSpec& spe
131 };143 };
132}144}
133 145 
146+/*
147+ * Link-time interposition stubs for the account APIs used by app_state_observer.cpp,
148+ * with the same technique as the OsAccountManager::GetOsAccountLocalIdFromUid stub
149+ * defined in dlp_permission_service_test.cpp (the definition in the test binary
150+ * preempts the shared library one). Defaults keep the on-device behavior so
151+ * existing tests are unaffected; DecMaskInfoCnt002 flips the flag temporarily.
152+ * Note: only static member functions can be interposed this way. Virtual ones
153+ * (e.g. OhosAccountKits::QueryOhosAccountInfo) are dispatched through the vtable
154+ * of the SDK-internal derived object and cannot be preempted, so they must not
155+ * be stubbed here.
156+ */
157+namespace OHOS {
158+namespace AccountSA {
159+bool g_foregroundAccountQueryOk = true; // real query succeeds on device; ext-branch tests flip it
160+static const int32_t FOREGROUND_OS_ACCOUNT_ID = 100; // same as on device
161+ 
162+int OsAccountManager::GetForegroundOsAccountLocalId(int32_t &localId)
163+{
164+ localId = FOREGROUND_OS_ACCOUNT_ID;
165+ return g_foregroundAccountQueryOk ? 0 : 1;
166+}
167+} // namespace AccountSA
168+} // namespace OHOS
169+ 
170+/*
171+ * Link-time interposition stubs for the common event APIs used by
172+ * app_uninstall_observer.cpp, with the same technique as the account stubs
173+ * above (the definition in the test binary preempts the shared library one).
174+ * The default keeps the on-device behavior (subscription succeeds), so
175+ * existing tests are unaffected; the DlpEventSubSubscriber case flips the
176+ * flag temporarily to cover the failure branch.
177+ */
178+namespace OHOS {
179+namespace EventFwk {
180+static bool g_subscribeCommonEventRet = true; // real subscription succeeds on device
181+ 
182+bool CommonEventManager::SubscribeCommonEvent(const std::shared_ptr<CommonEventSubscriber>& subscriber)
183+{
184+ (void)subscriber;
185+ return g_subscribeCommonEventRet;
186+}
187+ 
188+bool CommonEventManager::UnSubscribeCommonEvent(const std::shared_ptr<CommonEventSubscriber>& subscriber)
189+{
190+ (void)subscriber;
191+ return true;
192+}
193+} // namespace EventFwk
194+} // namespace OHOS
195+ 
134void AppStateObserverTest::SetUpTestCase() {}196void AppStateObserverTest::SetUpTestCase() {}
135 197 
136void AppStateObserverTest::TearDownTestCase() {}198void AppStateObserverTest::TearDownTestCase() {}
@@ -2102,4 +2164,369 @@ HWTEST_F(AppStateObserverTest, GetEnterpriseFileIdsByUid005, TestSize.Level1)
2102 ASSERT_EQ(fileIds, "f2");2164 ASSERT_EQ(fileIds, "f2");
2103 2165 
2104 ASSERT_FALSE(observer.GetEnterpriseFileIdsByUid(999, fileIds));2166 ASSERT_FALSE(observer.GetEnterpriseFileIdsByUid(999, fileIds));
2167+}
2168+ 
2169+/**
2170+ * @tc.name: UninstallDlpSandboxTest003
2171+ * @tc.desc: cover hipreview bind sandbox uninstall branch
2172+ * @tc.type: FUNC
2173+ * @tc.require:
2174+ */
2175+HWTEST_F(AppStateObserverTest, UninstallDlpSandboxTest003, TestSize.Level1)
2176+{
2177+ DLP_LOG_INFO(LABEL, "UninstallDlpSandboxTest003");
2178+ 
2179+ AppStateObserver observer;
2180+ DlpSandboxInfo appInfo = {
2181+ .uid = 1,
2182+ .userId = 123,
2183+ .appIndex = 2,
2184+ .bindAppIndex = 1001,
2185+ .tokenId = 100,
2186+ .bundleName = HIPREVIEW_HIGH
2187+ };
2188+ // appIndex > 0, bindAppIndex > HIPREVIEW_SANDBOX_LOW_BOUND and bundleName is HIPREVIEW_HIGH
2189+ observer.UninstallDlpSandbox(appInfo);
2190+ ASSERT_EQ(appInfo.tokenId, 100);
2191+}
2192+ 
2193+/**
2194+ * @tc.name: UninstallAllDlpSandboxForUser001
2195+ * @tc.desc: cover matching and mismatching userId branches of UninstallAllDlpSandboxForUser
2196+ * @tc.type: FUNC
2197+ * @tc.require:
2198+ */
2199+HWTEST_F(AppStateObserverTest, UninstallAllDlpSandboxForUser001, TestSize.Level1)
2200+{
2201+ DLP_LOG_INFO(LABEL, "UninstallAllDlpSandboxForUser001");
2202+ 
2203+ AppStateObserver observer;
2204+ DlpSandboxInfo matchInfo = {
2205+ .uid = 1,
2206+ .userId = 123,
2207+ .appIndex = 2,
2208+ .tokenId = 100,
2209+ .bundleName = "testbundle1"
2210+ };
2211+ observer.AddSandboxInfo(matchInfo);
2212+ DlpSandboxInfo mismatchInfo = {
2213+ .uid = 2,
2214+ .userId = 456,
2215+ .appIndex = 2,
2216+ .tokenId = 101,
2217+ .bundleName = "testbundle2"
2218+ };
2219+ observer.AddSandboxInfo(mismatchInfo);
2220+ 
2221+ // entry with the same userId is erased with callback, entry with another userId is kept
2222+ observer.UninstallAllDlpSandboxForUser(123);
2223+ ASSERT_EQ(observer.sandboxInfo_.size(), 1);
2224+ ASSERT_TRUE(observer.sandboxInfo_.count(2) > 0);
2225+}
2226+ 
2227+/**
2228+ * @tc.name: AddDlpSandboxInfo002
2229+ * @tc.desc: cover GetUserIdFromUid failed branch of AddDlpSandboxInfo
2230+ * @tc.type: FUNC
2231+ * @tc.require:
2232+ */
2233+HWTEST_F(AppStateObserverTest, AddDlpSandboxInfo002, TestSize.Level1)
2234+{
2235+ DLP_LOG_INFO(LABEL, "AddDlpSandboxInfo002");
2236+ 
2237+ AppStateObserver observer;
2238+ DlpSandboxInfo appInfo = {
2239+ .uid = INCORRECT_UID,
2240+ .userId = 100,
2241+ .appIndex = 2,
2242+ .tokenId = 100,
2243+ .bundleName = "testbundle1"
2244+ };
2245+ // GetUserIdFromUid fails for INCORRECT_UID (stubbed in dlp_permission_service_test.cpp)
2246+ observer.AddDlpSandboxInfo(appInfo);
2247+ ASSERT_TRUE(observer.sandboxInfo_.empty());
2248+ ASSERT_TRUE(observer.userIdList_.empty());
2249+}
2250+ 
2251+/**
2252+ * @tc.name: DecMaskInfoCnt002
2253+ * @tc.desc: cover GetUserIdByForegroundAccount failed branch of DecMaskInfoCnt
2254+ * @tc.type: FUNC
2255+ * @tc.require:
2256+ */
2257+HWTEST_F(AppStateObserverTest, DecMaskInfoCnt002, TestSize.Level1)
2258+{
2259+ DLP_LOG_INFO(LABEL, "DecMaskInfoCnt002");
2260+ 
2261+ AppStateObserver observer;
2262+ DlpSandboxInfo appInfo;
2263+ appInfo.isWatermark = true;
2264+ 
2265+ // GetUserIdByForegroundAccount fails (interposition stub)
2266+ OHOS::AccountSA::g_foregroundAccountQueryOk = false;
2267+ observer.DecMaskInfoCnt(appInfo);
2268+ OHOS::AccountSA::g_foregroundAccountQueryOk = true;
2269+ ASSERT_TRUE(observer.maskInfoMap_.empty());
2270+}
2271+ 
2272+/**
2273+ * @tc.name: GetRunningProcessesInfo002
2274+ * @tc.desc: cover GetAllRunningProcesses failed branch of GetRunningProcessesInfo
2275+ * @tc.type: FUNC
2276+ * @tc.require:
2277+ */
2278+HWTEST_F(AppStateObserverTest, GetRunningProcessesInfo002, TestSize.Level1)
2279+{
2280+ DLP_LOG_INFO(LABEL, "GetRunningProcessesInfo002");
2281+ 
2282+ AppStateObserver observer;
2283+ std::vector<RunningProcessInfo> infoVec;
2284+ observer.SetAppProxy(new (std::nothrow) MockAppMgrProxyFail());
2285+ 
2286+ // GetAllRunningProcesses returns error
2287+ ASSERT_FALSE(observer.GetRunningProcessesInfo(infoVec));
2288+ ASSERT_TRUE(infoVec.empty());
2289+}
2290+ 
2291+/**
2292+ * @tc.name: GetOpeningSandboxInfo003
2293+ * @tc.desc: cover uri/fileId mismatch and full match branches of GetOpeningSandboxInfo
2294+ * @tc.type: FUNC
2295+ * @tc.require:
2296+ */
2297+HWTEST_F(AppStateObserverTest, GetOpeningSandboxInfo003, TestSize.Level1)
2298+{
2299+ DLP_LOG_INFO(LABEL, "GetOpeningSandboxInfo003");
2300+ 
2301+ AppStateObserver observer;
2302+ SandboxInfo sandboxInfo;
2303+ std::string bundleName = "testbundle1";
2304+ int32_t userId = 100;
2305+ std::string uri = "uriB";
2306+ std::string fileId = "f2";
2307+ 
2308+ // userId and bundleName match but uri differs: continue
2309+ DlpSandboxInfo uriMismatch = {
2310+ .uid = 1,
2311+ .userId = 100,
2312+ .appIndex = 2,
2313+ .tokenId = 11,
2314+ .bundleName = "testbundle1",
2315+ .uri = "uriA",
2316+ .fileId = "f2"
2317+ };
2318+ observer.AddSandboxInfo(uriMismatch);
2319+ 
2320+ // uri matches but fileId differs: continue
2321+ DlpSandboxInfo fileIdMismatch = {
2322+ .uid = 2,
2323+ .userId = 100,
2324+ .appIndex = 3,
2325+ .tokenId = 22,
2326+ .bundleName = "testbundle1",
2327+ .uri = "uriB",
2328+ .fileId = "wrong"
2329+ };
2330+ observer.AddSandboxInfo(fileIdMismatch);
2331+ 
2332+ // all fields match: FillSandboxInfoIfProcessRunning is called
2333+ DlpSandboxInfo fullMatch = {
2334+ .uid = 3,
2335+ .userId = 100,
2336+ .appIndex = 4,
2337+ .bindAppIndex = 5,
2338+ .tokenId = 33,
2339+ .bundleName = "testbundle1",
2340+ .uri = "uriB",
2341+ .fileId = "f2"
2342+ };
2343+ observer.AddSandboxInfo(fullMatch);
2344+ 
2345+ SetMockAppProxy(observer, {
2346+ MakeRunningProcessInfo(3, "testbundle1", AppExecFwk::AppProcessState::APP_STATE_FOREGROUND, 300),
2347+ });
2348+ ASSERT_TRUE(observer.GetOpeningSandboxInfo(bundleName, uri, userId, sandboxInfo, fileId));
2349+ ASSERT_EQ(sandboxInfo.appIndex, 4);
2350+ ASSERT_EQ(sandboxInfo.bindAppIndex, 5);
2351+ ASSERT_EQ(sandboxInfo.tokenId, 33);
2352+}
2353+ 
2354+/**
2355+ * @tc.name: CanUninstallByGid001
2356+ * @tc.desc: cover all branches of CanUninstallByGid
2357+ * @tc.type: FUNC
2358+ * @tc.require:
2359+ */
2360+HWTEST_F(AppStateObserverTest, CanUninstallByGid001, TestSize.Level1)
2361+{
2362+ DLP_LOG_INFO(LABEL, "CanUninstallByGid001");
2363+ 
2364+ AppStateObserver observer;
2365+ DlpSandboxInfo appInfo;
2366+ appInfo.uid = 100;
2367+ appInfo.bundleName = "testbundle1";
2368+ OHOS::AppExecFwk::ProcessData processData;
2369+ processData.pid = 500;
2370+ 
2371+ // uid mismatch or empty bundleNames: continue
2372+ RunningProcessInfo uidMismatch = MakeRunningProcessInfo(
2373+ 999, "other", AppExecFwk::AppProcessState::APP_STATE_FOREGROUND, 501);
2374+ RunningProcessInfo noBundle = MakeRunningProcessInfo(
2375+ 100, "other2", AppExecFwk::AppProcessState::APP_STATE_FOREGROUND, 502);
2376+ noBundle.bundleNames.clear();
2377+ SetMockAppProxy(observer, {uidMismatch, noBundle});
2378+ ASSERT_TRUE(observer.CanUninstallByGid(appInfo, processData));
2379+ 
2380+ // dead process with the same pid: log only, can uninstall
2381+ SetMockAppProxy(observer, {
2382+ MakeRunningProcessInfo(100, "testbundle1", AppExecFwk::AppProcessState::APP_STATE_END, 500),
2383+ });
2384+ ASSERT_TRUE(observer.CanUninstallByGid(appInfo, processData));
2385+ 
2386+ // dead process with a different pid: can not uninstall
2387+ SetMockAppProxy(observer, {
2388+ MakeRunningProcessInfo(100, "testbundle1", AppExecFwk::AppProcessState::APP_STATE_TERMINATED, 779),
2389+ });
2390+ ASSERT_FALSE(observer.CanUninstallByGid(appInfo, processData));
2391+ 
2392+ // running process with a different pid: can not uninstall
2393+ SetMockAppProxy(observer, {
2394+ MakeRunningProcessInfo(100, "testbundle1", AppExecFwk::AppProcessState::APP_STATE_FOREGROUND, 777),
2395+ });
2396+ ASSERT_FALSE(observer.CanUninstallByGid(appInfo, processData));
2397+ 
2398+ // running process whose name contains "svr": can uninstall
2399+ RunningProcessInfo svrInfo = MakeRunningProcessInfo(
2400+ 100, "testbundle1", AppExecFwk::AppProcessState::APP_STATE_FOREGROUND, 778);
2401+ svrInfo.processName_ = "svr_testbundle1";
2402+ SetMockAppProxy(observer, {svrInfo});
2403+ ASSERT_TRUE(observer.CanUninstallByGid(appInfo, processData));
2404+}
2405+ 
2406+/**
2407+ * @tc.name: OnProcessDied005
2408+ * @tc.desc: cover CanUninstallByGid false branch of OnProcessDied
2409+ * @tc.type: FUNC
2410+ * @tc.require:
2411+ */
2412+HWTEST_F(AppStateObserverTest, OnProcessDied005, TestSize.Level1)
2413+{
2414+ DLP_LOG_INFO(LABEL, "OnProcessDied005");
2415+ 
2416+ AppStateObserver observer;
2417+ DlpSandboxInfo appInfo = {
2418+ .uid = 600,
2419+ .userId = 100,
2420+ .appIndex = 2,
2421+ .tokenId = 600,
2422+ .bundleName = "testbundle1"
2423+ };
2424+ observer.AddSandboxInfo(appInfo);
2425+ 
2426+ // sandbox process is still running with a different pid: can not uninstall
2427+ SetMockAppProxy(observer, {
2428+ MakeRunningProcessInfo(600, "testbundle1", AppExecFwk::AppProcessState::APP_STATE_FOREGROUND, 777),
2429+ });
2430+ 
2431+ OHOS::AppExecFwk::ProcessData processData;
2432+ processData.bundleName = "testbundle1";
2433+ processData.processName = "testbundle1";
2434+ processData.uid = 600;
2435+ processData.pid = 888;
2436+ processData.renderUid = -1;
2437+ 
2438+ observer.OnProcessDied(processData);
2439+ ASSERT_EQ(observer.sandboxInfo_.size(), 1);
2440+ ASSERT_TRUE(observer.sandboxInfo_.count(600) > 0);
2441+}
2442+ 
2443+/**
2444+ * @tc.name: GetSandboxInfoByTokenId001
2445+ * @tc.desc: cover sandbox info found branch of GetSandboxInfoByTokenId
2446+ * @tc.type: FUNC
2447+ * @tc.require:
2448+ */
2449+HWTEST_F(AppStateObserverTest, GetSandboxInfoByTokenId001, TestSize.Level1)
2450+{
2451+ DLP_LOG_INFO(LABEL, "GetSandboxInfoByTokenId001");
2452+ 
2453+ AppStateObserver observer;
2454+ observer.AddUidWithTokenId(700, 700);
2455+ DlpSandboxInfo appInfo = {
2456+ .uid = 700,
2457+ .userId = 100,
2458+ .appIndex = 2,
2459+ .tokenId = 700,
2460+ .bundleName = "testbundle1"
2461+ };
2462+ observer.AddSandboxInfo(appInfo);
2463+ 
2464+ // tokenId maps to uid and the sandbox info exists
2465+ DlpSandboxInfo result;
2466+ ASSERT_TRUE(observer.GetSandboxInfoByTokenId(700, result));
2467+ ASSERT_EQ(result.uid, 700);
2468+ ASSERT_EQ(result.bundleName, "testbundle1");
2469+}
2470+ 
2471+/**
2472+ * @tc.name: AppUninstallObserver001
2473+ * @tc.desc: cover HasRetentionSandboxInfo true branch of AppUninstallObserver OnReceiveEvent
2474+ * @tc.type: FUNC
2475+ * @tc.require:
2476+ */
2477+HWTEST_F(AppStateObserverTest, AppUninstallObserver001, TestSize.Level1)
2478+{
2479+ DLP_LOG_INFO(LABEL, "AppUninstallObserver001");
2480+ 
2481+ EventFwk::MatchingSkills matchingSkills;
2482+ matchingSkills.AddEvent(EventFwk::CommonEventSupport::COMMON_EVENT_PACKAGE_REMOVED);
2483+ EventFwk::CommonEventSubscribeInfo subscribeInfo(matchingSkills);
2484+ std::shared_ptr<AppUninstallObserver> observer = std::make_shared<AppUninstallObserver>(subscribeInfo);
2485+ 
2486+ // add retention info into the RetentionFileManager singleton (GetUserIdByForegroundAccount returns 100)
2487+ RetentionInfo retentionInfo = {
2488+ .appIndex = 1,
2489+ .tokenId = 827819,
2490+ .bundleName = "testbundle_uninstall",
2491+ .dlpFileAccess = DLPFileAccess::CONTENT_EDIT,
2492+ .userId = DEFAULT_USERID
2493+ };
2494+ ASSERT_EQ(DLP_OK, RetentionFileManager::GetInstance().AddSandboxInfo(retentionInfo));
2495+ ASSERT_TRUE(RetentionFileManager::GetInstance().HasRetentionSandboxInfo("testbundle_uninstall"));
2496+ 
2497+ // action matches and HasRetentionSandboxInfo returns true: RemoveRetentionState is called
2498+ EventFwk::CommonEventData data;
2499+ OHOS::AAFwk::Want want;
2500+ want.SetBundle("testbundle_uninstall");
2501+ want.SetAction(EventFwk::CommonEventSupport::COMMON_EVENT_PACKAGE_REMOVED);
2502+ data.SetWant(want);
2503+ observer->OnReceiveEvent(data);
2504+ 
2505+ // retention state of the uninstalled bundle has been removed
2506+ ASSERT_FALSE(RetentionFileManager::GetInstance().HasRetentionSandboxInfo("testbundle_uninstall"));
2507+}
2508+ 
2509+/**
2510+ * @tc.name: DlpEventSubSubscriber001
2511+ * @tc.desc: cover subscribe failed and destructor unsubscribe branches of DlpEventSubSubscriber
2512+ * @tc.type: FUNC
2513+ * @tc.require:
2514+ */
2515+HWTEST_F(AppStateObserverTest, DlpEventSubSubscriber001, TestSize.Level1)
2516+{
2517+ DLP_LOG_INFO(LABEL, "DlpEventSubSubscriber001");
2518+ 
2519+ // SubscribeCommonEvent fails: subscriber_ is reset to nullptr
2520+ OHOS::EventFwk::g_subscribeCommonEventRet = false;
2521+ {
2522+ DlpEventSubSubscriber subscriber;
2523+ ASSERT_TRUE(subscriber.subscriber_ == nullptr);
2524+ }
2525+ OHOS::EventFwk::g_subscribeCommonEventRet = true;
2526+ 
2527+ // SubscribeCommonEvent succeeds: subscriber_ is kept
2528+ {
2529+ DlpEventSubSubscriber subscriber;
2530+ ASSERT_TRUE(subscriber.subscriber_ != nullptr);
2531+ } // destructor calls UnSubscribeCommonEvent since subscriber_ is not nullptr
2105}2532}
@@ -0,0 +1,146 @@
1+/*
2+ * Copyright (c) 2026 Huawei Device Co., Ltd.
3+ * Licensed under the Apache License, Version 2.0 (the "License");
4+ * you may not use this file except in compliance with the License.
5+ * You may obtain a copy of the License at
6+ *
7+ * http://www.apache.org/licenses/LICENSE-2.0
8+ *
9+ * Unless required by applicable law or agreed to in writing, software
10+ * distributed under the License is distributed on an "AS IS" BASIS,
11+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+ * See the License for the specific language governing permissions and
13+ * limitations under the License.
14+ */
15+ 
16+#include "dlp_permission_service_ext_branch_test.h"
17+ 
18+#include <cstdio>
19+#include <string>
20+ 
21+#include "dlp_feature_info.h"
22+#include "dlp_permission.h"
23+#include "dlp_permission_log.h"
24+#include "file_operator.h"
25+ 
26+using namespace testing::ext;
27+using namespace OHOS;
28+using namespace OHOS::Security::DlpPermission;
29+using namespace std;
30+ 
31+/*
32+ * Helper defined in test/unittest/sa/mock/dlp_os_account_mock.cpp, which is compiled into
33+ * this target together with the mock os_account headers (test/unittest/sa/mock precedes the
34+ * SDK include paths), so the foreground account query and the domain info of OsAccountInfo
35+ * are fully controlled by the mock.
36+ */
37+namespace OHOS {
38+namespace Security {
39+namespace DlpPermissionUnitTest {
40+void SetForegroundOsAccountLocalIdRet(int32_t ret);
41+} // namespace DlpPermissionUnitTest
42+} // namespace Security
43+} // namespace OHOS
44+ 
45+namespace {
46+static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {
47+ LOG_CORE, SECURITY_DOMAIN_DLP_PERMISSION, "DlpPermissionServiceExtBranchTest"};
48+static constexpr int32_t SA_ID_DLP_PERMISSION_SERVICE = 3521;
49+static const int32_t FOREGROUND_QUERY_OK = 0;
50+static const int32_t FOREGROUND_QUERY_FAIL = 1;
51+static const uint32_t FEATURE_ENABLED = 1;
52+static const uint32_t FEATURE_DISABLED = 0;
53+static const std::string MDM_BUNDLE_NAME_KEY = "appId"; // aligned with dlp_permission_service_common.h
54+static const std::string MDM_ENABLE_VALUE_KEY = "status"; // aligned with dlp_permission_service_common.h
55+static const char* FEATURE_INFO_DATA_FILE_PATH =
56+ "/data/service/el1/public/dlp_permission_service/dlp_feature_info.txt";
57+static const std::string INVALID_FILE_CONTENT = "not_a_hmac_protected_file";
58+}
59+ 
60+void DlpPermissionServiceExtBranchTest::SetUpTestCase() {}
61+ 
62+void DlpPermissionServiceExtBranchTest::TearDownTestCase() {}
63+ 
64+void DlpPermissionServiceExtBranchTest::SetUp()
65+{
66+ if (service_ != nullptr) {
67+ return;
68+ }
69+ service_ = std::make_shared<DlpPermissionService>(SA_ID_DLP_PERMISSION_SERVICE, true);
70+ ASSERT_NE(nullptr, service_);
71+ service_->appStateObserver_ = new (std::nothrow) AppStateObserver();
72+ ASSERT_TRUE(service_->appStateObserver_ != nullptr);
73+}
74+ 
75+void DlpPermissionServiceExtBranchTest::TearDown()
76+{
77+ if (service_ != nullptr) {
78+ service_->appStateObserver_ = nullptr;
79+ }
80+ service_ = nullptr;
81+}
82+ 
83+/**
84+ * @tc.name: CheckIfEnterpriseAccount001
85+ * @tc.desc: cover GetForegroundOsAccountLocalId failed and enterprise account branches of
86+ * CheckIfEnterpriseAccount
87+ * @tc.type: FUNC
88+ * @tc.require:
89+ */
90+HWTEST_F(DlpPermissionServiceExtBranchTest, CheckIfEnterpriseAccount001, TestSize.Level1)
91+{
92+ DLP_LOG_INFO(LABEL, "CheckIfEnterpriseAccount001");
93+ // mock domain info is non-empty: foreground account is an enterprise account
94+ int32_t ret = service_->CheckIfEnterpriseAccount();
95+ ASSERT_EQ(DLP_OK, ret);
96+ 
97+ // GetForegroundOsAccountLocalId fails (mock): return DLP_PARSE_ERROR_ACCOUNT_INVALID
98+ SetForegroundOsAccountLocalIdRet(FOREGROUND_QUERY_FAIL);
99+ ret = service_->CheckIfEnterpriseAccount();
100+ SetForegroundOsAccountLocalIdRet(FOREGROUND_QUERY_OK);
101+ ASSERT_EQ(DLP_PARSE_ERROR_ACCOUNT_INVALID, ret);
102+}
103+ 
104+/**
105+ * @tc.name: IsDlpFeatureProvidedByEnterprise001
106+ * @tc.desc: cover feature info file branches of IsDLPFeatureProvided for an enterprise account
107+ * @tc.type: FUNC
108+ * @tc.require:
109+ */
110+HWTEST_F(DlpPermissionServiceExtBranchTest, IsDlpFeatureProvidedByEnterprise001, TestSize.Level1)
111+{
112+ DLP_LOG_INFO(LABEL, "IsDlpFeatureProvidedByEnterprise001");
113+ bool isProvideDLPFeature = false;
114+ 
115+ // feature info file does not exist: fall back to the system parameter (not "true")
116+ remove(FEATURE_INFO_DATA_FILE_PATH);
117+ int32_t ret = service_->IsDLPFeatureProvided(isProvideDLPFeature);
118+ ASSERT_EQ(DLP_OK, ret);
119+ ASSERT_FALSE(isProvideDLPFeature);
120+ 
121+ // valid file with the feature enabled: dlpFeature == ENABLE_VALUE_TRUE
122+ unordered_json featureJson;
123+ featureJson[MDM_BUNDLE_NAME_KEY] = "app_stub";
124+ featureJson[MDM_ENABLE_VALUE_KEY] = FEATURE_ENABLED;
125+ ASSERT_EQ(DLP_OK, DlpFeatureInfo::SaveDlpFeatureInfoToFile(featureJson));
126+ ret = service_->IsDLPFeatureProvided(isProvideDLPFeature);
127+ ASSERT_EQ(DLP_OK, ret);
128+ ASSERT_TRUE(isProvideDLPFeature);
129+ 
130+ // valid file with the feature disabled: dlpFeature != ENABLE_VALUE_TRUE
131+ featureJson[MDM_ENABLE_VALUE_KEY] = FEATURE_DISABLED;
132+ ASSERT_EQ(DLP_OK, DlpFeatureInfo::SaveDlpFeatureInfoToFile(featureJson));
133+ ret = service_->IsDLPFeatureProvided(isProvideDLPFeature);
134+ ASSERT_EQ(DLP_OK, ret);
135+ ASSERT_FALSE(isProvideDLPFeature);
136+ 
137+ // file exists but is not a valid hmac-protected file: GetDlpFeatureInfoFromFile fails
138+ FileOperator fileOperator;
139+ ASSERT_EQ(DLP_OK, fileOperator.InputFileByPathAndContent(FEATURE_INFO_DATA_FILE_PATH, INVALID_FILE_CONTENT));
140+ ret = service_->IsDLPFeatureProvided(isProvideDLPFeature);
141+ ASSERT_EQ(DLP_OK, ret);
142+ ASSERT_FALSE(isProvideDLPFeature);
143+ 
144+ // cleanup: keep the feature info file absent as before the case
145+ remove(FEATURE_INFO_DATA_FILE_PATH);
146+}
@@ -0,0 +1,41 @@
1+/*
2+ * Copyright (c) 2026 Huawei Device Co., Ltd.
3+ * Licensed under the Apache License, Version 2.0 (the "License");
4+ * you may not use this file except in compliance with the License.
5+ * You may obtain a copy of the License at
6+ *
7+ * http://www.apache.org/licenses/LICENSE-2.0
8+ *
9+ * Unless required by applicable law or agreed to in writing, software
10+ * distributed under the License is distributed on an "AS IS" BASIS,
11+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+ * See the License for the specific language governing permissions and
13+ * limitations under the License.
14+ */
15+ 
16+#ifndef DLP_PERMISSION_SERVICE_EXT_BRANCH_TEST_H
17+#define DLP_PERMISSION_SERVICE_EXT_BRANCH_TEST_H
18+ 
19+#include <gtest/gtest.h>
20+#include <memory>
21+#include <string>
22+#define private public
23+#include "dlp_permission_service.h"
24+#undef private
25+ 
26+namespace OHOS {
27+namespace Security {
28+namespace DlpPermission {
29+class DlpPermissionServiceExtBranchTest : public testing::Test {
30+public:
31+ static void SetUpTestCase();
32+ static void TearDownTestCase();
33+ void SetUp();
34+ void TearDown();
35+ 
36+ std::shared_ptr<DlpPermissionService> service_ = nullptr;
37+};
38+} // namespace DlpPermission
39+} // namespace Security
40+} // namespace OHOS
41+#endif // DLP_PERMISSION_SERVICE_EXT_BRANCH_TEST_H