#===============================================================================
#
#    assert.exp
#
#    Assertion test cases
#
#===============================================================================
######COPYRIGHTBEGIN####
#                                                                          
# ----------------------------------------------------------------------------
# Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
#
# This file is part of the eCos host tools.
#
# 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 2 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, write to the Free Software Foundation, Inc., 
# 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
# ----------------------------------------------------------------------------
#                                                                          
######COPYRIGHTEND####
#===============================================================================
######DESCRIPTIONBEGIN####
#
# Author(s):	bartv
# Contributors:	bartv
# Date:		1998-11-25
#
#####DESCRIPTIONEND####
#===============================================================================

# ----------------------------------------------------------------------------
# Start with the simple tests.
${tool}_load tassert1
${tool}_load tassert2
${tool}_load tassert3
${tool}_load tassert4

# tassert5 is not buildable under Linux. It is a C program linked with
# a C++ library, and there are dependencies on the default new and
# delete operators which are not satisfied.

if { [string match "cl*" $::hosttest_data(CC)] } {
    ${tool}_load tassert5
} else {
    unsupported "using the infrastructure from C code"
}

${tool}_load tassert6
${tool}_load tassert7

# ----------------------------------------------------------------------------
# tassert8 is a bit more complicated. It involves an assertion which
# is not caught in any way by the application code. Therefore the
# output of the program has to be analysed to make sure it is
# reasonable. There is also going to be a dump file that needs
# to be analysed and cleaned up.

proc tassert8_filter { name result output } {

    set all_ok 1
    
    if { $result == 0 } {
	fail "testcase $name should have a non-zero exit code"
	set all_ok 0
    }

    # Convert the output to a list of lines.
    set lines [split $output "\n"]

    # The first line of interest should contain the phrase
    # "Assertion failure" and the string embedded in tassert8.cxx
    while { 1 } {
	if { [llength $lines] == 0 } {
	    set all_ok 0
	    fail "No \"Assertion failure\" message detected in program output"
	    break
	}
	set line  [lindex $lines 0]
	set lines [lreplace $lines 0 0]
	if { [regexp -nocase -- {^assertion failure.*it seemed like a good idea at the time$} $line] } {
	    break
	}
    }
    
    # The next line should indicate the file and the line number
    if { [llength $lines] == 0 } {
	set all_ok 0
	fail "No file name or line number information"
    } else {
	set line  [lindex $lines 0]
	set lines [lreplace $lines 0 0]
	if { [regexp -nocase -- {^file .*tassert8.cxx.*line number [0-9]+$} $line] == 0} {
	    fail "Output did not contain the expected filename and linenumber"
	}
    }
    # There may or may not be a line containing the function name.
    # This should not be checked, it depends on compiler support
    # for __PRETTY_FUNCTION__. The next line of interest is
    # "Writing additional output to xxx", where xxx is a filename.
    while { 1 } {
	if { [llength $lines] == 0 } {
	    set all_ok 0
	    fail "Output did not specify where the dump information was stored"
	    break
	} else {
	    set line  [lindex $lines 0]
	    set lines [lreplace $lines 0 0]
	    set dummy ""
	    set match ""
	    if { [regexp -- {^Writing additional output to (.*)$} $line dummy match] } {
		tassert8_process_dump $match all_ok
		break
	    }
	}
    }
    
    if { $all_ok } {
	pass "Assertions generate sensible output"
    }

    return 0
}

