diff --git a/src/dconfigfile.cpp b/src/dconfigfile.cpp index bac32b24..d40a7e18 100644 --- a/src/dconfigfile.cpp +++ b/src/dconfigfile.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2021 - 2023 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2021 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later @@ -985,7 +985,7 @@ DConfigMetaImpl::~DConfigMetaImpl() \a value Configuration name \a uid User Id at setup time \a callerAppid Application id at setup time - @return A value of true indicates that the new value has been reset, and false indicates that it has not been set + @return true if the cache was updated (value or serial changed), false if no update was needed */ /*! @@ -1124,7 +1124,7 @@ class Q_DECL_HIDDEN DConfigCacheImpl : public DConfigCache { } bool setValue(const QString &key, const QVariant &value, const int serial, const uint uid, const QString &appid) override { - if (values.value(key) == value) { + if (values.value(key) == value && DConfigInfo::checkSerial(values.serial(key), serial)) { return false; } values.setValue(key, value); @@ -1487,7 +1487,7 @@ QVariant DConfigFile::cacheValue(DConfigCache *userCache, const QString &key) co \a value The value to set \a userCache Specific user cache at setup time \a appid Application id at setup time - @return A value of true indicates that the new value has been reset, and false indicates that it has not been set + @return true if the cache was updated (value or serial changed), false if no update was needed */ bool DConfigFile::setValue(const QString &key, const QVariant &value, const QString &callerAppid, DConfigCache *userCache) { diff --git a/tests/data.qrc b/tests/data.qrc index 8f2b8eb5..0b63e4c7 100644 --- a/tests/data.qrc +++ b/tests/data.qrc @@ -11,6 +11,8 @@ data/LGPLv3.txt data/example-license.json data/dconf-example.override.noexistitem.json + data/dconf-serial-test.meta.json + data/dconf-serial-test.override.json data/dconfig2cpp/basic-types.meta.json data/dconfig2cpp/numeric-types.meta.json data/dconfig2cpp/complex-types.meta.json diff --git a/tests/data/dconf-serial-test.meta.json b/tests/data/dconf-serial-test.meta.json new file mode 100644 index 00000000..2a2473e3 --- /dev/null +++ b/tests/data/dconf-serial-test.meta.json @@ -0,0 +1,14 @@ +{ + "magic": "dsg.config.meta", + "version": "1.0", + "contents": { + "testKey": { + "value": "initial", + "serial": 0, + "flags": [], + "name": "test key for serial comparison", + "permissions": "readwrite", + "visibility": "private" + } + } +} diff --git a/tests/data/dconf-serial-test.override.json b/tests/data/dconf-serial-test.override.json new file mode 100644 index 00000000..2c73113b --- /dev/null +++ b/tests/data/dconf-serial-test.override.json @@ -0,0 +1,10 @@ +{ + "magic": "dsg.config.override", + "version": "1.0", + "contents": { + "testKey": { + "value": "initial", + "serial": 1 + } + } +} diff --git a/tests/ut_dconfigfile.cpp b/tests/ut_dconfigfile.cpp index 45c007d8..8938709b 100644 --- a/tests/ut_dconfigfile.cpp +++ b/tests/ut_dconfigfile.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2021 - 2023 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2021 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later @@ -506,6 +506,87 @@ TEST_F(ut_DConfigFile, userPublic) { } } +TEST_F(ut_DConfigFile, setValueWithSerialComparison) { + // 测试 DConfigCacheImpl::setValue 中的 serial 比较逻辑 + // 当值相同但 serial 不同时,应该返回 true(更新缓存) + + FileCopyGuard guard(":/data/dconf-serial-test.meta.json", QString("%1/%2.json").arg(metaPath, FILE_NAME)); + + // 场景1: 值和 serial 都相同 → 返回 false + { + DConfigFile config(APP_ID, FILE_NAME); + ASSERT_TRUE(config.load(LocalPrefix)); + QScopedPointer userCache(config.createUserCache(uid)); + ASSERT_TRUE(userCache->load(LocalPrefix)); + + // 首次设置值,serial=0 从 meta 传入 + ASSERT_TRUE(config.setValue("testKey", "test_value", "test", userCache.get())); + + // 再次设置相同的值,serial 相同 → 返回 false + ASSERT_FALSE(config.setValue("testKey", "test_value", "test", userCache.get())); + } + + // 场景2: 值相同,serial 不同 → 返回 true(新修复的场景) + { + DConfigFile config(APP_ID, FILE_NAME); + ASSERT_TRUE(config.load(LocalPrefix)); + QScopedPointer userCache(config.createUserCache(uid)); + ASSERT_TRUE(userCache->load(LocalPrefix)); + + // 设置值,缓存中 serial=0 + ASSERT_TRUE(config.setValue("testKey", "test_value", "test", userCache.get())); + + // 使用 override 文件将 serial 升级到 1 + FileCopyGuard guard2(":/data/dconf-serial-test.override.json", QString("%1/%2.json").arg(overridePath, FILE_NAME)); + + // 重新加载配置,此时 meta serial=1 + DConfigFile config2(APP_ID, FILE_NAME); + ASSERT_TRUE(config2.load(LocalPrefix)); + QScopedPointer userCache2(config2.createUserCache(uid)); + ASSERT_TRUE(userCache2->load(LocalPrefix)); + + // 设置相同的值,但 meta serial=1, cache serial=0 → 应该返回 true + ASSERT_TRUE(config2.setValue("testKey", "test_value", "test", userCache2.get())); + } + + // 场景3: 值不同,serial 相同 → 返回 true + { + DConfigFile config(APP_ID, FILE_NAME); + ASSERT_TRUE(config.load(LocalPrefix)); + QScopedPointer userCache(config.createUserCache(uid)); + ASSERT_TRUE(userCache->load(LocalPrefix)); + + // 设置初始值 + ASSERT_TRUE(config.setValue("testKey", "value1", "test", userCache.get())); + + // 设置不同的值,serial 相同 → 返回 true + ASSERT_TRUE(config.setValue("testKey", "value2", "test", userCache.get())); + } + + // 场景4: 值不同,serial 不同 → 返回 true + { + DConfigFile config(APP_ID, FILE_NAME); + ASSERT_TRUE(config.load(LocalPrefix)); + QScopedPointer userCache(config.createUserCache(uid)); + ASSERT_TRUE(userCache->load(LocalPrefix)); + + // 设置初始值 + ASSERT_TRUE(config.setValue("testKey", "value1", "test", userCache.get())); + + // 使用 override 文件将 serial 升级到 1 + FileCopyGuard guard2(":/data/dconf-serial-test.override.json", QString("%1/%2.json").arg(overridePath, FILE_NAME)); + + // 重新加载配置 + DConfigFile config2(APP_ID, FILE_NAME); + ASSERT_TRUE(config2.load(LocalPrefix)); + QScopedPointer userCache2(config2.createUserCache(uid)); + ASSERT_TRUE(userCache2->load(LocalPrefix)); + + // 设置不同的值,serial 也不同 → 返回 true + ASSERT_TRUE(config2.setValue("testKey", "value3", "test", userCache2.get())); + } +} + class ut_DConfigFileCheckName : public ut_DConfigFile, public ::testing::WithParamInterface> {