#!/bin/sh # # Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License version 2 only, as # published by the Free Software Foundation. # # This code 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 # version 2 for more details (a copy is included in the LICENSE file that # accompanied this code). # # You should have received a copy of the GNU General Public License version # 2 along with this work; if not, write to the Free Software Foundation, # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. # # Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA # or visit www.oracle.com if you need additional information or have any # questions. # # # @test # @bug 4833089 4992454 # @summary Check for proper handling of uncaught exceptions # @author Martin Buchholz # # @run shell UncaughtExceptions.sh # To run this test manually, simply do ./UncaughtExceptions.sh java="${TESTJAVA+${TESTJAVA}/bin/}java" javac="${COMPILEJAVA+${COMPILEJAVA}/bin/}javac" failed="" Fail() { echo "FAIL: $1"; failed="${failed}."; } Die() { printf "%s\n" "$*"; exit 1; } Sys() { "$@"; rc="$?"; test "$rc" -eq 0 || Die "Command \"$*\" failed with exitValue $rc"; } HorizontalRule() { echo "-----------------------------------------------------------------" } Bottom() { test "$#" = 1 -a "$1" = "Line" || Die "Usage: Bottom Line" HorizontalRule if test -n "$failed"; then count=`printf "%s" "$failed" | wc -c | tr -d ' '` echo "FAIL: $count tests failed" exit 1 else echo "PASS: all tests gave expected results" exit 0 fi } Cleanup() { Sys rm -f Seppuku* OK.class; } set -u checkOutput() { name="$1" expected="$2" got="$3" printf "$name:\n"; cat "$got" if test -z "$expected"; then test "`cat $got`" != "" && \ Fail "Unexpected $name: `cat $got`" else grep "$expected" "$got" >/dev/null || \ Fail "Expected \"$expected\", got `cat $got`" fi } CheckCommandResults() { expectedRC="$1" expectedOut="$2" expectedErr="$3"; shift 3 saveFailed="${failed}" "$@" >TmpTest.Out 2>TmpTest.Err; rc="$?"; printf "==> %s (rc=%d)\n" "$*" "$rc" checkOutput "stdout" "$expectedOut" "TmpTest.Out" checkOutput "stderr" "$expectedErr" "TmpTest.Err" test "${saveFailed}" = "${failed}" && \ echo "PASS: command completed as expected" Sys rm -f TmpTest.Out TmpTest.Err } Run() { expectedRC="$1" expectedOut="$2" expectedErr="$3" mainBody="$4" cat > Seppuku.java <<EOJAVA import static java.lang.Thread.*; import static java.lang.System.*; class OK implements UncaughtExceptionHandler { public void uncaughtException(Thread t, Throwable e) { out.println("OK"); } } class NeverInvoked implements UncaughtExceptionHandler { public void uncaughtException(Thread t, Throwable e) { err.println("Test failure: This handler should never be invoked!"); } } public class Seppuku extends Thread implements Runnable { public static void seppuku() { throw new RuntimeException("Seppuku!"); } public void run() { seppuku(); } public static void main(String[] args) throws Exception { $mainBody } } EOJAVA Sys "$javac" ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} "Seppuku.java" CheckCommandResults "$expectedRC" "$expectedOut" "$expectedErr" \ "$java" "Seppuku" Cleanup } #---------------------------------------------------------------- # A thread is never alive after you've join()ed it. #---------------------------------------------------------------- Run 0 "OK" "Exception in thread \"Thread-0\".*Seppuku" " Thread t = new Seppuku(); t.start(); t.join(); if (! t.isAlive()) out.println(\"OK\");" #---------------------------------------------------------------- # Even the main thread is mortal - here it terminates "abruptly" #---------------------------------------------------------------- Run 1 "OK" "Exception in thread \"main\".*Seppuku" " final Thread mainThread = currentThread(); new Thread() { public void run() { try { mainThread.join(); } catch (InterruptedException e) {} if (! mainThread.isAlive()) out.println(\"OK\"); }}.start(); seppuku();" #---------------------------------------------------------------- # Even the main thread is mortal - here it terminates normally. #---------------------------------------------------------------- Run 0 "OK" "" " final Thread mainThread = currentThread(); new Thread() { public void run() { try { mainThread.join(); } catch (InterruptedException e) {} if (! mainThread.isAlive()) out.println(\"OK\"); }}.start();" #---------------------------------------------------------------- # Check uncaught exception handler mechanism on the main thread. # Check that thread-level handler overrides global default handler. #---------------------------------------------------------------- Run 1 "OK" "" " currentThread().setUncaughtExceptionHandler(new OK()); setDefaultUncaughtExceptionHandler(new NeverInvoked()); seppuku();" Run 1 "OK" "" " setDefaultUncaughtExceptionHandler(new OK()); seppuku();" #---------------------------------------------------------------- # Check uncaught exception handler mechanism on non-main threads. #---------------------------------------------------------------- Run 0 "OK" "" " Thread t = new Seppuku(); t.setUncaughtExceptionHandler(new OK()); t.start();" Run 0 "OK" "" " setDefaultUncaughtExceptionHandler(new OK()); new Seppuku().start();" #---------------------------------------------------------------- # Test ThreadGroup based uncaught exception handler mechanism. # Since the handler for the main thread group cannot be changed, # there are no tests for the main thread here. #---------------------------------------------------------------- Run 0 "OK" "" " setDefaultUncaughtExceptionHandler(new NeverInvoked()); new Thread( new ThreadGroup(\"OK\") { public void uncaughtException(Thread t, Throwable e) { out.println(\"OK\");}}, new Seppuku() ).start();" Cleanup Bottom Line