黄中银 1 неделя назад
Родитель
Сommit
f0d1cd535b
2 измененных файлов с 157 добавлено и 174 удалено
  1. 33 174
      README.md
  2. 124 0
      tests/README.md

+ 33 - 174
README.md

@@ -8,16 +8,21 @@
 
 ## 特性
 
-- 多格式支持(JSON、INI、XML、YAML、TOML、Redis、数据库)
-- 智能编码检测与统一 UTF-8 写入
-- 多层级配置合并
-- 可写配置与热重载
-- **动态配置重载**(支持文件变更自动检测、防抖、增量更新)
-- **配置节(GetSection)**:支持按路径获取配置子节,简化嵌套配置访问
+- **多格式支持**:JSON、INI、XML、YAML、TOML、Redis、数据库
+- **智能编码处理**:
+  - 读取时自动检测(BOM 优先,UTF.Unknown 库辅助,支持缓存)
+  - 写入时统一 UTF-8 无 BOM(PowerShell 脚本自动使用 UTF-8 BOM)
+  - 支持完整路径、通配符、正则表达式三种编码映射方式
+- **多层级配置合并**:高层级覆盖低层级
+- **可写配置**:支持配置修改并持久化到指定配置源
+- **热重载**:文件配置源支持变更自动重载
+- **动态配置重载**:支持文件变更自动检测、防抖、增量更新
+- **配置节**:支持按路径获取配置子节(`GetSection`),简化嵌套配置访问
+- **批量操作**:`GetMany`、`SetMany` 减少锁竞争,提升并发性能
 - **依赖注入集成**:提供 `AddApqCfg` 和 `ConfigureApqCfg<T>` 扩展方法
-- 线程安全(支持多线程并发读写)
-- Microsoft.Extensions.Configuration 兼容
-- Reactive Extensions (Rx) 支持配置变更订阅
+- **线程安全**:支持多线程并发读写
+- **Microsoft.Extensions.Configuration 兼容**:可无缝转换为标准配置接口
+- **Rx 支持**:通过 `ConfigChanges` 订阅配置变更事件
 
 ## 支持的框架
 
