11//! Patches the imports to use codspeed rather than the official "testing" package.
22
33use crate :: prelude:: * ;
4+ use itertools:: Itertools ;
45use rayon:: prelude:: * ;
56use std:: fs;
67use std:: path:: Path ;
@@ -71,19 +72,22 @@ pub fn patch_imports<P: AsRef<Path>>(folder: P) -> anyhow::Result<()> {
7172
7273/// Internal function to apply import patterns to Go source code
7374pub fn patch_imports_for_source ( source : & str ) -> String {
74- let replace_import = |mut source : String , import_path : & str , replacement : & str | -> String {
75+ let mut source = source. to_string ( ) ;
76+
77+ // If we can't parse the source, skip this replacement
78+ // This can happen with template files or malformed Go code
79+ let parsed = match gosyn:: parse_source ( & source) {
80+ Ok ( p) => p,
81+ Err ( _) => return source,
82+ } ;
83+
84+ let mut replacements = vec ! [ ] ;
85+ let mut find_replace_range = |import_path : & str , replacement : & str | {
7586 // Optimization: check if the import path exists in the source before parsing
7687 if !source. contains ( import_path) {
77- return source ;
88+ return ;
7889 }
7990
80- // If we can't parse the source, skip this replacement
81- // This can happen with template files or malformed Go code
82- let parsed = match gosyn:: parse_source ( & source) {
83- Ok ( p) => p,
84- Err ( _) => return source,
85- } ;
86-
8791 if let Some ( import) = parsed
8892 . imports
8993 . iter ( )
@@ -92,39 +96,43 @@ pub fn patch_imports_for_source(source: &str) -> String {
9296 let start_pos = import. path . pos ;
9397 let end_pos = start_pos + import. path . value . len ( ) ;
9498
95- source . replace_range ( start_pos..end_pos, replacement) ;
99+ replacements . push ( ( start_pos..end_pos, replacement. to_string ( ) ) ) ;
96100 }
97-
98- source
99101 } ;
100102
101- let mut source = replace_import (
102- source. to_string ( ) ,
103- "testing" ,
104- "testing \" github.com/CodSpeedHQ/codspeed-go/testing/testing\" " ,
105- ) ;
106-
107103 // Then replace sub-packages like "testing/synctest"
108104 for testing_pkg in & [ "fstest" , "iotest" , "quick" , "slogtest" , "synctest" ] {
109- source = replace_import (
110- source. to_string ( ) ,
105+ find_replace_range (
111106 & format ! ( "testing/{}" , testing_pkg) ,
112107 & format ! (
113108 "{testing_pkg} \" github.com/CodSpeedHQ/codspeed-go/testing/testing/{testing_pkg}\" "
114109 ) ,
115110 ) ;
116111 }
117112
118- let source = replace_import (
119- source,
113+ find_replace_range (
114+ "testing" ,
115+ "testing \" github.com/CodSpeedHQ/codspeed-go/testing/testing\" " ,
116+ ) ;
117+ find_replace_range (
120118 "github.com/thejerf/slogassert" ,
121119 "\" github.com/CodSpeedHQ/codspeed-go/pkg/slogassert\" " ,
122120 ) ;
123- replace_import (
124- source,
121+ find_replace_range (
125122 "github.com/frankban/quicktest" ,
126123 "\" github.com/CodSpeedHQ/codspeed-go/pkg/quicktest\" " ,
127- )
124+ ) ;
125+
126+ // Apply replacements in reverse order to avoid shifting positions
127+ for ( range, replacement) in replacements
128+ . into_iter ( )
129+ . sorted_by_key ( |( range, _) | range. start )
130+ . rev ( )
131+ {
132+ source. replace_range ( range, & replacement) ;
133+ }
134+
135+ source
128136}
129137
130138/// Patches imports and package in specific test files
@@ -390,6 +398,17 @@ func BenchmarkExample(b *testing.B) {
390398func TestExample(t *testing.T) {
391399 s := "package main"
392400}
401+ "# ;
402+
403+ const MANY_TESTING_IMPORTS : & str = r#"package subpackages
404+ import (
405+ "bytes"
406+ "io"
407+ "testing"
408+ "testing/fstest"
409+ "testing/iotest"
410+ "testing/synctest"
411+ )
393412"# ;
394413
395414 #[ rstest]
@@ -408,6 +427,7 @@ func TestExample(t *testing.T) {
408427 MULTILINE_IMPORT_WITH_TESTING_STRING
409428 ) ]
410429 #[ case( "package_main" , PACKAGE_MAIN ) ]
430+ #[ case( "many_testing_imports" , MANY_TESTING_IMPORTS ) ]
411431 fn test_patch_go_source ( #[ case] test_name : & str , #[ case] source : & str ) {
412432 let result = patch_imports_for_source ( source) ;
413433 let result = patch_package_for_source ( result) . unwrap ( ) ;
0 commit comments