| # Copyright 2020-2022 Free Software Foundation, Inc. | 
 |  | 
 | # This program is free software; you can redistribute it and/or modify | 
 | # it under the terms of the GNU General Public License as published by | 
 | # the Free Software Foundation; either version 3 of the License, or | 
 | # (at your option) any later version. | 
 | # | 
 | # This program is distributed in the hope that it will be useful, | 
 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 | # GNU General Public License for more details. | 
 | # | 
 | # You should have received a copy of the GNU General Public License | 
 | # along with this program.  If not, see <http://www.gnu.org/licenses/>. | 
 |  | 
 | # This library provides some protection against the introduction of | 
 | # tests that include either the source of build paths in the test | 
 | # name.  When a test includes the path in its test name it is harder | 
 | # to compare results between two runs of GDB from different trees. | 
 |  | 
 | namespace eval ::CheckTestNames { | 
 |     # An associative array of all test names to the number of times each | 
 |     # name is seen.  Used to detect duplicate test names. | 
 |     variable all_test_names | 
 |     array set all_test_names {} | 
 |  | 
 |     # An associative array of counts of tests that either include a path in | 
 |     # their test name, or have a duplicate test name.  There are two counts | 
 |     # for each issue, 'count', which counts occurrences within a single | 
 |     # variant run, and 'total', which counts across all variants. | 
 |     variable counts | 
 |     array set counts {} | 
 |     foreach nm {paths duplicates} { | 
 | 	set counts($nm,count) 0 | 
 | 	set counts($nm,total) 0 | 
 |     } | 
 |  | 
 |     # Increment the count, and total count for TYPE. | 
 |     proc inc_count { type } { | 
 | 	variable counts | 
 |  | 
 | 	incr counts($type,count) | 
 | 	incr counts($type,total) | 
 |     } | 
 |  | 
 |     # Check if MESSAGE contains a build or source path, if it does increment | 
 |     # the relevant counter and return true, otherwise, return false. | 
 |     proc _check_paths { message } { | 
 | 	global srcdir objdir | 
 |  | 
 | 	foreach path [list $srcdir $objdir] { | 
 | 	    if { [ string first $path $message ] >= 0 } { | 
 | 		# Count each test just once. | 
 | 		inc_count paths | 
 | 		return true | 
 | 	    } | 
 | 	} | 
 |  | 
 | 	return false | 
 |     } | 
 |  | 
 |     # Check if MESSAGE is a duplicate, if it is then increment the | 
 |     # duplicates counter and return true, otherwise, return false. | 
 |     proc _check_duplicates { message } { | 
 | 	variable all_test_names | 
 |  | 
 | 	# Initialise a count, or increment the count for this test name. | 
 | 	if {![info exists all_test_names($message)]} { | 
 | 	    set all_test_names($message) 0 | 
 | 	} else { | 
 | 	    if {$all_test_names($message) == 0} { | 
 | 		inc_count duplicates | 
 | 	    } | 
 | 	    incr all_test_names($message) | 
 | 	    return true | 
 | 	} | 
 |  | 
 | 	return false | 
 |     } | 
 |  | 
 |     # Remove the leading Dejagnu status marker from MESSAGE, and | 
 |     # return the remainder of MESSAGE.  A status marker is something | 
 |     # like 'PASS: '.  It is assumed that MESSAGE does contain such a | 
 |     # marker.  If it doesn't then MESSAGE is returned unmodified. | 
 |     proc _strip_status { message } { | 
 | 	# Find the position of the first ': ' string. | 
 | 	set pos [string first ": " $message] | 
 | 	if { $pos > -1 } { | 
 | 	    # The '+ 2' is so we skip the ': ' we found above. | 
 | 	    return  [string range $message [expr $pos + 2] end] | 
 | 	} | 
 |  | 
 | 	return $message | 
 |     } | 
 |  | 
 |     # Check if MESSAGE is a well-formed test name. | 
 |     proc _check_well_formed_name { message } { | 
 | 	if { [regexp \n $message]} { | 
 | 	    warning "Newline in test name" | 
 | 	} | 
 |     } | 
 |  | 
 |     # Check if MESSAGE contains either the source path or the build path. | 
 |     # This will result in test names that can't easily be compared between | 
 |     # different runs of GDB. | 
 |     # | 
 |     # Any offending test names cause the corresponding count to be | 
 |     # incremented, and an extra message to be printed into the log | 
 |     # file. | 
 |     proc check { message } { | 
 | 	set message [ _strip_status $message ] | 
 |  | 
 | 	if [ _check_paths $message ] { | 
 | 	    clone_output "PATH: $message" | 
 | 	} | 
 |  | 
 | 	if [ _check_duplicates $message ] { | 
 | 	    clone_output "DUPLICATE: $message" | 
 | 	} | 
 |  | 
 | 	_check_well_formed_name $message | 
 |     } | 
 |  | 
 |     # If COUNT is greater than zero, disply PREFIX followed by COUNT. | 
 |     proc maybe_show_count { prefix count } { | 
 | 	if { $count > 0 } { | 
 | 	    clone_output "$prefix$count" | 
 | 	} | 
 |     } | 
 |  | 
 |     # Rename Dejagnu's log_summary procedure, and create do_log_summary to | 
 |     # replace it.  We arrange to have do_log_summary called later. | 
 |     rename ::log_summary log_summary | 
 |     proc do_log_summary { args } { | 
 | 	variable counts | 
 |  | 
 | 	# If ARGS is the empty list then we don't want to pass a single | 
 | 	# empty string as a parameter here. | 
 | 	eval "CheckTestNames::log_summary $args" | 
 |  | 
 | 	if { [llength $args] == 0 } { | 
 | 	    set which "count" | 
 | 	} else { | 
 | 	    set which [lindex $args 0] | 
 | 	} | 
 |  | 
 | 	maybe_show_count "# of paths in test names\t" \ | 
 | 	    $counts(paths,$which) | 
 | 	maybe_show_count "# of duplicate test names\t" \ | 
 | 	    $counts(duplicates,$which) | 
 |     } | 
 |  | 
 |     # Rename Dejagnu's reset_vars procedure, and create do_reset_vars to | 
 |     # replace it.  We arrange to have do_reset_vars called later. | 
 |     rename ::reset_vars reset_vars | 
 |     proc do_reset_vars {} { | 
 | 	variable all_test_names | 
 | 	variable counts | 
 |  | 
 | 	CheckTestNames::reset_vars | 
 |  | 
 | 	array unset all_test_names | 
 | 	foreach nm {paths duplicates} { | 
 | 	    set counts($nm,count) 0 | 
 | 	} | 
 |     } | 
 | } | 
 |  | 
 | # Arrange for Dejagnu to call CheckTestNames::check for each test result. | 
 | foreach nm {pass fail xfail kfail xpass kpass unresolved untested \ | 
 | 		unsupported} { | 
 |     set local_record_procs($nm) "CheckTestNames::check" | 
 | } | 
 |  | 
 | # Create new global log_summary to replace Dejagnu's. | 
 | proc log_summary { args } { | 
 |     eval "CheckTestNames::do_log_summary $args" | 
 | } | 
 |  | 
 | # Create new global reset_vars to replace Dejagnu's. | 
 | proc reset_vars {} { | 
 |     eval "CheckTestNames::do_reset_vars" | 
 | } |