@@ -11,6 +11,7 @@ import (
1111 "time"
1212
1313 "github.com/sirupsen/logrus"
14+ "github.com/stretchr/testify/mock"
1415 "github.com/stretchr/testify/suite"
1516
1617 "github.com/mrz1836/go-broadcast/internal/config"
@@ -22,6 +23,7 @@ import (
2223// Test error variables
2324var (
2425 ErrGitTreeNotImplemented = errors .New ("git tree not implemented in mock" )
26+ ErrFileNotFound = errors .New ("file not found" )
2527)
2628
2729// DirectoryTransformTestSuite tests comprehensive directory transformation scenarios
@@ -1041,3 +1043,147 @@ func (m *DirectoryMockTransformChain) Transform(_ context.Context, content []byt
10411043
10421044 return []byte (result ), nil
10431045}
1046+
1047+ // DirectoryRealTransformChain provides a real transform chain for testing actual transformations
1048+ type DirectoryRealTransformChain struct {
1049+ transformers []transform.Transformer
1050+ }
1051+
1052+ // Add implements the Chain interface
1053+ func (m * DirectoryRealTransformChain ) Add (transformer transform.Transformer ) transform.Chain {
1054+ m .transformers = append (m .transformers , transformer )
1055+ return m
1056+ }
1057+
1058+ // Transformers implements the Chain interface
1059+ func (m * DirectoryRealTransformChain ) Transformers () []transform.Transformer {
1060+ if len (m .transformers ) == 0 {
1061+ // Initialize with the real repo transformer
1062+ m .transformers = append (m .transformers , transform .NewRepoTransformer ())
1063+ }
1064+ return m .transformers
1065+ }
1066+
1067+ // Transform implements the real Transform method using actual transformers
1068+ func (m * DirectoryRealTransformChain ) Transform (_ context.Context , content []byte , transformCtx transform.Context ) ([]byte , error ) {
1069+ result := content
1070+
1071+ // Apply all transformers in the chain
1072+ for _ , transformer := range m .Transformers () {
1073+ var err error
1074+ result , err = transformer .Transform (result , transformCtx )
1075+ if err != nil {
1076+ return nil , fmt .Errorf ("transformation failed with %s: %w" , transformer .Name (), err )
1077+ }
1078+ }
1079+
1080+ return result , nil
1081+ }
1082+
1083+ // TestVSCodeSettingsRealWorldTransformation tests the specific case reported
1084+ // where .vscode/settings.json wasn't being transformed correctly during sync
1085+ func (suite * DirectoryTransformTestSuite ) TestVSCodeSettingsRealWorldTransformation () {
1086+ ctx := context .Background ()
1087+
1088+ // Create a temporary source directory with .vscode/settings.json
1089+ tmpDir := suite .T ().TempDir ()
1090+ vscodeDir := filepath .Join (tmpDir , ".vscode" )
1091+ suite .Require ().NoError (os .MkdirAll (vscodeDir , 0o750 ))
1092+
1093+ // Write the exact content from the real .vscode/settings.json file
1094+ settingsContent := `{
1095+ "[go]": {
1096+ "editor.formatOnSave": true,
1097+ "editor.codeActionsOnSave": {
1098+ "source.organizeImports": "explicit"
1099+ }
1100+ },
1101+ "[go.mod]": {
1102+ "editor.formatOnSave": true,
1103+ "editor.codeActionsOnSave": {
1104+ "source.organizeImports": "explicit"
1105+ }
1106+ },
1107+ "go.useLanguageServer": true,
1108+ "gopls": {
1109+ "formatting.local": "github.com/mrz1836/go-broadcast",
1110+ "formatting.gofumpt": true
1111+ },
1112+ "go.lintTool": "golangci-lint",
1113+ "go.lintFlags": ["--verbose"],
1114+ "[go][go.mod]": {
1115+ "editor.codeActionsOnSave": {
1116+ "source.organizeImports": "explicit"
1117+ }
1118+ }
1119+ }`
1120+ settingsPath := filepath .Join (vscodeDir , "settings.json" )
1121+ suite .Require ().NoError (os .WriteFile (settingsPath , []byte (settingsContent ), 0o600 ))
1122+
1123+ // Configure the directory mapping for .vscode
1124+ dirMapping := config.DirectoryMapping {
1125+ Src : ".vscode" ,
1126+ Dest : ".vscode" ,
1127+ Transform : config.Transform {
1128+ RepoName : true ,
1129+ },
1130+ }
1131+
1132+ // Set up target config for go-pre-commit repository
1133+ targetConfig := config.TargetConfig {
1134+ Repo : "mrz1836/go-pre-commit" ,
1135+ Transform : config.Transform {
1136+ RepoName : true ,
1137+ },
1138+ }
1139+
1140+ sourceState := & state.SourceState {
1141+ Repo : "mrz1836/go-broadcast" ,
1142+ }
1143+
1144+ // Create a real engine with the actual repo transformer and a mock GitHub client
1145+ mockGHClient := gh .NewMockClient ()
1146+ // Configure mock to return "file not found" for any GetFile call so all files are treated as new
1147+ mockGHClient .On ("GetFile" , mock .Anything , mock .Anything , mock .Anything , mock .Anything ).Return ((* gh .FileContent )(nil ), ErrFileNotFound )
1148+
1149+ realEngine := & Engine {
1150+ transform : & DirectoryRealTransformChain {},
1151+ gh : mockGHClient ,
1152+ }
1153+
1154+ // Process the directory mapping
1155+ changes , err := suite .processor .ProcessDirectoryMapping (
1156+ ctx , tmpDir , dirMapping , targetConfig , sourceState , realEngine ,
1157+ )
1158+
1159+ suite .Require ().NoError (err )
1160+ suite .Require ().Len (changes , 1 , "Should have exactly one file change for settings.json" )
1161+
1162+ change := changes [0 ]
1163+ suite .Equal (".vscode/settings.json" , change .Path )
1164+
1165+ // Verify the transformation happened correctly
1166+ transformedContent := string (change .Content )
1167+ originalContent := string (change .OriginalContent )
1168+
1169+ // Key assertion: formatting.local should be transformed
1170+ suite .Contains (transformedContent , `"formatting.local": "github.com/mrz1836/go-pre-commit"` ,
1171+ "Should transform formatting.local to target repo" )
1172+ suite .NotContains (transformedContent , `"formatting.local": "github.com/mrz1836/go-broadcast"` ,
1173+ "Should not contain original repo in formatting.local" )
1174+
1175+ // Verify the original content contained the source repo
1176+ suite .Contains (originalContent , `"formatting.local": "github.com/mrz1836/go-broadcast"` ,
1177+ "Original content should contain source repo" )
1178+
1179+ // Verify no other content was changed (except the transformation)
1180+ suite .Contains (transformedContent , `"go.useLanguageServer": true` )
1181+ suite .Contains (transformedContent , `"go.lintTool": "golangci-lint"` )
1182+ suite .Contains (transformedContent , `"formatting.gofumpt": true` )
1183+
1184+ suite .logger .WithFields (logrus.Fields {
1185+ "original_length" : len (originalContent ),
1186+ "transformed_length" : len (transformedContent ),
1187+ "file_path" : change .Path ,
1188+ }).Info ("VSCode settings transformation test completed successfully" )
1189+ }
0 commit comments