@@ -96,8 +96,139 @@ impl TestConfig {
9696 }
9797}
9898
99+ /// Checks if the MySQL server at the given host:port is above the specified major.minor version.
100+ /// Uses `docker exec` to query the version. Returns true if version cannot be determined.
101+ pub fn is_mysql_version_above ( db_host : & str , db_port : i32 , major : u32 , minor : u32 ) -> bool {
102+ let output = std:: process:: Command :: new ( "docker" )
103+ . args ( [ "exec" , "sqlx-ts-mysql-1" , "mysql" , "-u" , "root" , "-N" , "-e" , "SELECT VERSION();" ] )
104+ . output ( ) ;
105+ match output {
106+ Ok ( out) => {
107+ let version = String :: from_utf8_lossy ( & out. stdout ) ;
108+ let version = version. trim ( ) ;
109+ let parts: Vec < & str > = version. split ( '.' ) . collect ( ) ;
110+ if parts. len ( ) >= 2 {
111+ let srv_major: u32 = parts[ 0 ] . parse ( ) . unwrap_or ( 0 ) ;
112+ let srv_minor: u32 = parts[ 1 ] . parse ( ) . unwrap_or ( 0 ) ;
113+ srv_major > major || ( srv_major == major && srv_minor > minor)
114+ } else {
115+ true
116+ }
117+ }
118+ Err ( _) => true ,
119+ }
120+ }
121+
99122#[ macro_export]
100123macro_rules! run_test {
124+ // Arm with minimum MySQL version requirement: (major, minor)
125+ ( $( $name: ident, $test_config: expr, $ts_content: expr, $generated_types: expr, min_mysql: ( $maj: expr, $min: expr) ) * ) => {
126+ $(
127+ #[ test]
128+ fn $name( ) -> Result <( ) , Box <dyn std:: error:: Error >> {
129+ use assert_cmd:: cargo:: cargo_bin_cmd;
130+ let ts_content = $ts_content;
131+ let test_config: TestConfig = $test_config;
132+
133+ // Check minimum MySQL version requirement
134+ if test_config. db_type == "mysql" {
135+ if !test_utils:: sandbox:: is_mysql_version_above( & test_config. db_host, test_config. db_port, $maj, $min) {
136+ eprintln!( "Skipping test {}: requires MySQL > {}.{}" , stringify!( $name) , $maj, $min) ;
137+ return Ok ( ( ) ) ;
138+ }
139+ }
140+
141+ println!( "checking test config {:?}" , test_config) ;
142+ let file_extension = test_config. file_extension;
143+ let db_type = test_config. db_type;
144+ let db_host = test_config. db_host;
145+ let db_port = test_config. db_port;
146+ let db_user = test_config. db_user;
147+ let db_pass = test_config. db_pass;
148+ let db_name = test_config. db_name;
149+ let config_file_name = test_config. config_file_name;
150+ let generate_path = test_config. generate_path;
151+
152+ // SETUP
153+ let dir = tempdir( ) ?;
154+ let parent_path = dir. path( ) ;
155+ let file_path = parent_path. join( format!( "index.{file_extension}" ) ) ;
156+
157+ let mut temp_file = fs:: File :: create( & file_path) ?;
158+ writeln!( temp_file, "{}" , ts_content) ?;
159+ let file_result = fs:: read_to_string( & file_path) ?;
160+
161+ // EXECUTE
162+ let mut cmd = cargo_bin_cmd!( "sqlx-ts" ) ;
163+
164+ cmd. arg( parent_path. to_str( ) . unwrap( ) )
165+ . arg( format!( "--ext={file_extension}" ) )
166+ . arg( format!( "--db-type={db_type}" ) )
167+ . arg( format!( "--db-host={db_host}" ) )
168+ . arg( format!( "--db-port={db_port}" ) )
169+ . arg( format!( "--db-user={db_user}" ) )
170+ . arg( format!( "--db-name={db_name}" ) ) ;
171+
172+ if & generate_path. is_some( ) == & true {
173+ let generate_path = generate_path. clone( ) ;
174+ let generate_path = generate_path. unwrap( ) ;
175+ let generate_path = generate_path. as_path( ) ;
176+ let generate_path = parent_path. join( generate_path) ;
177+ let generate_path = generate_path. display( ) ;
178+ cmd. arg( format!( "--generate-path={generate_path}" ) ) ;
179+ }
180+
181+ if ( test_config. generate_types) {
182+ cmd. arg( "-g" ) ;
183+ }
184+
185+ if ( config_file_name. is_some( ) ) {
186+ let cwd = env:: current_dir( ) ?;
187+ let config_file_name = format!( "{}" , config_file_name. unwrap( ) ) ;
188+ let config_path = cwd. join( format!( "tests/configs/{config_file_name}" ) ) ;
189+ let config_path = config_path. display( ) ;
190+ cmd. arg( format!( "--config={config_path}" ) ) ;
191+ }
192+
193+ if ( db_pass. is_some( ) ) {
194+ let db_pass = db_pass. unwrap( ) ;
195+ cmd. arg( format!( "--db-pass={db_pass}" ) ) ;
196+ } else {
197+ cmd. arg( "--db-pass=" ) ;
198+ }
199+
200+ cmd. assert( )
201+ . success( )
202+ . stdout( predicates:: str :: contains( "No SQL errors detected!" ) ) ;
203+
204+ let generated_types: & str = $generated_types. clone( ) ;
205+
206+ if generate_path. is_some( ) {
207+ let generate_path = parent_path. join( generate_path. unwrap( ) . as_path( ) ) ;
208+ let type_file = fs:: read_to_string( generate_path) ;
209+ let type_file = type_file. unwrap( ) ;
210+
211+ assert_eq!(
212+ generated_types. trim( ) . to_string( ) . flatten( ) ,
213+ type_file. trim( ) . to_string( ) . flatten( )
214+ ) ;
215+ return Ok ( ( ) ) ;
216+ }
217+
218+ let type_file = fs:: read_to_string( parent_path. join( "index.queries.ts" ) ) ;
219+ if type_file. is_ok( ) {
220+ let type_file = type_file. unwrap( ) . clone( ) ;
221+ let type_file = type_file. trim( ) ;
222+ assert_eq!(
223+ generated_types. trim( ) . to_string( ) . flatten( ) ,
224+ type_file. to_string( ) . flatten( )
225+ ) ;
226+ }
227+ Ok ( ( ) )
228+ }
229+ ) * } ;
230+
231+ // Original arm without version requirement
101232( $( $name: ident, $test_config: expr, $ts_content: expr, $generated_types: expr) * ) => {
102233$(
103234// MACRO STARTS
117248 let db_name = test_config. db_name;
118249 let config_file_name = test_config. config_file_name;
119250 let generate_path = test_config. generate_path;
120-
251+
121252 // SETUP
122253 let dir = tempdir( ) ?;
123254 let parent_path = dir. path( ) ;
126257 let mut temp_file = fs:: File :: create( & file_path) ?;
127258 writeln!( temp_file, "{}" , ts_content) ?;
128259 let file_result = fs:: read_to_string( & file_path) ?;
129-
260+
130261 // EXECUTE
131262 let mut cmd = cargo_bin_cmd!( "sqlx-ts" ) ;
132263
0 commit comments