1+ # version_stamping.py
2+
3+ # Made to tag all tests in a sub-directory with an options value. Initially used with
4+ # setting min_api_version to 19. This script looks for the starts of registering new tests,
5+ # then looking for the closing brackets and trying to insert the options field after
6+ # the definition of the test.
7+
8+ import os
9+ import sys
10+
11+ TARGETS = [
12+ "test.register_coroutine_test" ,
13+ "test.register_message_test" ,
14+ ]
15+
16+ INSERT_LINES = [
17+ "{" ,
18+ " min_api_version = 19" ,
19+ "}\n "
20+ ]
21+
22+
23+ def find_matching_paren (text , start_index ):
24+ """Find matching closing parenthesis handling nested parentheses."""
25+ depth = 0
26+ for i in range (start_index , len (text )):
27+ if text [i ] == "(" :
28+ depth += 1
29+ elif text [i ] == ")" :
30+ depth -= 1
31+ if depth == 0 :
32+ return i
33+ return - 1
34+
35+
36+ def find_next_target (content , start_index ):
37+ """Find the next occurrence of any target."""
38+ positions = []
39+ for target in TARGETS :
40+ pos = content .find (target , start_index )
41+ if pos != - 1 :
42+ positions .append ((pos , target ))
43+
44+ if not positions :
45+ return - 1 , None
46+
47+ # Return earliest match
48+ positions .sort (key = lambda x : x [0 ])
49+ return positions [0 ]
50+
51+
52+ def process_file (filepath ):
53+ with open (filepath , "r" , encoding = "utf-8" ) as f :
54+ content = f .read ()
55+
56+ modified = False
57+ index = 0
58+
59+ while True :
60+ match , target = find_next_target (content , index )
61+ if match == - 1 :
62+ break
63+
64+ paren_start = content .find ("(" , match )
65+ if paren_start == - 1 :
66+ break
67+
68+ paren_end = find_matching_paren (content , paren_start )
69+ if paren_end == - 1 :
70+ break
71+
72+ call_block = content [paren_start + 1 :paren_end ]
73+
74+ # Skip if already contains min_api_version
75+ if "min_api_version" in call_block :
76+ index = paren_end
77+ continue
78+
79+ lines = call_block .splitlines ()
80+
81+ # Find last non-empty line
82+ for i in range (len (lines ) - 1 , - 1 , - 1 ):
83+ stripped = lines [i ].strip ()
84+ if stripped :
85+ last_line_index = i
86+ break
87+ else :
88+ index = paren_end
89+ continue
90+
91+ last_line = lines [last_line_index ]
92+ stripped = last_line .strip ()
93+
94+ # Only modify if line ends with 'end' or '}'
95+ if not (stripped .endswith ("end" ) or stripped .endswith ("}" )):
96+ index = paren_end
97+ continue
98+
99+ indentation = last_line [:len (last_line ) - len (last_line .lstrip ())]
100+
101+ # Add comma if needed
102+ if not stripped .endswith ("," ):
103+ lines [last_line_index ] = last_line + ","
104+
105+ # Build inserted block with correct indentation
106+ indented_insert = [
107+ indentation + line for line in INSERT_LINES
108+ ]
109+
110+ lines = (
111+ lines [:last_line_index + 1 ]
112+ + indented_insert
113+ + lines [last_line_index + 1 :]
114+ )
115+
116+ new_call_block = "\n " .join (lines )
117+
118+ content = (
119+ content [:paren_start + 1 ]
120+ + new_call_block
121+ + content [paren_end :]
122+ )
123+
124+ modified = True
125+ index = paren_start + 1 + len (new_call_block )
126+
127+ if modified :
128+ with open (filepath , "w" , encoding = "utf-8" ) as f :
129+ f .write (content )
130+ print (f"Modified: { filepath } " )
131+
132+
133+ def process_directory (root_dir ):
134+ for root , _ , files in os .walk (root_dir ):
135+ for file in files :
136+ if file .endswith (".lua" ):
137+ process_file (os .path .join (root , file ))
138+
139+
140+ if __name__ == "__main__" :
141+ if len (sys .argv ) != 2 :
142+ print (f"Usage: python { sys .argv [0 ]} <directory>" )
143+ sys .exit (1 )
144+
145+ process_directory (sys .argv [1 ])
0 commit comments