@@ -102,9 +107,12 @@ cfg.ConfigChanges.Subscribe(e =>
 
 所有文件配置源(JSON、INI、XML、YAML、TOML)均支持智能编码处理:
 
-- **读取时自动检测**:BOM 优先,UTF.Unknown 库辅助检测,支持 UTF-8、GBK、GB2312 等常见编码
-- **写入时统一 UTF-8**:默认使用 UTF-8 无 BOM 写入,PowerShell 脚本自动使用 UTF-8 BOM
-- **编码映射**:支持为特定文件或文件模式指定读取/写入编码
+- **读取时自动检测**:
+  - BOM 优先检测(UTF-8、UTF-16 LE/BE、UTF-32 LE/BE)
+  - UTF.Unknown 库辅助检测,支持 GBK、GB2312 等常见编码
+  - 检测结果自动缓存,文件修改后自动失效
+- **写入时统一 UTF-8**:默认使用 UTF-8 无 BOM,PowerShell 脚本(*.ps1、*.psm1、*.psd1)自动使用 UTF-8 BOM
+- **编码映射**:支持完整路径、通配符、正则表达式三种匹配方式
 
 ```csharp
 var cfg = new CfgBuilder()
@@ -112,6 +120,10 @@ var cfg = new CfgBuilder()
     .AddReadEncodingMapping(@"C:\legacy\old.ini", Encoding.GetEncoding("GB2312"))
     // 为 PowerShell 脚本指定写入编码(UTF-8 BOM)
     .AddWriteEncodingMappingWildcard("*.ps1", new UTF8Encoding(true))
+    // 设置编码检测置信度阈值(默认 0.6)
+    .WithEncodingConfidenceThreshold(0.7f)
+    // 启用编码检测日志
+    .WithEncodingDetectionLogging(result => Console.WriteLine($"检测到编码: {result}"))
     .AddJson("config.json", level: 0, writeable: true)
     .Build();
 ```
@@ -164,111 +176,15 @@ cd benchmarks/Apq.Cfg.Benchmarks
 dotnet run -c Release
 ```
 
-## 测试覆盖情况
-
-### 测试统计(共 199 个测试)
-
-| 测试类 | 测试数量 | 说明 |
-|--------|----------|------|
-| JsonCfgTests | 15 | JSON 配置源测试 |
-| EnvVarsCfgTests | 4 | 环境变量配置源测试 |
-| IniCfgTests | 5 | INI 文件配置源测试 |
-| XmlCfgTests | 5 | XML 文件配置源测试 |
-| YamlCfgTests | 6 | YAML 文件配置源测试 |
-| TomlCfgTests | 6 | TOML 文件配置源测试 |
-| RedisCfgTests | 5 | Redis 配置源测试 |
-| DatabaseCfgTests | 5 | 数据库配置源测试 |
-| CfgRootExtensionsTests | 4 | 扩展方法测试 |
-| CfgBuilderAdvancedTests | 14 | 高级功能测试 |
-| DynamicReloadTests | 12 | 动态配置重载测试 |
-| EncodingDetectionTests | 14 | 编码检测测试 |
-| ConcurrencyTests | 10 | 并发安全测试 |
-| BoundaryConditionTests | 32 | 边界条件测试 |
-| ExceptionHandlingTests | 20 | 异常处理测试 |
-| ConfigChangesSubscriptionTests | 28 | 配置变更订阅测试 |
-| CfgSectionTests | 14 | 配置节(GetSection/GetChildKeys)测试 |
-| ServiceCollectionExtensionsTests | 10 | 依赖注入扩展测试 |
-
-### 公开 API 覆盖矩阵
-
-| API | Json | Env | Ini | Xml | Yaml | Toml | Redis | DB |
-|-----|:----:|:---:|:---:|:---:|:----:|:----:|:-----:|:--:|
-| **ICfgRoot** |
-| `Get(key)` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
-| `Get<T>(key)` | ✅ | - | ✅ | ✅ | ✅ | ✅ | - | - |
-| `Exists(key)` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
-| `GetMany(keys)` | ✅ | - | - | - | - | - | - | - |
-| `GetMany<T>(keys)` | ✅ | - | - | - | - | - | - | - |
-| `Set(key, value)` | ✅ | - | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
-| `SetMany(values)` | ✅ | - | - | - | - | - | - | - |
-| `Set(key, value, targetLevel)` | ✅ | - | - | - | - | - | - | - |
-| `Remove(key)` | ✅ | - | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
-| `Remove(key, targetLevel)` | ✅ | - | - | - | - | - | - | - |
-| `SaveAsync()` | ✅ | - | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
-| `SaveAsync(targetLevel)` | ✅ | - | - | - | - | - | - | - |
-| `ToMicrosoftConfiguration()` | ✅ | - | - | - | - | - | - | - |
-| `ToMicrosoftConfiguration(options)` | ✅ | - | - | - | - | - | - | - |
-| `ConfigChanges` | ✅ | - | - | - | - | - | - | - |
-| `GetSection(path)` | ✅ | - | ✅ | ✅ | ✅ | ✅ | - | - |
-| `GetChildKeys()` | ✅ | - | ✅ | ✅ | ✅ | ✅ | - | - |
-| `Dispose/DisposeAsync` | ✅ | - | - | - | - | - | - | - |
-| **CfgBuilder** |
-| `AddJson()` | ✅ | - | - | - | - | - | - | - |
-| `AddEnvironmentVariables()` | - | ✅ | - | - | - | - | - | - |
-| `AddSource()` | ✅ | - | - | - | - | - | - | - |
-| `WithEncodingConfidenceThreshold()` | ✅ | - | - | - | - | - | - | - |
-| `AddReadEncodingMapping()` | ✅ | - | - | - | - | - | - | - |
-| `AddWriteEncodingMapping()` | ✅ | - | - | - | - | - | - | - |
-| `ConfigureEncodingMapping()` | ✅ | - | - | - | - | - | - | - |
-| `WithEncodingDetectionLogging()` | ✅ | - | - | - | - | - | - | - |
-| `Build()` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
-| **CfgRootExtensions** |
-| `TryGet<T>()` | ✅ | - | - | - | - | - | - | - |
-| `GetRequired<T>()` | ✅ | - | - | - | - | - | - | - |
-| **FileCfgSourceBase** |
-| `EncodingDetector` | ✅ | - | - | - | - | - | - | - |
-| `EncodingConfidenceThreshold` | ✅ | - | - | - | - | - | - | - |
-| **扩展包** |
-| `AddIni()` | - | - | ✅ | - | - | - | - | - |
-| `AddXml()` | - | - | - | ✅ | - | - | - | - |
-| `AddYaml()` | - | - | - | - | ✅ | - | - | - |
-| `AddToml()` | - | - | - | - | - | ✅ | - | - |
-| `AddRedis()` | - | - | - | - | - | - | ✅ | - |
-| `AddDatabase()` | - | - | - | - | - | - | - | ✅ |
-| **依赖注入扩展** |
-| `AddApqCfg()` | ✅ | - | - | - | - | - | - | - |
-| `ConfigureApqCfg<T>()` | ✅ | - | - | - | - | - | - | - |
-| **多层级覆盖** |
-| 高层级覆盖低层级 | ✅ | ✅ | - | - | - | - | ✅ | ✅ |
-
-> 说明:`-` 表示该配置源不支持此功能(如环境变量只读)或该功能只需测试一次
-
-### 测试场景覆盖
-
-| 场景类别 | 测试文件 | 测试数量 |
-|----------|----------|----------|
-| 基本读写 | JsonCfgTests, 各格式测试 | 47 |
-| 类型转换 | JsonCfgTests | 15 |
-| 编码检测 | EncodingDetectionTests | 14 |
-| 并发安全 | ConcurrencyTests | 10 |
-| 边界条件 | BoundaryConditionTests | 32 |
-| 异常处理 | ExceptionHandlingTests | 20 |
-| 动态重载 | DynamicReloadTests | 12 |
-| 变更订阅 | ConfigChangesSubscriptionTests | 28 |
-| 配置节访问 | CfgSectionTests | 14 |
-| 依赖注入 | ServiceCollectionExtensionsTests | 10 |
-
-### 测试覆盖率
-
-**100%** - 所有公开 API 均已覆盖测试
-
-### 多框架测试通过情况
-
-| 框架 | 测试数量 | 状态 | 测试日期 |
-|------|----------|------|----------|
-| .NET 6.0 | 199 | ✅ 全部通过 | 2025-12-25 |
-| .NET 8.0 | 199 | ✅ 全部通过 | 2025-12-25 |
-| .NET 9.0 | 199 | ✅ 全部通过 | 2025-12-25 |
+### 单元测试通过情况
+
+| 框架 | 测试数量 | 状态 |
+|------|----------|------|
+| .NET 6.0 | 199 | ✅ 全部通过 |
+| .NET 8.0 | 199 | ✅ 全部通过 |
+| .NET 9.0 | 199 | ✅ 全部通过 |
+
+> 详细测试覆盖情况见 [tests/README.md](tests/README.md)
 
 ## 性能测试结果
 
@@ -408,63 +324,6 @@ dotnet run -c Release
 
 > 性能测试运行方法见 [benchmarks/README.md](benchmarks/README.md)
 
-## 项目结构
-
-```text
-Apq.Cfg/
-├── Apq.Cfg/                     # 核心库(JSON + 环境变量)
-│   ├── ICfgRoot.cs              # 配置根接口
-│   ├── MergedCfgRoot.cs         # 合并配置根实现
-│   ├── CfgBuilder.cs            # 配置构建器
-│   ├── ICfgSection.cs           # 配置节接口
-│   ├── CfgSection.cs            # 配置节实现
-│   ├── CfgRootExtensions.cs     # 扩展方法
-│   ├── ServiceCollectionExtensions.cs  # DI 扩展
-│   ├── Changes/                 # 配置变更相关
-│   │   ├── ChangeType.cs
-│   │   ├── ConfigChange.cs
-│   │   ├── ConfigChangeEvent.cs
-│   │   ├── DynamicReloadOptions.cs
-│   │   ├── ReloadStrategy.cs
-│   │   └── ReloadErrorEvent.cs
-│   ├── EncodingSupport/         # 编码支持
-│   │   ├── EncodingDetector.cs      # 编码检测器
-│   │   ├── EncodingDetectionResult.cs
-│   │   ├── EncodingMapping.cs       # 编码映射规则
-│   │   └── EncodingOptions.cs       # 编码选项配置
-│   ├── Internal/                # 内部实现
-│   │   ├── ChangeCoordinator.cs
-│   │   ├── MergedConfigurationProvider.cs
-│   │   ├── MergedConfigurationSource.cs
-│   │   ├── ValueConverter.cs
-│   │   ├── ValueCache.cs
-│   │   ├── KeyPathParser.cs
-│   │   └── FastCollections.cs
-│   └── Sources/                 # 配置源
-│       ├── ICfgSource.cs
-│       ├── JsonFileCfgSource.cs
-│       ├── File/
-│       │   └── FileCfgSourceBase.cs
-│       └── Environment/
-│           └── EnvVarsCfgSource.cs
-├── Apq.Cfg.Ini/                 # INI 文件扩展
-├── Apq.Cfg.Xml/                 # XML 文件扩展
-├── Apq.Cfg.Yaml/                # YAML 文件扩展
-├── Apq.Cfg.Toml/                # TOML 文件扩展
-├── Apq.Cfg.Redis/               # Redis 扩展
-├── Apq.Cfg.Database/            # 数据库扩展
-├── Samples/                     # 示例项目
-├── tests/                       # 单元测试
-│   ├── Apq.Cfg.Tests.Shared/        # 共享测试代码
-│   ├── Apq.Cfg.Tests.Net6/          # .NET 6 测试
-│   ├── Apq.Cfg.Tests.Net8/          # .NET 8 测试
-│   └── Apq.Cfg.Tests.Net9/          # .NET 9 测试
-├── benchmarks/                  # 性能测试
-├── buildTools/                  # 构建工具脚本
-├── versions/                    # 版本文件目录
-└── nupkgs/                      # NuGet 包输出目录
-```
-
 ## 许可证
 
 MIT License

+ 124 - 0
tests/README.md

@@ -0,0 +1,124 @@
+# Apq.Cfg 测试
+
+本目录包含 Apq.Cfg 的单元测试项目。
+
+## 项目结构
+
+```text
+tests/
+├── Apq.Cfg.Tests.Shared/    # 共享测试代码
+├── Apq.Cfg.Tests.Net6/      # .NET 6 测试项目
+├── Apq.Cfg.Tests.Net8/      # .NET 8 测试项目
+└── Apq.Cfg.Tests.Net9/      # .NET 9 测试项目
+```
+
+## 运行测试
+
+```bash
+# 运行所有测试
+dotnet test
+
+# 运行特定框架的测试
+dotnet test tests/Apq.Cfg.Tests.Net9/
+
+# 运行特定测试类
+dotnet test --filter "FullyQualifiedName~JsonCfgTests"
+```
+
+## 测试统计(共 199 个测试)
+
+| 测试类 | 测试数量 | 说明 |
+|--------|----------|------|
+| JsonCfgTests | 15 | JSON 配置源测试 |
+| EnvVarsCfgTests | 4 | 环境变量配置源测试 |
+| IniCfgTests | 5 | INI 文件配置源测试 |
+| XmlCfgTests | 5 | XML 文件配置源测试 |
+| YamlCfgTests | 6 | YAML 文件配置源测试 |
+| TomlCfgTests | 6 | TOML 文件配置源测试 |
+| RedisCfgTests | 5 | Redis 配置源测试 |
+| DatabaseCfgTests | 5 | 数据库配置源测试 |
+| CfgRootExtensionsTests | 4 | 扩展方法测试 |
+| CfgBuilderAdvancedTests | 14 | 高级功能测试 |
+| DynamicReloadTests | 12 | 动态配置重载测试 |
+| EncodingDetectionTests | 14 | 编码检测测试 |
+| ConcurrencyTests | 10 | 并发安全测试 |
+| BoundaryConditionTests | 32 | 边界条件测试 |
+| ExceptionHandlingTests | 20 | 异常处理测试 |
+| ConfigChangesSubscriptionTests | 28 | 配置变更订阅测试 |
+| CfgSectionTests | 14 | 配置节(GetSection/GetChildKeys)测试 |
+| ServiceCollectionExtensionsTests | 10 | 依赖注入扩展测试 |
+| EncodingTests | 14 | 编码映射测试 |
+
+## 公开 API 覆盖矩阵
+
+| API | Json | Env | Ini | Xml | Yaml | Toml | Redis | DB |
+|-----|:----:|:---:|:---:|:---:|:----:|:----:|:-----:|:--:|
+| **ICfgRoot** |
+| `Get(key)` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
+| `Get<T>(key)` | ✅ | - | ✅ | ✅ | ✅ | ✅ | - | - |
+| `Exists(key)` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
+| `GetMany(keys)` | ✅ | - | - | - | - | - | - | - |
+| `GetMany<T>(keys)` | ✅ | - | - | - | - | - | - | - |
+| `Set(key, value)` | ✅ | - | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
+| `SetMany(values)` | ✅ | - | - | - | - | - | - | - |
+| `Set(key, value, targetLevel)` | ✅ | - | - | - | - | - | - | - |
+| `Remove(key)` | ✅ | - | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
+| `Remove(key, targetLevel)` | ✅ | - | - | - | - | - | - | - |
+| `SaveAsync()` | ✅ | - | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
+| `SaveAsync(targetLevel)` | ✅ | - | - | - | - | - | - | - |
+| `ToMicrosoftConfiguration()` | ✅ | - | - | - | - | - | - | - |
+| `ToMicrosoftConfiguration(options)` | ✅ | - | - | - | - | - | - | - |
+| `ConfigChanges` | ✅ | - | - | - | - | - | - | - |
+| `GetSection(path)` | ✅ | - | ✅ | ✅ | ✅ | ✅ | - | - |
+| `GetChildKeys()` | ✅ | - | ✅ | ✅ | ✅ | ✅ | - | - |
+| `Dispose/DisposeAsync` | ✅ | - | - | - | - | - | - | - |
+| **CfgBuilder** |
+| `AddJson()` | ✅ | - | - | - | - | - | - | - |
+| `AddEnvironmentVariables()` | - | ✅ | - | - | - | - | - | - |
+| `AddSource()` | ✅ | - | - | - | - | - | - | - |
+| `WithEncodingConfidenceThreshold()` | ✅ | - | - | - | - | - | - | - |
+| `AddReadEncodingMapping()` | ✅ | - | - | - | - | - | - | - |
+| `AddWriteEncodingMapping()` | ✅ | - | - | - | - | - | - | - |
+| `ConfigureEncodingMapping()` | ✅ | - | - | - | - | - | - | - |
+| `WithEncodingDetectionLogging()` | ✅ | - | - | - | - | - | - | - |
+| `Build()` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
+| **CfgRootExtensions** |
+| `TryGet<T>()` | ✅ | - | - | - | - | - | - | - |
+| `GetRequired<T>()` | ✅ | - | - | - | - | - | - | - |
+| **FileCfgSourceBase** |
+| `EncodingDetector` | ✅ | - | - | - | - | - | - | - |
+| `EncodingConfidenceThreshold` | ✅ | - | - | - | - | - | - | - |
+| **扩展包** |
+| `AddIni()` | - | - | ✅ | - | - | - | - | - |
+| `AddXml()` | - | - | - | ✅ | - | - | - | - |
+| `AddYaml()` | - | - | - | - | ✅ | - | - | - |
+| `AddToml()` | - | - | - | - | - | ✅ | - | - |
+| `AddRedis()` | - | - | - | - | - | - | ✅ | - |
+| `AddDatabase()` | - | - | - | - | - | - | - | ✅ |
+| **依赖注入扩展** |
+| `AddApqCfg()` | ✅ | - | - | - | - | - | - | - |
+| `ConfigureApqCfg<T>()` | ✅ | - | - | - | - | - | - | - |
+| **多层级覆盖** |
+| 高层级覆盖低层级 | ✅ | ✅ | - | - | - | - | ✅ | ✅ |
+
+> 说明:`-` 表示该配置源不支持此功能(如环境变量只读)或该功能只需测试一次
+
+## 测试场景覆盖
+
+| 场景类别 | 测试文件 | 测试数量 |
+|----------|----------|----------|
+| 基本读写 | JsonCfgTests, 各格式测试 | 47 |
+| 类型转换 | JsonCfgTests | 15 |
+| 编码检测 | EncodingDetectionTests | 14 |
+| 编码映射 | EncodingTests | 14 |
+| 并发安全 | ConcurrencyTests | 10 |
+| 边界条件 | BoundaryConditionTests | 32 |
+| 异常处理 | ExceptionHandlingTests | 20 |
+| 动态重载 | DynamicReloadTests | 12 |
+| 变更订阅 | ConfigChangesSubscriptionTests | 28 |
+| 配置节访问 | CfgSectionTests | 14 |
+| 依赖注入 | ServiceCollectionExtensionsTests | 10 |
+
+## 测试覆盖率
+
+**100%** - 所有公开 API 均已覆盖测试