check-test-names.exp revision 1.1.1.4 1 # Copyright 2020-2024 Free Software Foundation, Inc.
2
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 3 of the License, or
6 # (at your option) any later version.
7 #
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
12 #
13 # You should have received a copy of the GNU General Public License
14 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15
16 # This library provides some protection against the introduction of
17 # tests that include either the source of build paths in the test
18 # name. When a test includes the path in its test name it is harder
19 # to compare results between two runs of GDB from different trees.
20
21 namespace eval ::CheckTestNames {
22 # An associative array of all test names to the number of times each
23 # name is seen. Used to detect duplicate test names.
24 variable all_test_names
25 array set all_test_names {}
26
27 # An associative array of counts of tests that either include a path in
28 # their test name, or have a duplicate test name. There are two counts
29 # for each issue, 'count', which counts occurrences within a single
30 # variant run, and 'total', which counts across all variants.
31 variable counts
32 array set counts {}
33 foreach nm {paths duplicates} {
34 set counts($nm,count) 0
35 set counts($nm,total) 0
36 }
37
38 # Increment the count, and total count for TYPE.
39 proc inc_count { type } {
40 variable counts
41
42 incr counts($type,count)
43 incr counts($type,total)
44 }
45
46 # Check if MESSAGE contains a build or source path, if it does increment
47 # the relevant counter and return true, otherwise, return false.
48 proc _check_paths { message } {
49 global srcdir objdir
50
51 foreach path [list $srcdir $objdir] {
52 if { [ string first $path $message ] >= 0 } {
53 # Count each test just once.
54 inc_count paths
55 return true
56 }
57 }
58
59 return false
60 }
61
62 # Check if MESSAGE is a duplicate, if it is then increment the
63 # duplicates counter and return true, otherwise, return false.
64 proc _check_duplicates { message } {
65 variable all_test_names
66
67 # Remove test-case prefix, including the space separator.
68 set prefix [string_to_regexp "$::subdir/$::gdb_test_file_name.exp: "]
69 set message [regsub ^$prefix $message ""]
70
71 # Remove the "extra information" part.
72 set message [regsub { \([^()]*\)$} $message ""]
73
74 # Add back the test-case prefix.
75 set message "${prefix}$message"
76
77 # Initialise a count, or increment the count for this test name.
78 if {![info exists all_test_names($message)]} {
79 set all_test_names($message) 0
80 } else {
81 if {$all_test_names($message) == 0} {
82 inc_count duplicates
83 }
84 incr all_test_names($message)
85 return true
86 }
87
88 return false
89 }
90
91 # Remove the leading Dejagnu status marker from MESSAGE, and
92 # return the remainder of MESSAGE. A status marker is something
93 # like 'PASS: '. It is assumed that MESSAGE does contain such a
94 # marker. If it doesn't then MESSAGE is returned unmodified.
95 proc _strip_status { message } {
96 # Find the position of the first ': ' string.
97 set pos [string first ": " $message]
98 if { $pos > -1 } {
99 # The '+ 2' is so we skip the ': ' we found above.
100 return [string range $message [expr $pos + 2] end]
101 }
102
103 return $message
104 }
105
106 # Check if MESSAGE is a well-formed test name.
107 proc _check_well_formed_name { message } {
108 if { [regexp \n $message]} {
109 warning "Newline in test name"
110 }
111 }
112
113 # Check if MESSAGE contains either the source path or the build path.
114 # This will result in test names that can't easily be compared between
115 # different runs of GDB.
116 #
117 # Any offending test names cause the corresponding count to be
118 # incremented, and an extra message to be printed into the log
119 # file.
120 proc check { message } {
121 set message [ _strip_status $message ]
122
123 if [ _check_paths $message ] {
124 clone_output "PATH: $message"
125 }
126
127 if [ _check_duplicates $message ] {
128 clone_output "DUPLICATE: $message"
129 }
130
131 _check_well_formed_name $message
132 }
133
134 # If COUNT is greater than zero, disply PREFIX followed by COUNT.
135 proc maybe_show_count { prefix count } {
136 if { $count > 0 } {
137 clone_output "$prefix$count"
138 }
139 }
140
141 # Rename Dejagnu's log_summary procedure, and create do_log_summary to
142 # replace it. We arrange to have do_log_summary called later.
143 rename ::log_summary log_summary
144 proc do_log_summary { args } {
145 variable counts
146
147 # If ARGS is the empty list then we don't want to pass a single
148 # empty string as a parameter here.
149 eval "CheckTestNames::log_summary $args"
150
151 if { [llength $args] == 0 } {
152 set which "count"
153 } else {
154 set which [lindex $args 0]
155 }
156
157 maybe_show_count "# of paths in test names\t" \
158 $counts(paths,$which)
159 maybe_show_count "# of duplicate test names\t" \
160 $counts(duplicates,$which)
161 }
162
163 # Rename Dejagnu's reset_vars procedure, and create do_reset_vars to
164 # replace it. We arrange to have do_reset_vars called later.
165 rename ::reset_vars reset_vars
166 proc do_reset_vars {} {
167 variable all_test_names
168 variable counts
169
170 CheckTestNames::reset_vars
171
172 array unset all_test_names
173 foreach nm {paths duplicates} {
174 set counts($nm,count) 0
175 }
176 }
177 }
178
179 # Arrange for Dejagnu to call CheckTestNames::check for each test result.
180 foreach nm {pass fail xfail kfail xpass kpass unresolved untested \
181 unsupported} {
182 set local_record_procs($nm) "CheckTestNames::check"
183 }
184
185 # Create new global log_summary to replace Dejagnu's.
186 proc log_summary { args } {
187 eval "CheckTestNames::do_log_summary $args"
188 }
189
190 # Create new global reset_vars to replace Dejagnu's.
191 proc reset_vars {} {
192 eval "CheckTestNames::do_reset_vars"
193 }
194