1+ /**
2+ * File Metadata Inheritance Settings Tests
3+ *
4+ * Tests for settings integration and configuration migration
5+ */
6+
7+ import { DEFAULT_SETTINGS , FileMetadataInheritanceConfig } from "../common/setting-definition" ;
8+ import TaskProgressBarPlugin from "../index" ;
9+
10+ // Mock Obsidian API
11+ const mockPlugin = {
12+ settings : { ...DEFAULT_SETTINGS } ,
13+ loadData : jest . fn ( ) ,
14+ saveData : jest . fn ( ) ,
15+ migrateInheritanceSettings : jest . fn ( ) ,
16+ } as any ;
17+
18+ describe ( "File Metadata Inheritance Settings" , ( ) => {
19+ beforeEach ( ( ) => {
20+ jest . clearAllMocks ( ) ;
21+ mockPlugin . settings = { ...DEFAULT_SETTINGS } ;
22+ } ) ;
23+
24+ describe ( "Default Configuration" , ( ) => {
25+ test ( "should have correct default values" , ( ) => {
26+ const defaultConfig = DEFAULT_SETTINGS . fileMetadataInheritance ;
27+
28+ expect ( defaultConfig ) . toBeDefined ( ) ;
29+ expect ( defaultConfig . enabled ) . toBe ( true ) ;
30+ expect ( defaultConfig . inheritFromFrontmatter ) . toBe ( true ) ;
31+ expect ( defaultConfig . inheritFromFrontmatterForSubtasks ) . toBe ( false ) ;
32+ } ) ;
33+
34+ test ( "should have FileMetadataInheritanceConfig interface" , ( ) => {
35+ const config : FileMetadataInheritanceConfig = {
36+ enabled : true ,
37+ inheritFromFrontmatter : true ,
38+ inheritFromFrontmatterForSubtasks : false ,
39+ } ;
40+
41+ expect ( config ) . toBeDefined ( ) ;
42+ expect ( typeof config . enabled ) . toBe ( "boolean" ) ;
43+ expect ( typeof config . inheritFromFrontmatter ) . toBe ( "boolean" ) ;
44+ expect ( typeof config . inheritFromFrontmatterForSubtasks ) . toBe ( "boolean" ) ;
45+ } ) ;
46+ } ) ;
47+
48+ describe ( "Configuration Migration" , ( ) => {
49+ test ( "should migrate old inheritance settings to new structure" , ( ) => {
50+ const savedData = {
51+ projectConfig : {
52+ metadataConfig : {
53+ metadataKey : "project" ,
54+ inheritFromFrontmatter : true ,
55+ inheritFromFrontmatterForSubtasks : true ,
56+ enabled : true ,
57+ } ,
58+ } ,
59+ // 没有新的fileMetadataInheritance配置
60+ } ;
61+
62+ // 模拟迁移逻辑
63+ const migrateInheritanceSettings = ( savedData : any ) => {
64+ if ( savedData ?. projectConfig ?. metadataConfig &&
65+ ! savedData ?. fileMetadataInheritance ) {
66+
67+ const oldConfig = savedData . projectConfig . metadataConfig ;
68+
69+ return {
70+ enabled : true ,
71+ inheritFromFrontmatter : oldConfig . inheritFromFrontmatter ?? true ,
72+ inheritFromFrontmatterForSubtasks : oldConfig . inheritFromFrontmatterForSubtasks ?? false
73+ } ;
74+ }
75+ return null ;
76+ } ;
77+
78+ const migratedConfig = migrateInheritanceSettings ( savedData ) ;
79+
80+ expect ( migratedConfig ) . not . toBeNull ( ) ;
81+ expect ( migratedConfig ?. enabled ) . toBe ( true ) ;
82+ expect ( migratedConfig ?. inheritFromFrontmatter ) . toBe ( true ) ;
83+ expect ( migratedConfig ?. inheritFromFrontmatterForSubtasks ) . toBe ( true ) ;
84+ } ) ;
85+
86+ test ( "should not migrate when new configuration already exists" , ( ) => {
87+ const savedData = {
88+ projectConfig : {
89+ metadataConfig : {
90+ metadataKey : "project" ,
91+ inheritFromFrontmatter : true ,
92+ inheritFromFrontmatterForSubtasks : true ,
93+ enabled : true ,
94+ } ,
95+ } ,
96+ fileMetadataInheritance : {
97+ enabled : false ,
98+ inheritFromFrontmatter : false ,
99+ inheritFromFrontmatterForSubtasks : false ,
100+ } ,
101+ } ;
102+
103+ // 模拟迁移逻辑
104+ const migrateInheritanceSettings = ( savedData : any ) => {
105+ if ( savedData ?. projectConfig ?. metadataConfig &&
106+ ! savedData ?. fileMetadataInheritance ) {
107+
108+ const oldConfig = savedData . projectConfig . metadataConfig ;
109+
110+ return {
111+ enabled : true ,
112+ inheritFromFrontmatter : oldConfig . inheritFromFrontmatter ?? true ,
113+ inheritFromFrontmatterForSubtasks : oldConfig . inheritFromFrontmatterForSubtasks ?? false
114+ } ;
115+ }
116+ return null ;
117+ } ;
118+
119+ const migratedConfig = migrateInheritanceSettings ( savedData ) ;
120+
121+ // 应该返回null,表示不需要迁移
122+ expect ( migratedConfig ) . toBeNull ( ) ;
123+ } ) ;
124+
125+ test ( "should handle missing old configuration gracefully" , ( ) => {
126+ const savedData = {
127+ // 没有projectConfig
128+ } ;
129+
130+ // 模拟迁移逻辑
131+ const migrateInheritanceSettings = ( savedData : any ) => {
132+ if ( savedData ?. projectConfig ?. metadataConfig &&
133+ ! savedData ?. fileMetadataInheritance ) {
134+
135+ const oldConfig = savedData . projectConfig . metadataConfig ;
136+
137+ return {
138+ enabled : true ,
139+ inheritFromFrontmatter : oldConfig . inheritFromFrontmatter ?? true ,
140+ inheritFromFrontmatterForSubtasks : oldConfig . inheritFromFrontmatterForSubtasks ?? false
141+ } ;
142+ }
143+ return null ;
144+ } ;
145+
146+ const migratedConfig = migrateInheritanceSettings ( savedData ) ;
147+
148+ // 应该返回null,表示没有需要迁移的配置
149+ expect ( migratedConfig ) . toBeNull ( ) ;
150+ } ) ;
151+ } ) ;
152+
153+ describe ( "Settings Validation" , ( ) => {
154+ test ( "should maintain type safety for FileMetadataInheritanceConfig" , ( ) => {
155+ const validConfig : FileMetadataInheritanceConfig = {
156+ enabled : true ,
157+ inheritFromFrontmatter : true ,
158+ inheritFromFrontmatterForSubtasks : false ,
159+ } ;
160+
161+ // TypeScript应该不会报错
162+ expect ( validConfig . enabled ) . toBe ( true ) ;
163+ expect ( validConfig . inheritFromFrontmatter ) . toBe ( true ) ;
164+ expect ( validConfig . inheritFromFrontmatterForSubtasks ) . toBe ( false ) ;
165+ } ) ;
166+
167+ test ( "should handle all boolean combinations" , ( ) => {
168+ const combinations = [
169+ { enabled : true , inheritFromFrontmatter : true , inheritFromFrontmatterForSubtasks : true } ,
170+ { enabled : true , inheritFromFrontmatter : true , inheritFromFrontmatterForSubtasks : false } ,
171+ { enabled : true , inheritFromFrontmatter : false , inheritFromFrontmatterForSubtasks : true } ,
172+ { enabled : true , inheritFromFrontmatter : false , inheritFromFrontmatterForSubtasks : false } ,
173+ { enabled : false , inheritFromFrontmatter : true , inheritFromFrontmatterForSubtasks : true } ,
174+ { enabled : false , inheritFromFrontmatter : true , inheritFromFrontmatterForSubtasks : false } ,
175+ { enabled : false , inheritFromFrontmatter : false , inheritFromFrontmatterForSubtasks : true } ,
176+ { enabled : false , inheritFromFrontmatter : false , inheritFromFrontmatterForSubtasks : false } ,
177+ ] ;
178+
179+ combinations . forEach ( config => {
180+ expect ( typeof config . enabled ) . toBe ( "boolean" ) ;
181+ expect ( typeof config . inheritFromFrontmatter ) . toBe ( "boolean" ) ;
182+ expect ( typeof config . inheritFromFrontmatterForSubtasks ) . toBe ( "boolean" ) ;
183+ } ) ;
184+ } ) ;
185+ } ) ;
186+
187+ describe ( "Integration with Main Settings" , ( ) => {
188+ test ( "should be properly integrated into TaskProgressBarSettings" , ( ) => {
189+ const settings = DEFAULT_SETTINGS ;
190+
191+ expect ( settings . fileMetadataInheritance ) . toBeDefined ( ) ;
192+ expect ( settings . fileMetadataInheritance . enabled ) . toBe ( true ) ;
193+ expect ( settings . fileMetadataInheritance . inheritFromFrontmatter ) . toBe ( true ) ;
194+ expect ( settings . fileMetadataInheritance . inheritFromFrontmatterForSubtasks ) . toBe ( false ) ;
195+ } ) ;
196+
197+ test ( "should work independently of project configuration" , ( ) => {
198+ const settingsWithoutProject = {
199+ ...DEFAULT_SETTINGS ,
200+ projectConfig : {
201+ ...DEFAULT_SETTINGS . projectConfig ,
202+ enableEnhancedProject : false ,
203+ } ,
204+ } ;
205+
206+ expect ( settingsWithoutProject . fileMetadataInheritance ) . toBeDefined ( ) ;
207+ expect ( settingsWithoutProject . fileMetadataInheritance . enabled ) . toBe ( true ) ;
208+ } ) ;
209+
210+ test ( "should work when project configuration is null" , ( ) => {
211+ const settingsWithNullProject = {
212+ ...DEFAULT_SETTINGS ,
213+ projectConfig : null as any ,
214+ } ;
215+
216+ expect ( settingsWithNullProject . fileMetadataInheritance ) . toBeDefined ( ) ;
217+ expect ( settingsWithNullProject . fileMetadataInheritance . enabled ) . toBe ( true ) ;
218+ } ) ;
219+ } ) ;
220+
221+ describe ( "Settings Persistence" , ( ) => {
222+ test ( "should preserve fileMetadataInheritance config during save/load" , ( ) => {
223+ const testSettings = {
224+ ...DEFAULT_SETTINGS ,
225+ fileMetadataInheritance : {
226+ enabled : false ,
227+ inheritFromFrontmatter : false ,
228+ inheritFromFrontmatterForSubtasks : true ,
229+ } ,
230+ } ;
231+
232+ // 模拟保存和加载
233+ const savedData = JSON . stringify ( testSettings ) ;
234+ const loadedSettings = JSON . parse ( savedData ) ;
235+
236+ expect ( loadedSettings . fileMetadataInheritance ) . toBeDefined ( ) ;
237+ expect ( loadedSettings . fileMetadataInheritance . enabled ) . toBe ( false ) ;
238+ expect ( loadedSettings . fileMetadataInheritance . inheritFromFrontmatter ) . toBe ( false ) ;
239+ expect ( loadedSettings . fileMetadataInheritance . inheritFromFrontmatterForSubtasks ) . toBe ( true ) ;
240+ } ) ;
241+
242+ test ( "should handle partial configuration updates" , ( ) => {
243+ const baseSettings = {
244+ ...DEFAULT_SETTINGS ,
245+ } ;
246+
247+ // 模拟部分更新
248+ const updatedSettings = {
249+ ...baseSettings ,
250+ fileMetadataInheritance : {
251+ ...baseSettings . fileMetadataInheritance ,
252+ enabled : false ,
253+ } ,
254+ } ;
255+
256+ expect ( updatedSettings . fileMetadataInheritance . enabled ) . toBe ( false ) ;
257+ expect ( updatedSettings . fileMetadataInheritance . inheritFromFrontmatter ) . toBe ( true ) ;
258+ expect ( updatedSettings . fileMetadataInheritance . inheritFromFrontmatterForSubtasks ) . toBe ( false ) ;
259+ } ) ;
260+ } ) ;
261+
262+ describe ( "Backward Compatibility" , ( ) => {
263+ test ( "should handle settings without fileMetadataInheritance gracefully" , ( ) => {
264+ const oldSettings = {
265+ ...DEFAULT_SETTINGS ,
266+ } ;
267+
268+ // 删除新字段模拟旧版本设置
269+ delete ( oldSettings as any ) . fileMetadataInheritance ;
270+
271+ // 合并默认设置应该恢复缺失的字段
272+ const mergedSettings = Object . assign ( { } , DEFAULT_SETTINGS , oldSettings ) ;
273+
274+ expect ( mergedSettings . fileMetadataInheritance ) . toBeDefined ( ) ;
275+ expect ( mergedSettings . fileMetadataInheritance . enabled ) . toBe ( true ) ;
276+ } ) ;
277+
278+ test ( "should maintain project config structure after migration" , ( ) => {
279+ const oldProjectConfig = {
280+ enableEnhancedProject : true ,
281+ pathMappings : [ ] ,
282+ metadataConfig : {
283+ metadataKey : "project" ,
284+ inheritFromFrontmatter : true ,
285+ inheritFromFrontmatterForSubtasks : true ,
286+ enabled : true ,
287+ } ,
288+ configFile : {
289+ fileName : "project.md" ,
290+ searchRecursively : true ,
291+ enabled : true ,
292+ } ,
293+ metadataMappings : [ ] ,
294+ defaultProjectNaming : {
295+ strategy : "filename" as const ,
296+ stripExtension : true ,
297+ enabled : true ,
298+ } ,
299+ } ;
300+
301+ // 迁移后项目配置应该移除继承相关字段
302+ const migratedProjectConfig = {
303+ ...oldProjectConfig ,
304+ metadataConfig : {
305+ metadataKey : oldProjectConfig . metadataConfig . metadataKey ,
306+ enabled : oldProjectConfig . metadataConfig . enabled ,
307+ } ,
308+ } ;
309+
310+ expect ( migratedProjectConfig . metadataConfig . metadataKey ) . toBe ( "project" ) ;
311+ expect ( migratedProjectConfig . metadataConfig . enabled ) . toBe ( true ) ;
312+ expect ( ( migratedProjectConfig . metadataConfig as any ) . inheritFromFrontmatter ) . toBeUndefined ( ) ;
313+ expect ( ( migratedProjectConfig . metadataConfig as any ) . inheritFromFrontmatterForSubtasks ) . toBeUndefined ( ) ;
314+ } ) ;
315+ } ) ;
316+ } ) ;
0 commit comments