Home | History | Annotate | Line # | Download | only in lib
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