proc tassert8_process_dump { filename all_ok_arg } {

    upvar $all_ok_arg all_ok
    set realname [hosttest_translate_existing_filename $filename]
    if { $realname == "" } {
	set all_ok 0
	fail "Unable to find assertion dump file $filename"
	return
    }
    set lines {}
    set status [ catch {
	set fd   [open $realname r]
	set data [read $fd]
	close $fd
	set lines [split $data "\n"]
	if { [llength $lines] == 0 } {
	    set all_ok 0
	    fail "The assertion dump file $realname contains no data"
	}
    } message ]
    if { $status != 0 } {
	set all_ok 0
	fail "Unable to open assertion output file $realname, $message"
    } 
    set status [ catch { file delete $realname } message ]
    if { $status != 0 } {
	warning "Unable to delete assertion dump file $realname, $message" 0
    }
    if { [llength $lines] == 0 } {
	return
    }

    # We have some data to process. The information should include
    # the following:
    # 1) a line Assertion failure msg
    # 2) a line with the filename and the linenumber
    # 3) optionally a line with the function name. This depends on
    #    compiler support.
    # 4) information from callback1
    # 5) information from callback2
    #
    # The relative order of (4) and (5) is not defined.
    while { 1 } {
	if { [llength $lines] == 0 } {
	    set all_ok 0
	    fail "No \"Assertion failure\" message detected in output file"
	    break
	}
	set line  [lindex $lines 0]
	set lines [lreplace $lines 0 0]
	if { [regexp -nocase -- {^assertion failure.*it seemed like a good idea at the time$} $line] } {
	    break
	}
    }
    
    if { [llength $lines] == 0 } {
	set all_ok 0
	fail "No file name or line number information"
    } else {
	set line  [lindex $lines 0]
	set lines [lreplace $lines 0 0]
	if { [regexp -nocase -- {^file .*tassert8.cxx.*line number [0-9]+$} $line] == 0} {
	    set all_ok 0
	    fail "Output did not contain the expected filename and linenumber"
	}
    }

    set seen_callback1 0
    set seen_callback2 0
    while { [llength $lines] > 0 } {
	
	set line  [lindex $lines 0]
	set lines [lreplace $lines 0 0]

	if { [regexp -nocase -- {^\# \{\{\{.*callback1.*$} $line] } {
	    if { $seen_callback1 != 0 } {
		set all_ok 0
		fail "Output contains multiple occurrences of callback1"
		continue
	    }
	    set seen_callback1 1

	    while { [llength $lines] > 0 } {
		set line  [lindex   $lines 0]
		set lines [lreplace $lines 0 0]

		if { [regexp -nocase -- {^\# \}\}\}.*$} $line] } {
		    break
		}

		# callback1 should not generate any output so only blank lines
		# are acceptable
		if { [regexp -nocase -- {^ *$} $line] != 1} {
		    set all_ok 0
		    fail "Unexpected data in callback1 output: $line"
		    # Do not repeat this failure message. This break will
		    # do near enough the right thing.
		    break
		}
	    }
	    
	} elseif  { [regexp -nocase -- {^\# \{\{\{.*callback2.*$} $line] } {
	    if { $seen_callback2 != 0 } {
		set all_ok 0
		fail "Output contains multiple occurrences of callback2"
	    }
	    set seen_callback2 1

	    while { [llength $lines] > 0 } {
		set line  [lindex   $lines 0]
		set lines [lreplace $lines 0 0]

		if { [regexp -nocase -- {^\# \}\}\}.*$} $line] } {
		    break
		}

		# callback2 is allowed to generate blank lines and
		# fixed lines.
		if { [regexp -nocase -- {^ *$} $line] == 1 } {
		    continue
		}
		if { $line == "callback2 output" } {
		    continue
		}
		set all_ok 0
		fail "Unexpected data in callback2 output: $line"
	    }
	    
	} 
    }
    if { ($seen_callback1 == 0) || ($seen_callback2 == 0) } {
	set all_ok 0
	fail "Output did not contain all the callback information"
    }
}

hosttest_run_test_with_filter tassert8 tassert8_filter {} {} {} cyginfra {}

# ----------------------------------------------------------------------------
# Strictly speaking this is not an assertion test. However there are some
# support routines in hosttest.exp which are tried closely to the
# implementation of the assertion code, and it is worthwhile checking
# these. The tassert8 testcase can be reused for this.

proc tassert9_filter { name result output } {

    if { [hosttest_assert_check $result $output] == 0 } {
	fail "testcase did not generate a recognised assertion"
	return
    }

    set output [hosttest_assert_read_dump $output]
    if { $output == "" } {
	fail "testcase did not generate a recognised assertion dump"
	return
    }

    set all_ok 1
    
    set callback1_output [hosttest_assert_extract_callback $output "callback1"]
    set callback2_output [hosttest_assert_extract_callback $output "callback2"]

    # Callback1 output should be empty, all blank lines should have been filtered
    # out.
    if { $callback1_output != "" } {
	set all_ok 0
	fail "callback1 output should be empty"
    }
    set lines [split $callback2_output "\n"]
    if { [llength $lines] == 0 } {
	set all_ok 0
	fail "callback2 should have produced some output"
    } elseif { [llength $lines] < 10} {
	set all_ok 0
	fail "callback2 is supposted to have at least ten lines of output"
    } else {
	# There should be ten lines of output, possibly followed by
	# some blanks.
	for { set i 0 } { $i < 10 } { incr i } {
	    set line  [lindex $lines 0]
	    set lines [lreplace $lines 0 0]
	    if { $line != "callback2 output" } {
		set all_ok 0
		fail "incorrect output from callback2"
		break
	    }
	}

	while { [llength $lines] > 0 } {
	    set line  [lindex $lines 0]
	    set lines [lreplace $lines 0 0]
	    if { [regexp -- {^ *$} $line] != 1 } {
		set all_ok 0
		fail "callback2 output contains unexpected data"
		break
	    }
	}
    }

    if { $all_ok } {
	pass "assertion output and dump file format match test harness expectations"
    }
    return 0
}

hosttest_run_test_with_filter tassert9 tassert9_filter tassert8.cxx {} {} cyginfra {}

