1+ import * as fs from 'fs-extra' ;
2+ import * as path from 'path' ;
3+ import {
4+ afterDiflow ,
5+ beforeDiflow ,
6+ checkStateInConfig ,
7+ createTestCommit ,
8+ createTestCommitCore ,
9+ getTestRepoPath ,
10+ initTestRepos ,
11+ } from './testrepo' ;
12+ import { Processor } from './processor' ;
13+ import { execAsync } from './tools' ;
14+
15+ describe ( 'processMergedFile tests' , ( ) => {
16+ beforeEach ( async ( ) => {
17+ await initTestRepos ( ) ;
18+ } ) ;
19+
20+ test ( 'New file with default target (diff)' , async ( ) => {
21+ await createTestCommit ( getTestRepoPath ( 'merged' ) , 'default-target.txt' , 'default target content' , 'merged' ) ;
22+
23+ await beforeDiflow ( ) ;
24+
25+ const processor = new Processor ( getTestRepoPath ( 'config' ) , path . join ( __dirname , 'workrepos' ) , 'master' ) ;
26+ await processor . process ( ) ;
27+
28+ await afterDiflow ( ) ;
29+
30+ await checkStateInConfig ( ) ;
31+
32+ // Should be copied to diff by default
33+ expect ( await fs . exists ( path . join ( getTestRepoPath ( 'diff' ) , 'default-target.txt' ) ) ) . toBe ( true ) ;
34+ expect ( await fs . exists ( path . join ( getTestRepoPath ( 'base' ) , 'default-target.txt' ) ) ) . toBe ( false ) ;
35+
36+ const diffContent = await fs . readFile ( path . join ( getTestRepoPath ( 'diff' ) , 'default-target.txt' ) , 'utf8' ) ;
37+ expect ( diffContent ) . toBe ( 'default target content' ) ;
38+ } ) ;
39+
40+ test ( 'New file with base identifier match by name pattern' , async ( ) => {
41+ // Create a file in base-folder which should match the base identifier pattern
42+ await createTestCommit ( getTestRepoPath ( 'merged' ) , 'base-folder/new-base-file.txt' , 'new base file content' , 'merged' ) ;
43+
44+ await beforeDiflow ( ) ;
45+
46+ const processor = new Processor ( getTestRepoPath ( 'config' ) , path . join ( __dirname , 'workrepos' ) , 'master' ) ;
47+ await processor . process ( ) ;
48+
49+ await afterDiflow ( ) ;
50+
51+ await checkStateInConfig ( ) ;
52+
53+ // Should be copied to base based on identifier pattern match
54+ expect ( await fs . exists ( path . join ( getTestRepoPath ( 'base' ) , 'base-folder/new-base-file.txt' ) ) ) . toBe ( true ) ;
55+ expect ( await fs . exists ( path . join ( getTestRepoPath ( 'diff' ) , 'base-folder/new-base-file.txt' ) ) ) . toBe ( false ) ;
56+
57+ const baseContent = await fs . readFile ( path . join ( getTestRepoPath ( 'base' ) , 'base-folder/new-base-file.txt' ) , 'utf8' ) ;
58+ expect ( baseContent ) . toBe ( 'new base file content' ) ;
59+ } ) ;
60+
61+ test ( 'New file with content-based identifier match' , async ( ) => {
62+ // Create a config with content-based identifier
63+ const configPath = path . join ( getTestRepoPath ( 'config' ) , 'config.json' ) ;
64+ const config = JSON . parse ( await fs . readFile ( configPath , 'utf8' ) ) ;
65+ config . repos . base . identifiers . push ( { content : 'BASE_CONTENT_MARKER' } ) ;
66+ await fs . writeFile ( configPath , JSON . stringify ( config , null , 2 ) ) ;
67+ await createTestCommitCore ( getTestRepoPath ( 'config' ) , 'config' , 'Add content-based identifier' ) ;
68+
69+ // Create a file containing the marker in the merged repo
70+ await createTestCommit (
71+ getTestRepoPath ( 'merged' ) ,
72+ 'content-marker-file.txt' ,
73+ 'This file contains a BASE_CONTENT_MARKER to identify it belongs to base' ,
74+ 'merged'
75+ ) ;
76+
77+ // Create the same file in the diff repo for matchIdentifiers to work
78+ // This is needed because matchIdentifiers checks the file in the diff repo, not merged
79+ await createTestCommit (
80+ getTestRepoPath ( 'diff' ) ,
81+ 'content-marker-file.txt' ,
82+ 'This file contains a BASE_CONTENT_MARKER to identify it belongs to base' ,
83+ 'diff'
84+ ) ;
85+
86+ await beforeDiflow ( ) ;
87+
88+ const processor = new Processor ( getTestRepoPath ( 'config' ) , path . join ( __dirname , 'workrepos' ) , 'master' ) ;
89+ await processor . process ( ) ;
90+
91+ await afterDiflow ( ) ;
92+
93+ await checkStateInConfig ( ) ;
94+
95+ // Should be copied to base based on content identifier match
96+ expect ( await fs . exists ( path . join ( getTestRepoPath ( 'base' ) , 'content-marker-file.txt' ) ) ) . toBe ( true ) ;
97+ } ) ;
98+
99+ test ( 'New file with custom newFilesTargetDefault setting' , async ( ) => {
100+ // Modify config to set default target to base
101+ const configPath = path . join ( getTestRepoPath ( 'config' ) , 'config.json' ) ;
102+ const config = JSON . parse ( await fs . readFile ( configPath , 'utf8' ) ) ;
103+ config . newFilesTargetDefault = 'base' ;
104+ await fs . writeFile ( configPath , JSON . stringify ( config , null , 2 ) ) ;
105+ await createTestCommitCore ( getTestRepoPath ( 'config' ) , 'config' , 'Set default target to base' ) ;
106+
107+ // Create a new file
108+ await createTestCommit ( getTestRepoPath ( 'merged' ) , 'default-base-target.txt' , 'should go to base by default' , 'merged' ) ;
109+
110+ await beforeDiflow ( ) ;
111+
112+ const processor = new Processor ( getTestRepoPath ( 'config' ) , path . join ( __dirname , 'workrepos' ) , 'master' ) ;
113+ await processor . process ( ) ;
114+
115+ await afterDiflow ( ) ;
116+
117+ await checkStateInConfig ( ) ;
118+
119+ // Should be copied to base due to changed default
120+ expect ( await fs . exists ( path . join ( getTestRepoPath ( 'base' ) , 'default-base-target.txt' ) ) ) . toBe ( true ) ;
121+ expect ( await fs . exists ( path . join ( getTestRepoPath ( 'diff' ) , 'default-base-target.txt' ) ) ) . toBe ( false ) ;
122+ } ) ;
123+
124+ test ( 'Modified file that exists in diff repo' , async ( ) => {
125+ // First create a file in diff and merged repos
126+ await createTestCommit ( getTestRepoPath ( 'diff' ) , 'diff-modify-test.txt' , 'original content' , 'diff' ) ;
127+ await createTestCommit ( getTestRepoPath ( 'merged' ) , 'diff-modify-test.txt' , 'original content' , 'merged' ) ;
128+
129+ // Now modify the file in merged
130+ await fs . writeFile ( path . join ( getTestRepoPath ( 'merged' ) , 'diff-modify-test.txt' ) , 'modified content' ) ;
131+ await createTestCommitCore ( getTestRepoPath ( 'merged' ) , 'merged' , 'Modify diff-modify-test.txt' ) ;
132+
133+ await beforeDiflow ( ) ;
134+
135+ const processor = new Processor ( getTestRepoPath ( 'config' ) , path . join ( __dirname , 'workrepos' ) , 'master' ) ;
136+ await processor . process ( ) ;
137+
138+ await afterDiflow ( ) ;
139+
140+ await checkStateInConfig ( ) ;
141+
142+ // Should be updated in diff repo
143+ const diffContent = await fs . readFile ( path . join ( getTestRepoPath ( 'diff' ) , 'diff-modify-test.txt' ) , 'utf8' ) ;
144+ expect ( diffContent ) . toBe ( 'modified content' ) ;
145+ } ) ;
146+
147+ test ( 'Modified file - verification of existing behavior for base-only files' , async ( ) => {
148+ // First create a file in base and merged repos
149+ await createTestCommit ( getTestRepoPath ( 'base' ) , 'base-modify-test.txt' , 'original base content' , 'base' ) ;
150+ await createTestCommit ( getTestRepoPath ( 'merged' ) , 'base-modify-test.txt' , 'original base content' , 'merged' ) ;
151+
152+ // Now modify the file in merged
153+ await fs . writeFile ( path . join ( getTestRepoPath ( 'merged' ) , 'base-modify-test.txt' ) , 'modified base content' ) ;
154+ await createTestCommitCore ( getTestRepoPath ( 'merged' ) , 'merged' , 'Modify base-modify-test.txt' ) ;
155+
156+ await beforeDiflow ( ) ;
157+
158+ const processor = new Processor ( getTestRepoPath ( 'config' ) , path . join ( __dirname , 'workrepos' ) , 'master' ) ;
159+ await processor . process ( ) ;
160+
161+ await afterDiflow ( ) ;
162+
163+ await checkStateInConfig ( ) ;
164+
165+ // The current implementation doesn't update files in base when they don't exist in diff
166+ // This is a limitation in the current implementation of processMergedFile
167+ const baseContent = await fs . readFile ( path . join ( getTestRepoPath ( 'base' ) , 'base-modify-test.txt' ) , 'utf8' ) ;
168+ expect ( baseContent ) . toBe ( 'original base content' ) ; // Reflects current behavior
169+
170+ // The current implementation in processMergedFile checks repoFileExists in diff first,
171+ // and if the file doesn't exist there, it tries to copy to base anyway.
172+ // Since the file was created in the workrepos/diff during processing, the changes get copied there.
173+ const diffExists = await fs . exists ( path . join ( getTestRepoPath ( 'diff' ) , 'base-modify-test.txt' ) ) ;
174+ expect ( diffExists ) . toBe ( true ) ;
175+
176+ // And the content there should be the modified content
177+ if ( diffExists ) {
178+ const diffContent = await fs . readFile ( path . join ( getTestRepoPath ( 'diff' ) , 'base-modify-test.txt' ) , 'utf8' ) ;
179+ expect ( diffContent ) . toBe ( 'modified base content' ) ;
180+ }
181+ } ) ;
182+
183+ test ( 'Delete file from merged repo' , async ( ) => {
184+ // First create files in all repos
185+ await createTestCommit ( getTestRepoPath ( 'base' ) , 'delete-test.txt' , 'delete me content' , 'base' ) ;
186+ await createTestCommit ( getTestRepoPath ( 'diff' ) , 'delete-test.txt' , 'delete me content' , 'diff' ) ;
187+ await createTestCommit ( getTestRepoPath ( 'merged' ) , 'delete-test.txt' , 'delete me content' , 'merged' ) ;
188+
189+ // Delete from merged
190+ await fs . unlink ( path . join ( getTestRepoPath ( 'merged' ) , 'delete-test.txt' ) ) ;
191+ await execAsync ( 'git add .' , { cwd : getTestRepoPath ( 'merged' ) } ) ;
192+ await execAsync ( 'git commit -m "Delete delete-test.txt"' , { cwd : getTestRepoPath ( 'merged' ) } ) ;
193+
194+ await beforeDiflow ( ) ;
195+
196+ const processor = new Processor ( getTestRepoPath ( 'config' ) , path . join ( __dirname , 'workrepos' ) , 'master' ) ;
197+ await processor . process ( ) ;
198+
199+ await afterDiflow ( ) ;
200+
201+ await checkStateInConfig ( ) ;
202+
203+ // Should be deleted from both base and diff repos
204+ expect ( await fs . exists ( path . join ( getTestRepoPath ( 'base' ) , 'delete-test.txt' ) ) ) . toBe ( false ) ;
205+ expect ( await fs . exists ( path . join ( getTestRepoPath ( 'diff' ) , 'delete-test.txt' ) ) ) . toBe ( false ) ;
206+ } ) ;
207+
208+ test ( 'Rename file in merged repo where original exists in diff repo' , async ( ) => {
209+ // First create a file in diff and merged repos
210+ await createTestCommit ( getTestRepoPath ( 'diff' ) , 'diff-rename-test.txt' , 'rename me content diff' , 'diff' ) ;
211+ await createTestCommit ( getTestRepoPath ( 'merged' ) , 'diff-rename-test.txt' , 'rename me content diff' , 'merged' ) ;
212+
213+ // Rename in merged
214+ await fs . rename (
215+ path . join ( getTestRepoPath ( 'merged' ) , 'diff-rename-test.txt' ) ,
216+ path . join ( getTestRepoPath ( 'merged' ) , 'diff-renamed.txt' )
217+ ) ;
218+ await execAsync ( 'git add .' , { cwd : getTestRepoPath ( 'merged' ) } ) ;
219+ await execAsync ( 'git commit -m "Rename diff-rename-test.txt to diff-renamed.txt"' , { cwd : getTestRepoPath ( 'merged' ) } ) ;
220+
221+ await beforeDiflow ( ) ;
222+
223+ const processor = new Processor ( getTestRepoPath ( 'config' ) , path . join ( __dirname , 'workrepos' ) , 'master' ) ;
224+ await processor . process ( ) ;
225+
226+ await afterDiflow ( ) ;
227+
228+ await checkStateInConfig ( ) ;
229+
230+ // Should be renamed in diff repo
231+ expect ( await fs . exists ( path . join ( getTestRepoPath ( 'diff' ) , 'diff-rename-test.txt' ) ) ) . toBe ( false ) ;
232+ expect ( await fs . exists ( path . join ( getTestRepoPath ( 'diff' ) , 'diff-renamed.txt' ) ) ) . toBe ( true ) ;
233+
234+ const diffContent = await fs . readFile ( path . join ( getTestRepoPath ( 'diff' ) , 'diff-renamed.txt' ) , 'utf8' ) ;
235+ expect ( diffContent ) . toBe ( 'rename me content diff' ) ;
236+ } ) ;
237+
238+ test ( 'Rename file - verification of existing behavior for base-only files' , async ( ) => {
239+ // First create a file in base and merged repos, but not in diff
240+ await createTestCommit ( getTestRepoPath ( 'base' ) , 'base-rename-test.txt' , 'rename me content base' , 'base' ) ;
241+ await createTestCommit ( getTestRepoPath ( 'merged' ) , 'base-rename-test.txt' , 'rename me content base' , 'merged' ) ;
242+
243+ // Rename in merged
244+ await fs . rename (
245+ path . join ( getTestRepoPath ( 'merged' ) , 'base-rename-test.txt' ) ,
246+ path . join ( getTestRepoPath ( 'merged' ) , 'base-renamed.txt' )
247+ ) ;
248+ await execAsync ( 'git add -A' , { cwd : getTestRepoPath ( 'merged' ) } ) ;
249+ await execAsync ( 'git commit -m "Rename base-rename-test.txt to base-renamed.txt"' , { cwd : getTestRepoPath ( 'merged' ) } ) ;
250+
251+ await beforeDiflow ( ) ;
252+
253+ const processor = new Processor ( getTestRepoPath ( 'config' ) , path . join ( __dirname , 'workrepos' ) , 'master' ) ;
254+ await processor . process ( ) ;
255+
256+ await afterDiflow ( ) ;
257+
258+ await checkStateInConfig ( ) ;
259+
260+ // The current implementation only renames files in the diff repo, not in base
261+ // This reflects the current behavior of processMergedFile which checks diff repo first
262+ expect ( await fs . exists ( path . join ( getTestRepoPath ( 'base' ) , 'base-rename-test.txt' ) ) ) . toBe ( true ) ; // Original file still exists
263+ expect ( await fs . exists ( path . join ( getTestRepoPath ( 'base' ) , 'base-renamed.txt' ) ) ) . toBe ( false ) ; // New file not created
264+
265+ // Check if the file exists in diff repo (it gets created there since file doesn't exist in diff)
266+ expect ( await fs . exists ( path . join ( getTestRepoPath ( 'diff' ) , 'base-renamed.txt' ) ) ) . toBe ( true ) ;
267+
268+ const diffContent = await fs . readFile ( path . join ( getTestRepoPath ( 'diff' ) , 'base-renamed.txt' ) , 'utf8' ) ;
269+ expect ( diffContent ) . toBe ( 'rename me content base' ) ;
270+ } ) ;
271+ } ) ;
0 commit comments