diff --git a/interfaces/kits/js/src/mod_fs/class_atomicfile/ani/atomicfile_ani.cpp b/interfaces/kits/js/src/mod_fs/class_atomicfile/ani/atomicfile_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..07b6eef169ecf1b47f5540f13bf036fbd8c7dc0d --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_atomicfile/ani/atomicfile_ani.cpp @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "atomicfile_ani.h" + +#include + +#include "ani_signature.h" +#include "error_handler.h" +#include "file_wrapper.h" +#include "filemgmt_libhilog.h" +#include "fs_atomicfile.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +namespace fs = filesystem; +using namespace std; +using namespace OHOS::FileManagement::ModuleFileIO; +using namespace OHOS::FileManagement::ModuleFileIO::ANI::AniSignature; + +const string READ_STREAM_CLASS = "ReadStream"; +const string WRITE_STREAM_CLASS = "WriteStream"; +const string TEMP_FILE_SUFFIX = "_XXXXXX"; + +void AtomicFileAni::Constructor(ani_env *env, ani_object obj, ani_string pathObj) +{ + auto [succ, filePath] = TypeConverter::ToUTF8String(env, pathObj); + if (!succ) { + HILOGE("Invalid path"); + ErrorHandler::Throw(env, E_PARAMS); + return; + } + + auto ret = FsAtomicFile::Constructor(filePath); + if (!ret.IsSuccess()) { + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return; + } + + if (ANI_OK != + env->Object_SetFieldByName_Long(obj, "nativePtr", + static_cast(reinterpret_cast(ret.GetData().value())))) { + HILOGE("Failed to wrap entity for obj AtomicFile"); + ErrorHandler::Throw(env, EIO); + return; + } +} + +static FsAtomicFile *Unwrap(ani_env *env, ani_object object) +{ + ani_long file; + auto ret = env->Object_GetFieldByName_Long(object, "nativePtr", &file); + if (ret != ANI_OK) { + HILOGE("Unwrap file err: %{private}d", ret); + return nullptr; + } + + return reinterpret_cast(file); +} + +ani_string AtomicFileAni::GetPath(ani_env *env, [[maybe_unused]] ani_object object) +{ + auto file = Unwrap(env, object); + if (file == nullptr) { + ErrorHandler::Throw(env, E_PARAMS); + return nullptr; + } + + string path = file->GetPath(); + auto [succ, result] = TypeConverter::ToAniString(env, path); + if (!succ) { + HILOGE("ToAniString failed"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return nullptr; + } + + return result; +} + +ani_object AtomicFileAni::GetBaseFile(ani_env *env, [[maybe_unused]] ani_object object) +{ + auto atomicFile = Unwrap(env, object); + if (atomicFile == nullptr) { + HILOGE("Failed to get atomicFile"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return nullptr; + } + + auto ret = atomicFile->GetBaseFile(); + if (!ret.IsSuccess()) { + HILOGE("Failed to GetBaseFile"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return nullptr; + } + + const FsFile *fsFile = ret.GetData().value(); + auto result = FileWrapper::Wrap(env, move(fsFile)); + if (result == nullptr) { + HILOGE("Failed to wrap"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return nullptr; + } + + return result; +} + +static ani_object CreateReadStream(ani_env *env, ani_string filePath) +{ + auto classDesc = FS::ReadStream::classDesc.c_str(); + ani_class cls; + if (ANI_OK != env->FindClass(classDesc, &cls)) { + HILOGE("Cannot find class %s", classDesc); + return nullptr; + } + + auto ctorDesc = FS::ReadStream::ctorDesc.c_str(); + auto ctorSig = FS::ReadStream::ctorSig.c_str(); + ani_method ctor; + if (ANI_OK != env->Class_FindMethod(cls, ctorDesc, ctorSig, &ctor)) { + HILOGE("Cannot find constructor method for class %s", classDesc); + return nullptr; + } + + ani_object obj; + if (ANI_OK != env->Object_New(cls, ctor, &obj, filePath)) { + HILOGE("New %s obj Failed", classDesc); + return nullptr; + } + + return move(obj); +} + +static ani_object CreateWriteStream(ani_env *env, ani_string filePath) +{ + auto classDesc = FS::WriteStream::classDesc.c_str(); + ani_class cls; + if (ANI_OK != env->FindClass(classDesc, &cls)) { + HILOGE("Cannot find class %s", classDesc); + return nullptr; + } + + auto ctorDesc = FS::WriteStream::ctorDesc.c_str(); + auto ctorSig = FS::WriteStream::ctorSig.c_str(); + ani_method ctor; + if (ANI_OK != env->Class_FindMethod(cls, ctorDesc, ctorSig, &ctor)) { + HILOGE("Cannot find constructor method for class %s", classDesc); + return nullptr; + } + + ani_object obj; + if (ANI_OK != env->Object_New(cls, ctor, &obj, filePath)) { + HILOGE("New %s obj Failed", classDesc); + return nullptr; + } + + return move(obj); +} + +static ani_object CreateStream( + ani_env *env, [[maybe_unused]] ani_object object, const string &streamName, const string &fileName) +{ + auto [succ, filePath] = TypeConverter::ToAniString(env, fileName); + if (!succ) { + HILOGE("Failed to ani_string"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return nullptr; + } + + if (streamName == READ_STREAM_CLASS) { + auto stream = CreateReadStream(env, filePath); + if (stream == nullptr) { + HILOGE("Failed to create read stream"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return nullptr; + } + return move(stream); + } + if (streamName == WRITE_STREAM_CLASS) { + auto stream = CreateWriteStream(env, filePath); + if (stream == nullptr) { + HILOGE("Failed to create write stream"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return nullptr; + } + return move(stream); + } + + ErrorHandler::Throw(env, UNKNOWN_ERR); + return nullptr; +} + +ani_object AtomicFileAni::OpenRead(ani_env *env, [[maybe_unused]] ani_object object) +{ + auto atomicFile = Unwrap(env, object); + if (atomicFile == nullptr) { + HILOGE("Failed to get atomicFile"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return nullptr; + } + + auto entity = atomicFile->GetEntity(); + if (entity == nullptr) { + ErrorHandler::Throw(env, UNKNOWN_ERR); + return nullptr; + } + + return CreateStream(env, object, READ_STREAM_CLASS, entity->baseFileName); +} + +ani_arraybuffer AtomicFileAni::ReadFully(ani_env *env, [[maybe_unused]] ani_object object) +{ + auto atomicFile = Unwrap(env, object); + if (atomicFile == nullptr) { + HILOGE("Failed to get atomicFile"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return nullptr; + } + + auto ret = atomicFile->ReadFully(); + if (!ret.IsSuccess()) { + HILOGE("Failed to read fully"); + ErrorHandler::Throw(env, ret.GetError()); + return nullptr; + } + + auto &bufferData = ret.GetData().value(); + uint8_t *buffer = bufferData->buffer; + size_t length = bufferData->length; + auto [succ, obj] = TypeConverter::ToAniArrayBuffer(env, buffer, length); + if (!succ) { + HILOGE("Failed to ani_arrayBuffer"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return nullptr; + } + + return obj; +} + +ani_object AtomicFileAni::StartWrite(ani_env *env, [[maybe_unused]] ani_object object) +{ + auto atomicFile = Unwrap(env, object); + if (atomicFile == nullptr) { + HILOGE("Failed to get atomicFile"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return nullptr; + } + + auto entity = atomicFile->GetEntity(); + if (entity == nullptr) { + HILOGE("Failed to get atomicFile entity"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return nullptr; + } + + fs::path filePath = entity->newFileName; + fs::path parentPath = filePath.parent_path(); + if (access(parentPath.c_str(), F_OK) != 0) { + HILOGE("Parent directory does not exist, err:%{public}d", errno); + ErrorHandler::Throw(env, ENOENT); + return nullptr; + } + + char *tmpfile = const_cast(entity->newFileName.c_str()); + if (mkstemp(tmpfile) == -1) { + HILOGE("Fail to create tmp file err:%{public}d!", errno); + ErrorHandler::Throw(env, ENOENT); + return nullptr; + } + + ani_object writeStream = CreateStream(env, object, WRITE_STREAM_CLASS, entity->newFileName); + if (writeStream == nullptr) { + HILOGE("Failed to create write stream"); + return nullptr; + } + + return writeStream; +} + +void AtomicFileAni::FinishWrite(ani_env *env, [[maybe_unused]] ani_object object) +{ + auto atomicFile = Unwrap(env, object); + if (atomicFile == nullptr) { + HILOGE("Failed to get atomicFile"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return; + } + + auto entity = atomicFile->GetEntity(); + if (entity == nullptr) { + HILOGE("Failed to get atomicFile entity"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return; + } + + auto ret = atomicFile->FinishWrite(); + if (!ret.IsSuccess()) { + HILOGE("Failed to finish write"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + } + return; +} + +void AtomicFileAni::FailWrite(ani_env *env, [[maybe_unused]] ani_object object) +{ + auto atomicFile = Unwrap(env, object); + if (atomicFile == nullptr) { + HILOGE("Failed to get atomicFile"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return; + } + + auto entity = atomicFile->GetEntity(); + if (entity == nullptr) { + HILOGE("Failed to get atomicFile entity"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return; + } + + auto ret = atomicFile->FailWrite(); + if (!ret.IsSuccess()) { + HILOGE("Failed to fail write"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + } + return; +} + +void AtomicFileAni::Delete(ani_env *env, [[maybe_unused]] ani_object object) +{ + auto atomicFile = Unwrap(env, object); + if (atomicFile == nullptr) { + HILOGE("Failed to get atomicFile"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return; + } + + auto ret = atomicFile->Delete(); + if (!ret.IsSuccess()) { + HILOGE("Failed to delete"); + ErrorHandler::Throw(env, ret.GetError()); + return; + } + + return; +} +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_atomicfile/ani/atomicfile_ani.h b/interfaces/kits/js/src/mod_fs/class_atomicfile/ani/atomicfile_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..5a2c8d02c2ba4754b23fa978b785cb11dafee38e --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_atomicfile/ani/atomicfile_ani.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_ATOMICFILE_ANI_ATOMICFILE_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_ATOMICFILE_ANI_ATOMICFILE_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class AtomicFileAni final { +public: + static void Constructor(ani_env *env, ani_object obj, ani_string pathObj); + static ani_string GetPath(ani_env *env, [[maybe_unused]] ani_object object); + static ani_object GetBaseFile(ani_env *env, [[maybe_unused]] ani_object object); + static ani_object OpenRead(ani_env *env, [[maybe_unused]] ani_object object); + static ani_arraybuffer ReadFully(ani_env *env, [[maybe_unused]] ani_object object); + static ani_object StartWrite(ani_env *env, [[maybe_unused]] ani_object object); + static void FinishWrite(ani_env *env, [[maybe_unused]] ani_object object); + static void FailWrite(ani_env *env, [[maybe_unused]] ani_object object); + static void Delete(ani_env *env, [[maybe_unused]] ani_object object); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_ATOMICFILE_ANI_ATOMICFILE_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_atomicfile/fs_atomicfile.cpp b/interfaces/kits/js/src/mod_fs/class_atomicfile/fs_atomicfile.cpp new file mode 100644 index 0000000000000000000000000000000000000000..21200a84226f2b0370ef0f13535cb9fc51f2688d --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_atomicfile/fs_atomicfile.cpp @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "fs_atomicfile.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "fs_atomicfile_entity.h" +#include "filemgmt_libfs.h" +#include "file_instantiator.h" +#include "file_utils.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace fs = std::filesystem; + +const std::string READ_STREAM_CLASS = "ReadStream"; +const std::string WRITE_STREAM_CLASS = "WriteStream"; +const std::string TEMP_FILE_SUFFIX = "_XXXXXX"; + +FsAtomicFileEntity *FsAtomicFile::GetEntity() +{ + if (!entity) { + return nullptr; + } + return entity.get(); +} + +void FsAtomicFile::FinalizeCallback(void *finalizeData, [[maybe_unused]] void *finalizeHint) +{ + BufferData *bufferData = static_cast(finalizeData); + delete bufferData; +} + +string FsAtomicFile::GetPath() +{ + return entity->baseFileName; +} + +FsResult FsAtomicFile::GetBaseFile() +{ + if (entity == nullptr) { + HILOGE("Failed to get atomicFileEntity"); + return FsResult::Error(UNKNOWN_ERR); + } + + if (entity->baseFileName.size() >= PATH_MAX) { + HILOGE("Base file name is too long"); + return FsResult::Error(UNKNOWN_ERR); + } + + auto absolutePath = std::make_unique(PATH_MAX); + char *result = realpath(entity->baseFileName.c_str(), absolutePath.get()); + if (result == nullptr) { + HILOGE("Failed to resolve real path, err:%{public}d", errno); + return FsResult::Error(errno); + } + + int fd = open(result, O_RDONLY); + if (fd < 0) { + HILOGE("Failed to open file, err:%{public}d", errno); + return FsResult::Error(errno); + } + + return FileInstantiator::InstantiateFile(fd, entity->baseFileName, false); +} + +static std::tuple, int32_t> ReadFileToBuffer(FILE *fp) +{ + int fd = fileno(fp); + if (fd < 0) { + HILOGE("Failed to get file descriptor, err:%{public}d", errno); + return { nullptr, UNKNOWN_ERR }; + } + + struct stat fileStat {}; + if (fstat(fd, &fileStat) < 0) { + HILOGE("Failed to get file stats, err:%{public}d", errno); + return { nullptr, errno }; + } + + long fileSize = fileStat.st_size; + if (fileSize <= 0) { + HILOGE("Invalid file size"); + return { nullptr, EIO }; + } + + auto bufferData = std::make_unique(); + bufferData->buffer = new (std::nothrow) uint8_t[fileSize]; + if (bufferData->buffer == nullptr) { + HILOGE("Failed to allocate memory"); + return { nullptr, ENOMEM }; + } + + bufferData->length = fread(bufferData->buffer, sizeof(uint8_t), fileSize, fp); + if ((bufferData->length != static_cast(fileSize) && !feof(fp)) || ferror(fp)) { + HILOGE("Failed to read file, actual length is:%zu, fileSize:%ld", bufferData->length, fileSize); + delete[] bufferData->buffer; + bufferData->buffer = nullptr; + bufferData->length = 0; + return { nullptr, EIO }; + } + return { std::move(bufferData), ERRNO_NOERR }; +} + +FsResult> FsAtomicFile::ReadFully() +{ + if (entity == nullptr) { + HILOGE("Failed to get atomicFileEntity"); + return FsResult>::Error(UNKNOWN_ERR); + } + + auto absolutePath = std::make_unique(PATH_MAX); + char *result = realpath(entity->baseFileName.c_str(), absolutePath.get()); + if (result == nullptr) { + HILOGE("Failed to resolve file real path, err:%{public}d", errno); + return FsResult>::Error(errno); + } + + auto file = std::unique_ptr(std::fopen(result, "rb"), &std::fclose); + if (!file) { + HILOGE("Failed to open file, err:%{public}d", errno); + return FsResult>::Error(errno); + } + + auto [bufferData, errCode] = ReadFileToBuffer(file.get()); + if (errCode != ERRNO_NOERR) { + return FsResult>::Error(errCode); + } + return FsResult>::Success(move(bufferData)); +} + +FsResult FsAtomicFile::StartWrite() +{ + fs::path filePath = entity->newFileName; + fs::path parentPath = filePath.parent_path(); + if (access(parentPath.c_str(), F_OK) != 0) { + HILOGE("Parent directory does not exist, err:%{public}d", errno); + return FsResult::Error(ENOENT); + } + + char *tmpfile = const_cast(entity->newFileName.c_str()); + if (mkstemp(tmpfile) == -1) { + HILOGE("Fail to create tmp file err:%{public}d!", errno); + return FsResult::Error(ENOENT); + } + + return FsResult::Success(entity->newFileName); +} + +FsResult FsAtomicFile::FinishWrite() +{ + if (std::rename(entity->newFileName.c_str(), entity->baseFileName.c_str()) != 0) { + HILOGE("Rename failed"); + return FsResult::Error(errno); + } + std::string tmpNewFileName = entity->baseFileName; + entity->newFileName = tmpNewFileName.append(TEMP_FILE_SUFFIX); + + return FsResult::Success(); +} + +FsResult FsAtomicFile::FailWrite() +{ + if (!fs::remove(entity->newFileName)) { + HILOGW("Failed to remove file"); + return FsResult::Error(errno); + } + std::string tmpNewFileName = entity->baseFileName; + entity->newFileName = tmpNewFileName.append(TEMP_FILE_SUFFIX); + + return FsResult::Success(); +} + +FsResult FsAtomicFile::Delete() +{ + auto rafentity = GetEntity(); + if (rafentity == nullptr) { + HILOGE("Failed to get atomicFileEntity"); + return FsResult::Error(UNKNOWN_ERR); + } + + bool errFlag = false; + std::error_code fsErrcode; + if (fs::exists(rafentity->newFileName, fsErrcode) && !fs::remove(rafentity->newFileName, fsErrcode)) { + errFlag = true; + } + if (fs::exists(rafentity->baseFileName, fsErrcode) && !fs::remove(rafentity->baseFileName, fsErrcode)) { + errFlag = true; + } + if (errFlag) { + HILOGE("Failed to remove file, err:%{public}s", fsErrcode.message().c_str()); + return FsResult::Error(fsErrcode.value()); + } + + rafentity->newFileName.clear(); + rafentity->baseFileName.clear(); + return FsResult::Success(); +} + +FsResult FsAtomicFile::Constructor(string path) +{ + auto atomicFileEntity = CreateUniquePtr(); + if (atomicFileEntity == nullptr) { + HILOGE("Failed to request heap memory"); + return FsResult::Error(ENOMEM); + } + atomicFileEntity->baseFileName = path; + atomicFileEntity->newFileName = path.append(TEMP_FILE_SUFFIX); + + auto file = new FsAtomicFile(move(atomicFileEntity)); + + return FsResult::Success(file); +} +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_atomicfile/fs_atomicfile.h b/interfaces/kits/js/src/mod_fs/class_atomicfile/fs_atomicfile.h new file mode 100644 index 0000000000000000000000000000000000000000..80996b1c76844d90248768f25499a424dbf07352 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_atomicfile/fs_atomicfile.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_ATOMICFILE_FS_ATOMICFILE_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_ATOMICFILE_FS_ATOMICFILE_H + +#include "fs_atomicfile_entity.h" +#include "fs_file.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +struct BufferData { + uint8_t *buffer = nullptr; + size_t length = 0; + + ~BufferData() + { + delete[] buffer; + } +}; + +class FsAtomicFile final { +public: + FsAtomicFileEntity *GetEntity(); + static FsResult Constructor(string path); + string GetPath(); + FsResult GetBaseFile(); + FsResult> ReadFully(); + FsResult StartWrite(); + FsResult FinishWrite(); + FsResult FailWrite(); + FsResult Delete(); + static void FinalizeCallback(void *finalizeData, [[maybe_unused]] void *finalizeHint); + +private: + unique_ptr entity; + explicit FsAtomicFile(unique_ptr entity) : entity(move(entity)) {} +}; +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_ATOMICFILE_FS_ATOMICFILE_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_atomicfile/fs_atomicfile_entity.h b/interfaces/kits/js/src/mod_fs/class_atomicfile/fs_atomicfile_entity.h new file mode 100644 index 0000000000000000000000000000000000000000..71bcb9ee18e96c6f3b174dcc380aeae781d7a2b3 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_atomicfile/fs_atomicfile_entity.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_ATOMICFILE_FS_ATOMICFILE_ENTITY_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_ATOMICFILE_FS_ATOMICFILE_ENTITY_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +struct FsAtomicFileEntity { + std::string baseFileName = ""; + std::string newFileName = ""; +}; +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_ATOMICFILE_FS_ATOMICFILE_ENTITY_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_readeriterator/ani/reader_iterator_ani.cpp b/interfaces/kits/js/src/mod_fs/class_readeriterator/ani/reader_iterator_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8642ae512c49e0ee34a4ab8183302ecdcd01ed09 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_readeriterator/ani/reader_iterator_ani.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "reader_iterator_ani.h" + +#include "ani_signature.h" +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "reader_iterator_result_ani.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +using namespace std; +using namespace OHOS::FileManagement::ModuleFileIO; +using namespace OHOS::FileManagement::ModuleFileIO::ANI::AniSignature; + +ani_object ReaderIteratorAni::Wrap(ani_env *env, const FsReaderIterator *it) +{ + if (it == nullptr) { + HILOGE("FsReaderIterator pointer is null!"); + return nullptr; + } + + auto classDesc = FS::ReaderIteratorInner::classDesc.c_str(); + ani_class cls; + if (ANI_OK != env->FindClass(classDesc, &cls)) { + HILOGE("Cannot find class %s", classDesc); + return nullptr; + } + + auto ctorDesc = FS::ReaderIteratorInner::ctorDesc.c_str(); + auto ctorSig = FS::ReaderIteratorInner::ctorSig.c_str(); + ani_method ctor; + if (ANI_OK != env->Class_FindMethod(cls, ctorDesc, ctorSig, &ctor)) { + HILOGE("Cannot find constructor method for class %s", classDesc); + return nullptr; + } + + ani_long ptr = static_cast(reinterpret_cast(it)); + ani_object obj; + if (ANI_OK != env->Object_New(cls, ctor, &obj, ptr)) { + HILOGE("New %s obj Failed!", classDesc); + return nullptr; + } + + return obj; +} + +FsReaderIterator *ReaderIteratorAni::Unwrap(ani_env *env, ani_object object) +{ + ani_long nativePtr; + auto ret = env->Object_GetFieldByName_Long(object, "nativePtr", &nativePtr); + if (ret != ANI_OK) { + HILOGE("Unwrap fsReaderIterator err: %{private}d", ret); + return nullptr; + } + uintptr_t ptrValue = static_cast(nativePtr); + FsReaderIterator *readeriterator = reinterpret_cast(ptrValue); + return readeriterator; +} + +ani_object ReaderIteratorAni::Next(ani_env *env, [[maybe_unused]] ani_object object) +{ + auto fsReaderIterator = Unwrap(env, object); + if (fsReaderIterator == nullptr) { + ErrorHandler::Throw(env, UNKNOWN_ERR); + return nullptr; + } + + auto ret = fsReaderIterator->Next(); + if (!ret.IsSuccess()) { + HILOGE("Cannot get readeriterator next!"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return nullptr; + } + + auto nextRet = ret.GetData().value(); + auto result = ReaderIteratorResultAni::Wrap(env, &nextRet); + if (result == nullptr) { + ErrorHandler::Throw(env, UNKNOWN_ERR); + return nullptr; + } + return result; +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_readeriterator/ani/reader_iterator_ani.h b/interfaces/kits/js/src/mod_fs/class_readeriterator/ani/reader_iterator_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..13b2f7556bd5f2313b36c5a96f8fb42252d3e0d1 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_readeriterator/ani/reader_iterator_ani.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_READERITERATOR_ANI_READER_ITERATOR_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_READERITERATOR_ANI_READER_ITERATOR_ANI_H + +#include + +#include "fs_reader_iterator.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class ReaderIteratorAni final { +public: + static ani_object Wrap(ani_env *env, const FsReaderIterator *it); + static FsReaderIterator *Unwrap(ani_env *env, ani_object object); + static ani_object Next(ani_env *env, [[maybe_unused]] ani_object object); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_READERITERATOR_ANI_READER_ITERATOR_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_readeriterator/ani/reader_iterator_result_ani.cpp b/interfaces/kits/js/src/mod_fs/class_readeriterator/ani/reader_iterator_result_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b8efe806e026de0b7c54f2b29aab3d76007120ac --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_readeriterator/ani/reader_iterator_result_ani.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "reader_iterator_result_ani.h" + +#include "ani_signature.h" +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +using namespace std; +using namespace OHOS::FileManagement::ModuleFileIO; +using namespace OHOS::FileManagement::ModuleFileIO::ANI::AniSignature; + +ani_object ReaderIteratorResultAni::Wrap(ani_env *env, const ReaderIteratorResult *result) +{ + if (result == nullptr) { + HILOGE("ReaderIteratorResult pointer is null!"); + return nullptr; + } + + auto classDesc = FS::ReaderIteratorResultInner::classDesc.c_str(); + ani_class cls; + if (ANI_OK != env->FindClass(classDesc, &cls)) { + HILOGE("Cannot find class %s", classDesc); + return nullptr; + } + + auto ctorDesc = FS::ReaderIteratorResultInner::ctorDesc.c_str(); + auto ctorSig = FS::ReaderIteratorResultInner::ctorSig.c_str(); + ani_method ctor; + if (ANI_OK != env->Class_FindMethod(cls, ctorDesc, ctorSig, &ctor)) { + HILOGE("Cannot find constructor method for class %s", classDesc); + return nullptr; + } + + ani_long ptr = static_cast(reinterpret_cast(result)); + ani_object obj; + if (ANI_OK != env->Object_New(cls, ctor, &obj, ptr)) { + HILOGE("New %s obj Failed!", classDesc); + return nullptr; + } + + const auto &done = result->done; + if (ANI_OK != AniHelper::SetPropertyValue(env, cls, obj, "done", static_cast(done))) { + HILOGE("Set 'done' field value failed!"); + return nullptr; + } + + const auto &value = result->value; + if (ANI_OK != AniHelper::SetPropertyValue(env, cls, obj, "value", value)) { + HILOGE("Set 'value' field value failed!"); + return nullptr; + } + + return obj; +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_readeriterator/ani/reader_iterator_result_ani.h b/interfaces/kits/js/src/mod_fs/class_readeriterator/ani/reader_iterator_result_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..31bf73e9cef76868f054bdc0b5d3158ef2cb7606 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_readeriterator/ani/reader_iterator_result_ani.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_READERITERATOR_ANI_READER_ITERATOR_RESULT_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_READERITERATOR_ANI_READER_ITERATOR_RESULT_ANI_H + +#include + +#include "fs_reader_iterator.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class ReaderIteratorResultAni final { +public: + static ani_object Wrap(ani_env *env, const ReaderIteratorResult *result); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_READERITERATOR_ANI_READER_ITERATOR_RESULT_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_readeriterator/fs_reader_iterator.cpp b/interfaces/kits/js/src/mod_fs/class_readeriterator/fs_reader_iterator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..31e0c6b9d60973846df2e117415753f0feb2c6e2 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_readeriterator/fs_reader_iterator.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "fs_reader_iterator.h" + +#include "file_utils.h" +#include "filemgmt_libhilog.h" +#include "rust_file.h" + +namespace OHOS::FileManagement::ModuleFileIO { +using namespace std; + +FsResult FsReaderIterator::Constructor() +{ + auto entity = CreateUniquePtr(); + if (entity == nullptr) { + HILOGE("Failed to request heap memory."); + return FsResult::Error(ENOMEM); + } + + FsReaderIterator *it = new FsReaderIterator(move(entity)); + + if (it == nullptr) { + HILOGE("Failed to create FsReaderIterator object on heap."); + return FsResult::Error(ENOMEM); + } + return FsResult::Success(move(it)); +} + +FsResult FsReaderIterator::Next() +{ + if (entity == nullptr) { + HILOGE("Failed to get reader iterator entity"); + return FsResult::Error(UNKNOWN_ERR); + } + + Str *str = NextLine(entity->iterator); + if (str == nullptr && entity->offset != 0) { + HILOGE("Failed to get next line, error:%{public}d", errno); + return FsResult::Error(errno); + } + + ReaderIteratorResult result; + bool done = entity->offset == 0; + result.done = done; + if (str != nullptr) { + string value(str->str, str->len); + result.value = value; + entity->offset -= static_cast(str->len); + } else { + result.value = ""; + } + StrFree(str); + + return FsResult::Success(move(result)); +} + +} // namespace OHOS::FileManagement::ModuleFileIO \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_readeriterator/fs_reader_iterator.h b/interfaces/kits/js/src/mod_fs/class_readeriterator/fs_reader_iterator.h new file mode 100644 index 0000000000000000000000000000000000000000..bc534da09eb0acbaa8261bfe599580c6fdbda9aa --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_readeriterator/fs_reader_iterator.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_READERITERATOR_FS_READERITERATOR_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_READERITERATOR_FS_READERITERATOR_H + +#include "filemgmt_libfs.h" +#include "readeriterator_entity.h" + +namespace OHOS::FileManagement::ModuleFileIO { + +struct ReaderIteratorResult { + bool done; + std::string value; +}; + +class FsReaderIterator final { +public: + static FsResult Constructor(); + + ReaderIteratorEntity *GetReaderIteratorEntity() const + { + return entity.get(); + } + + FsResult Next(); + +private: + unique_ptr entity; + explicit FsReaderIterator(unique_ptr entity) : entity(move(entity)) {}; +}; +} // namespace OHOS::FileManagement::ModuleFileIO +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_READERITERATOR_FS_READERITERATOR_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/read_lines_ani.cpp b/interfaces/kits/js/src/mod_fs/properties/ani/read_lines_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..10c3ce394cbca152b0576a82b45d521f9f23fc9f --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/read_lines_ani.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "read_lines_ani.h" + +#include "ani_helper.h" +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "read_lines_core.h" +#include "reader_iterator_ani.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +using namespace OHOS::FileManagement::ModuleFileIO; + +static tuple> ToReadLinesOptions(ani_env *env, ani_object obj) +{ + Options options; + + ani_boolean isUndefined; + env->Reference_IsUndefined(obj, &isUndefined); + if (isUndefined) { + return { true, nullopt }; + } + + auto [succEncoding, encoding] = AniHelper::ParseEncoding(env, obj); + if (!succEncoding) { + HILOGE("Illegal option.encoding parameter"); + return { false, nullopt }; + } + options.encoding = encoding.value(); + + return { true, make_optional(move(options)) }; +} + +ani_object ReadLinesAni::ReadLinesSync( + ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path, ani_object options) +{ + auto [succPath, filePath] = TypeConverter::ToUTF8String(env, path); + if (!succPath) { + HILOGE("Invalid path from ETS first argument"); + ErrorHandler::Throw(env, EINVAL); + return nullptr; + } + + auto [succMode, opt] = ToReadLinesOptions(env, options); + if (!succMode) { + HILOGE("Invalid options"); + ErrorHandler::Throw(env, EINVAL); + return nullptr; + } + + FsResult ret = ReadLinesCore::DoReadLines(filePath, opt); + if (!ret.IsSuccess()) { + HILOGE("Readlines failed"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return nullptr; + } + + const FsReaderIterator *readerIterator = ret.GetData().value(); + auto result = ReaderIteratorAni::Wrap(env, move(readerIterator)); + if (result == nullptr) { + ErrorHandler::Throw(env, UNKNOWN_ERR); + return nullptr; + } + return result; +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/read_lines_ani.h b/interfaces/kits/js/src/mod_fs/properties/ani/read_lines_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..3f1bfeb7252e7c71937aa5ee63ff3631f4ec8926 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/read_lines_ani.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_ANI_READ_LINES_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_ANI_READ_LINES_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class ReadLinesAni final { +public: + static ani_object ReadLinesSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path, + ani_object options); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_ANI_READ_LINES_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/read_lines_core.h b/interfaces/kits/js/src/mod_fs/properties/read_lines_core.h new file mode 100644 index 0000000000000000000000000000000000000000..67cae2c52183c08fd066431aee5daee23db5b776 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/read_lines_core.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_READ_LINES_CORE_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_READ_LINES_CORE_H + +#include + +#include "filemgmt_libfs.h" +#include "fs_reader_iterator.h" +#include "fs_utils.h" +#include "readeriterator_entity.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { + +struct Options final { + std::string encoding; +}; + +class ReadLinesCore final { +public: + static FsResult DoReadLines( + const std::string &path, std::optional option = std::nullopt); +}; + +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_READ_LINES_CORE_H \ No newline at end of file diff --git a/interfaces/test/unittest/js/mod_fs/class_readeriterator/fs_reader_iterator_mock_test.cpp b/interfaces/test/unittest/js/mod_fs/class_readeriterator/fs_reader_iterator_mock_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..196354ad1e6d71fddc5eb4e17ce2fb0396119b86 --- /dev/null +++ b/interfaces/test/unittest/js/mod_fs/class_readeriterator/fs_reader_iterator_mock_test.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include + +#include "fs_reader_iterator.h" +#include "read_lines_core.h" +#include "uv_fs_mock.h" + +namespace OHOS::FileManagement::ModuleFileIO::Test { +using namespace testing; +using namespace testing::ext; +using namespace std; + +class FsReaderIteratorMockTest : public testing::Test { +public: + static filesystem::path tempFilePath; + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); + static inline shared_ptr uvMock = nullptr; +}; + +filesystem::path FsReaderIteratorMockTest::tempFilePath; + +void FsReaderIteratorMockTest::SetUpTestCase(void) +{ + GTEST_LOG_(INFO) << "SetUpTestCase"; + tempFilePath = filesystem::temp_directory_path() / "FsReaderIteratorMockTest_test_file.txt"; + ofstream tempfile(tempFilePath); + tempfile << ""; + tempfile.close(); + uvMock = make_shared(); + Uvfs::ins = uvMock; +} + +void FsReaderIteratorMockTest::TearDownTestCase(void) +{ + GTEST_LOG_(INFO) << "TearDownTestCase"; + filesystem::remove(tempFilePath); + Uvfs::ins = nullptr; + uvMock = nullptr; +} + +void FsReaderIteratorMockTest::SetUp(void) +{ + GTEST_LOG_(INFO) << "SetUp"; +} + +void FsReaderIteratorMockTest::TearDown(void) +{ + GTEST_LOG_(INFO) << "TearDown"; +} + +/** + * @tc.name: FsReaderIteratorMockTest_Next_001 + * @tc.desc: Test FsReaderIterator::Next for success case + * @tc.size: SMALL + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(FsReaderIteratorMockTest, FsReaderIteratorMockTest_Next_001, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FsReaderIteratorMockTest-begin FsReaderIteratorMockTest_Next_001"; + + string path = tempFilePath.string(); + optional option = nullopt; + + EXPECT_CALL(*uvMock, uv_fs_stat(_, _, _, _)).WillOnce(Return(1)); + + auto result = ReadLinesCore::DoReadLines(path, option); + EXPECT_TRUE(result.IsSuccess()); + + auto iterator = result.GetData().value(); + ASSERT_NE(iterator, nullptr); + + auto nextResult = iterator->Next(); + EXPECT_TRUE(nextResult.IsSuccess()); + EXPECT_TRUE(nextResult.GetData().value().done); + EXPECT_EQ(nextResult.GetData().value().value, ""); + + GTEST_LOG_(INFO) << "FsReaderIteratorMockTest-end FsReaderIteratorMockTest_Next_001"; +} + +} \ No newline at end of file diff --git a/interfaces/test/unittest/js/mod_fs/class_readeriterator/fs_reader_iterator_test.cpp b/interfaces/test/unittest/js/mod_fs/class_readeriterator/fs_reader_iterator_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..91729572d05f8a87729824319b84e2542d244b71 --- /dev/null +++ b/interfaces/test/unittest/js/mod_fs/class_readeriterator/fs_reader_iterator_test.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "fs_reader_iterator.h" + +#include +#include +#include + +namespace OHOS::FileManagement::ModuleFileIO::Test { +using namespace testing; +using namespace testing::ext; +using namespace std; + +class FsReaderIteratorTest : public testing::Test { +public: + static std::filesystem::path tempFilePath; + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +filesystem::path FsReaderIteratorTest::tempFilePath; + +void FsReaderIteratorTest::SetUpTestCase(void) +{ + GTEST_LOG_(INFO) << "SetUpTestCase"; + tempFilePath = std::filesystem::temp_directory_path() / "fs_reader_iterator_test_file.txt"; + ofstream tempfile(tempFilePath); + tempfile << "Test content\n123\n456"; + tempfile.close(); +} + +void FsReaderIteratorTest::TearDownTestCase(void) +{ + GTEST_LOG_(INFO) << "TearDownTestCase"; + filesystem::remove(tempFilePath); +} + +void FsReaderIteratorTest::SetUp(void) +{ + GTEST_LOG_(INFO) << "SetUp"; +} + +void FsReaderIteratorTest::TearDown(void) +{ + GTEST_LOG_(INFO) << "TearDown"; +} + +/** + * @tc.name: FsReaderIteratorTest_Constructor_001 + * @tc.desc: Test FsReaderIterator::Constructor for success case + * @tc.size: SMALL + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(FsReaderIteratorTest, FsReaderIteratorTest_Constructor_001, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FsReaderIteratorTest-begin FsReaderIteratorTest_Constructor_001"; + + auto result = FsReaderIterator::Constructor(); + EXPECT_EQ(result.IsSuccess(), true); + + GTEST_LOG_(INFO) << "FsReaderIteratorTest-end FsReaderIteratorTest_Constructor_001"; +} + +} \ No newline at end of file diff --git a/interfaces/test/unittest/js/mod_fs/properties/read_lines_core_mock_test.cpp b/interfaces/test/unittest/js/mod_fs/properties/read_lines_core_mock_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..118e5e28a9c116433cf08fb5ab3f2557a0dd8566 --- /dev/null +++ b/interfaces/test/unittest/js/mod_fs/properties/read_lines_core_mock_test.cpp @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include "mock/uv_fs_mock.h" +#include "read_lines_core.h" + +namespace OHOS::FileManagement::ModuleFileIO::Test { +using namespace testing; +using namespace testing::ext; +using namespace std; + +class ReadLinesCoreMockTest : public testing::Test { +public: + static filesystem::path tempFilePath; + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); + static inline shared_ptr uvMock = nullptr; +}; + +filesystem::path ReadLinesCoreMockTest::tempFilePath; + +void ReadLinesCoreMockTest::SetUpTestCase(void) +{ + GTEST_LOG_(INFO) << "SetUpTestCase"; + tempFilePath = filesystem::temp_directory_path() / "read_lines_test_file.txt"; + ofstream(tempFilePath) << "Test content\n123\n456"; + ofstream(tempFilePath).close(); + uvMock = std::make_shared(); + Uvfs::ins = uvMock; +} + +void ReadLinesCoreMockTest::TearDownTestCase(void) +{ + filesystem::remove(tempFilePath); + GTEST_LOG_(INFO) << "TearDownTestCase"; + Uvfs::ins = nullptr; + uvMock = nullptr; +} + +void ReadLinesCoreMockTest::SetUp(void) +{ + GTEST_LOG_(INFO) << "SetUp"; +} + +void ReadLinesCoreMockTest::TearDown(void) +{ + GTEST_LOG_(INFO) << "TearDown"; +} + +/** + * @tc.name: ReadLinesCoreMockTest_DoReadLines_001 + * @tc.desc: Test function of ReadLinesCore::DoReadLines interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(ReadLinesCoreMockTest, ReadLinesCoreMockTest_DoReadLines_001, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ReadLinesCoreMockTest-begin ReadLinesCoreMockTest_DoReadLines_001"; + + string path = tempFilePath.string(); + Options option; + option.encoding = "utf-8"; + + EXPECT_CALL(*uvMock, uv_fs_stat(_, _, _, _)).WillOnce(Return(1)); + auto res = ReadLinesCore::DoReadLines(path, option); + EXPECT_EQ(res.IsSuccess(), true); + + GTEST_LOG_(INFO) << "ReadLinesCoreMockTest-end ReadLinesCoreMockTest_DoReadLines_001"; +} + +/** + * @tc.name: ReadLinesCoreMockTest_DoReadLines_002 + * @tc.desc: Test function of ReadLinesCore::DoReadLines interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(ReadLinesCoreMockTest, ReadLinesCoreMockTest_DoReadLines_002, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ReadLinesCoreMockTest-begin ReadLinesCoreMockTest_DoReadLines_002"; + + string path = tempFilePath.string(); + + EXPECT_CALL(*uvMock, uv_fs_stat(_, _, _, _)).WillOnce(Return(1)); + auto res = ReadLinesCore::DoReadLines(path); + EXPECT_EQ(res.IsSuccess(), true); + + GTEST_LOG_(INFO) << "ReadLinesCoreMockTest-end ReadLinesCoreMockTest_DoReadLines_002"; +} + +/** + * @tc.name: ReadLinesCoreMockTest_DoReadLines_003 + * @tc.desc: Test function of ReadLinesCore::DoReadLines interface for FAILED. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(ReadLinesCoreMockTest, ReadLinesCoreMockTest_DoReadLines_003, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ReadLinesCoreMockTest-begin ReadLinesCoreMockTest_DoReadLines_003"; + + string path = tempFilePath.string(); + Options option; + option.encoding = "utf-8"; + + EXPECT_CALL(*uvMock, uv_fs_stat(_, _, _, _)).WillOnce(Return(-1)); + auto res = ReadLinesCore::DoReadLines(path, option); + EXPECT_EQ(res.IsSuccess(), false); + + GTEST_LOG_(INFO) << "ReadLinesCoreMockTest-end ReadLinesCoreMockTest_DoReadLines_003"; +} + +} // namespace OHOS::FileManagement::ModuleFileIO::Test \ No newline at end of file diff --git a/interfaces/test/unittest/js/mod_fs/properties/read_lines_core_test.cpp b/interfaces/test/unittest/js/mod_fs/properties/read_lines_core_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..92e4f19b429030d609720ca723a95115d2e281d1 --- /dev/null +++ b/interfaces/test/unittest/js/mod_fs/properties/read_lines_core_test.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "read_lines_core.h" + +namespace OHOS::FileManagement::ModuleFileIO::Test { +using namespace testing; +using namespace testing::ext; +using namespace std; + +class ReadLinesCoreTest : public testing::Test { +public: + static filesystem::path tempFilePath; + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +filesystem::path ReadLinesCoreTest::tempFilePath; + +void ReadLinesCoreTest::SetUpTestCase(void) +{ + tempFilePath = filesystem::temp_directory_path() / "read_lines_test_file.txt"; + ofstream(tempFilePath) << "Test content\n123\n456"; + ofstream(tempFilePath).close(); + GTEST_LOG_(INFO) << "SetUpTestCase"; +} + +void ReadLinesCoreTest::TearDownTestCase(void) +{ + filesystem::remove(tempFilePath); + GTEST_LOG_(INFO) << "TearDownTestCase"; +} + +void ReadLinesCoreTest::SetUp(void) +{ + GTEST_LOG_(INFO) << "SetUp"; +} + +void ReadLinesCoreTest::TearDown(void) +{ + GTEST_LOG_(INFO) << "TearDown"; +} + +/** + * @tc.name: ReadLinesCoreTest_DoReadLines_001 + * @tc.desc: Test function of ReadLinesCore::DoReadLines interface for FAILED. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(ReadLinesCoreTest, ReadLinesCoreTest_DoReadLines_001, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ReadLinesCoreTest-begin ReadLinesCoreTest_DoReadLines_001"; + + string path = "ReadLinesCoreTest_DoReadLines_001"; + Options option; + option.encoding = "utf-8"; + auto res = ReadLinesCore::DoReadLines(path, option); + EXPECT_EQ(res.IsSuccess(), false); + + GTEST_LOG_(INFO) << "ReadLinesCoreTest-end ReadLinesCoreTest_DoReadLines_001"; +} + +/** + * @tc.name: ReadLinesCoreTest_DoReadLines_002 + * @tc.desc: Test function of ReadLinesCore::DoReadLines interface for FAILED. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(ReadLinesCoreTest, ReadLinesCoreTest_DoReadLines_002, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ReadLinesCoreTest-begin ReadLinesCoreTest_DoReadLines_002"; + + string path = "ReadLinesCoreTest_DoReadLines_002"; + Options option; + option.encoding = "utf-16"; + auto res = ReadLinesCore::DoReadLines(path, option); + EXPECT_EQ(res.IsSuccess(), false); + + GTEST_LOG_(INFO) << "ReadLinesCoreTest-end ReadLinesCoreTest_DoReadLines_002"; +} + +} // namespace OHOS::FileManagement::ModuleFileIO::Test \ No newline at end of file diff --git a/interfaces/test/unittest/js/mod_fs/properties/read_text_core_test.cpp b/interfaces/test/unittest/js/mod_fs/properties/read_text_core_test.cpp index 459ffd6fadd9993d4aa82c73216ecd0db64c53bb..d9135867ef67a7f333d099c4919f2408e84d1f6b 100644 --- a/interfaces/test/unittest/js/mod_fs/properties/read_text_core_test.cpp +++ b/interfaces/test/unittest/js/mod_fs/properties/read_text_core_test.cpp @@ -47,7 +47,6 @@ public: * @tc.size: MEDIUM * @tc.type: FUNC * @tc.level Level 1 -* @tc.require: AR000IGDNF */ HWTEST_F(ReadTextCoreTest, DoReadTextTest_0001, testing::ext::TestSize.Level1) { @@ -68,7 +67,6 @@ HWTEST_F(ReadTextCoreTest, DoReadTextTest_0001, testing::ext::TestSize.Level1) * @tc.size: MEDIUM * @tc.type: FUNC * @tc.level Level 1 -* @tc.require: AR000IGDNF */ HWTEST_F(ReadTextCoreTest, DoReadTextTest_0002, testing::ext::TestSize.Level1) { @@ -90,7 +88,6 @@ HWTEST_F(ReadTextCoreTest, DoReadTextTest_0002, testing::ext::TestSize.Level1) * @tc.size: MEDIUM * @tc.type: FUNC * @tc.level Level 1 -* @tc.require: AR000IGDNF */ HWTEST_F(ReadTextCoreTest, DoReadTextTest_0003, testing::ext::TestSize.Level1) { @@ -112,7 +109,6 @@ HWTEST_F(ReadTextCoreTest, DoReadTextTest_0003, testing::ext::TestSize.Level1) * @tc.size: MEDIUM * @tc.type: FUNC * @tc.level Level 1 -* @tc.require: AR000IGDNF */ HWTEST_F(ReadTextCoreTest, DoReadTextTest_0004, testing::ext::TestSize.Level1) { @@ -134,7 +130,6 @@ HWTEST_F(ReadTextCoreTest, DoReadTextTest_0004, testing::ext::TestSize.Level1) * @tc.size: MEDIUM * @tc.type: FUNC * @tc.level Level 1 -* @tc.require: AR000IGDNF */ HWTEST_F(ReadTextCoreTest, DoReadTextTest_0005, testing::ext::TestSize.Level1) { @@ -156,7 +151,6 @@ HWTEST_F(ReadTextCoreTest, DoReadTextTest_0005, testing::ext::TestSize.Level1) * @tc.size: MEDIUM * @tc.type: FUNC * @tc.level Level 1 -* @tc.require: AR000IGDNF */ HWTEST_F(ReadTextCoreTest, DoReadTextTest_0006, testing::ext::TestSize.Level1) { @@ -176,7 +170,6 @@ HWTEST_F(ReadTextCoreTest, DoReadTextTest_0006, testing::ext::TestSize.Level1) * @tc.size: MEDIUM * @tc.type: FUNC * @tc.level Level 1 -* @tc.require: AR000IGDNF */ HWTEST_F(ReadTextCoreTest, DoReadTextTest_0007, testing::ext::TestSize.Level1) { @@ -198,7 +191,6 @@ HWTEST_F(ReadTextCoreTest, DoReadTextTest_0007, testing::ext::TestSize.Level1) * @tc.size: MEDIUM * @tc.type: FUNC * @tc.level Level 1 -* @tc.require: AR000IGDNF */ HWTEST_F(ReadTextCoreTest, DoReadTextTest_0008, testing::ext::TestSize.Level1) { @@ -221,7 +213,6 @@ HWTEST_F(ReadTextCoreTest, DoReadTextTest_0008, testing::ext::TestSize.Level1) * @tc.size: MEDIUM * @tc.type: FUNC * @tc.level Level 1 -* @tc.require: AR000IGDNF */ HWTEST_F(ReadTextCoreTest, DoReadTextTest_0009, testing::ext::TestSize.Level1) {