diff --git a/src/gfunction/gfunction.go b/src/gfunction/gfunction.go index 96695c85..52e493c3 100644 --- a/src/gfunction/gfunction.go +++ b/src/gfunction/gfunction.go @@ -102,6 +102,7 @@ func MTableLoadGFunctions(MTable *classloader.MT) { // java/text/* javaText.Load_Math_SimpleDateFormat() + javaText.Load_Text_DateFormat() // java/security/* javaSecurity.Load_ECFieldAndPoint() diff --git a/src/gfunction/javaText/javaTextDateFormat.go b/src/gfunction/javaText/javaTextDateFormat.go new file mode 100644 index 00000000..bbc01a29 --- /dev/null +++ b/src/gfunction/javaText/javaTextDateFormat.go @@ -0,0 +1,194 @@ +/* + * Jacobin VM - A Java virtual machine + * Copyright (c) 2025 by the Jacobin Authors. All rights reserved. + * Licensed under Mozilla Public License 2.0 (MPL 2.0) Consult jacobin.org. + */ + +package javaText + +import ( + "jacobin/src/gfunction/ghelpers" +) + +func Load_Text_DateFormat() { + + ghelpers.MethodSignatures["java/text/DateFormat.()V"] = + ghelpers.GMeth{ + ParamSlots: 0, + GFunction: ghelpers.ClinitGeneric, + } + + ghelpers.MethodSignatures["java/text/DateFormat.()V"] = + ghelpers.GMeth{ + ParamSlots: 0, + GFunction: ghelpers.TrapFunction, + } + + ghelpers.MethodSignatures["java/text/DateFormat.clone()Ljava/lang/Object;"] = + ghelpers.GMeth{ + ParamSlots: 0, + GFunction: ghelpers.TrapFunction, + } + + ghelpers.MethodSignatures["java/text/DateFormat.equals(Ljava/lang/Object;)Z"] = + ghelpers.GMeth{ + ParamSlots: 1, + GFunction: ghelpers.TrapFunction, + } + + ghelpers.MethodSignatures["java/text/DateFormat.format(Ljava/lang/Object;Ljava/lang/StringBuffer;Ljava/text/FieldPosition;)Ljava/lang/StringBuffer;"] = + ghelpers.GMeth{ + ParamSlots: 3, + GFunction: ghelpers.TrapFunction, + } + + ghelpers.MethodSignatures["java/text/DateFormat.format(Ljava/util/Date;)Ljava/lang/String;"] = + ghelpers.GMeth{ + ParamSlots: 1, + GFunction: ghelpers.TrapFunction, + } + + ghelpers.MethodSignatures["java/text/DateFormat.format(Ljava/util/Date;Ljava/lang/StringBuffer;Ljava/text/FieldPosition;)Ljava/lang/StringBuffer;"] = + ghelpers.GMeth{ + ParamSlots: 3, + GFunction: ghelpers.TrapFunction, + } + + ghelpers.MethodSignatures["java/text/DateFormat.getAvailableLocales()[Ljava/util/Locale;"] = + ghelpers.GMeth{ + ParamSlots: 0, + GFunction: ghelpers.TrapFunction, + } + + ghelpers.MethodSignatures["java/text/DateFormat.getCalendar()Ljava/util/Calendar;"] = + ghelpers.GMeth{ + ParamSlots: 0, + GFunction: ghelpers.TrapFunction, + } + + ghelpers.MethodSignatures["java/text/DateFormat.getDateInstance()Ljava/text/DateFormat;"] = + ghelpers.GMeth{ + ParamSlots: 0, + GFunction: ghelpers.TrapFunction, + } + + ghelpers.MethodSignatures["java/text/DateFormat.getDateInstance(I)Ljava/text/DateFormat;"] = + ghelpers.GMeth{ + ParamSlots: 1, + GFunction: ghelpers.TrapFunction, + } + + ghelpers.MethodSignatures["java/text/DateFormat.getDateInstance(ILjava/util/Locale;)Ljava/text/DateFormat;"] = + ghelpers.GMeth{ + ParamSlots: 2, + GFunction: ghelpers.TrapFunction, + } + + ghelpers.MethodSignatures["java/text/DateFormat.getDateTimeInstance()Ljava/text/DateFormat;"] = + ghelpers.GMeth{ + ParamSlots: 0, + GFunction: ghelpers.TrapFunction, + } + + ghelpers.MethodSignatures["java/text/DateFormat.getDateTimeInstance(II)Ljava/text/DateFormat;"] = + ghelpers.GMeth{ + ParamSlots: 2, + GFunction: ghelpers.TrapFunction, + } + + ghelpers.MethodSignatures["java/text/DateFormat.getDateTimeInstance(IILjava/util/Locale;)Ljava/text/DateFormat;"] = + ghelpers.GMeth{ + ParamSlots: 3, + GFunction: ghelpers.TrapFunction, + } + + ghelpers.MethodSignatures["java/text/DateFormat.getInstance()Ljava/text/DateFormat;"] = + ghelpers.GMeth{ + ParamSlots: 0, + GFunction: ghelpers.TrapFunction, + } + + ghelpers.MethodSignatures["java/text/DateFormat.getNumberFormat()Ljava/text/NumberFormat;"] = + ghelpers.GMeth{ + ParamSlots: 0, + GFunction: ghelpers.TrapFunction, + } + + ghelpers.MethodSignatures["java/text/DateFormat.getTimeInstance()Ljava/text/DateFormat;"] = + ghelpers.GMeth{ + ParamSlots: 0, + GFunction: ghelpers.TrapFunction, + } + + ghelpers.MethodSignatures["java/text/DateFormat.getTimeInstance(I)Ljava/text/DateFormat;"] = + ghelpers.GMeth{ + ParamSlots: 1, + GFunction: ghelpers.TrapFunction, + } + + ghelpers.MethodSignatures["java/text/DateFormat.getTimeInstance(ILjava/util/Locale;)Ljava/text/DateFormat;"] = + ghelpers.GMeth{ + ParamSlots: 2, + GFunction: ghelpers.TrapFunction, + } + + ghelpers.MethodSignatures["java/text/DateFormat.getTimeZone()Ljava/util/TimeZone;"] = + ghelpers.GMeth{ + ParamSlots: 0, + GFunction: ghelpers.TrapFunction, + } + + ghelpers.MethodSignatures["java/text/DateFormat.hashCode()I"] = + ghelpers.GMeth{ + ParamSlots: 0, + GFunction: ghelpers.TrapFunction, + } + + ghelpers.MethodSignatures["java/text/DateFormat.isLenient()Z"] = + ghelpers.GMeth{ + ParamSlots: 0, + GFunction: ghelpers.TrapFunction, + } + + ghelpers.MethodSignatures["java/text/DateFormat.parse(Ljava/lang/String;)Ljava/util/Date;"] = + ghelpers.GMeth{ + ParamSlots: 1, + GFunction: ghelpers.TrapFunction, + } + + ghelpers.MethodSignatures["java/text/DateFormat.parse(Ljava/lang/String;Ljava/text/ParsePosition;)Ljava/util/Date;"] = + ghelpers.GMeth{ + ParamSlots: 2, + GFunction: ghelpers.TrapFunction, + } + + ghelpers.MethodSignatures["java/text/DateFormat.parseObject(Ljava/lang/String;Ljava/text/ParsePosition;)Ljava/lang/Object;"] = + ghelpers.GMeth{ + ParamSlots: 2, + GFunction: ghelpers.TrapFunction, + } + + ghelpers.MethodSignatures["java/text/DateFormat.setCalendar(Ljava/util/Calendar;)V"] = + ghelpers.GMeth{ + ParamSlots: 1, + GFunction: ghelpers.TrapFunction, + } + + ghelpers.MethodSignatures["java/text/DateFormat.setLenient(Z)V"] = + ghelpers.GMeth{ + ParamSlots: 1, + GFunction: ghelpers.TrapFunction, + } + + ghelpers.MethodSignatures["java/text/DateFormat.setNumberFormat(Ljava/text/NumberFormat;)V"] = + ghelpers.GMeth{ + ParamSlots: 1, + GFunction: ghelpers.TrapFunction, + } + + ghelpers.MethodSignatures["java/text/DateFormat.setTimeZone(Ljava/util/TimeZone;)V"] = + ghelpers.GMeth{ + ParamSlots: 1, + GFunction: ghelpers.TrapFunction, + } +} diff --git a/src/gfunction/javaText/javaTextSimpleDateFormat.go b/src/gfunction/javaText/javaTextSimpleDateFormat.go index d01ac36f..42486509 100644 --- a/src/gfunction/javaText/javaTextSimpleDateFormat.go +++ b/src/gfunction/javaText/javaTextSimpleDateFormat.go @@ -43,6 +43,12 @@ func Load_Math_SimpleDateFormat() { GFunction: ghelpers.TrapFunction, } + ghelpers.MethodSignatures["java/text/SimpleDateFormat.(Ljava/lang/String;Ljava/util/Locale;)V"] = + ghelpers.GMeth{ + ParamSlots: 2, + GFunction: ghelpers.TrapFunction, + } + ghelpers.MethodSignatures["java/text/SimpleDateFormat.applyLocalizedPattern(Ljava/lang/String;)V"] = ghelpers.GMeth{ ParamSlots: 1, @@ -61,6 +67,18 @@ func Load_Math_SimpleDateFormat() { GFunction: sdfClone, } + ghelpers.MethodSignatures["java/text/SimpleDateFormat.equals(Ljava/lang/Object;)Z"] = + ghelpers.GMeth{ + ParamSlots: 1, + GFunction: ghelpers.TrapFunction, + } + + ghelpers.MethodSignatures["java/text/SimpleDateFormat.format(Ljava/lang/Object;Ljava/lang/StringBuffer;Ljava/text/FieldPosition;)Ljava/lang/StringBuffer;"] = + ghelpers.GMeth{ + ParamSlots: 3, + GFunction: ghelpers.TrapFunction, + } + ghelpers.MethodSignatures["java/text/SimpleDateFormat.format(Ljava/util/Date;)Ljava/lang/String;"] = ghelpers.GMeth{ ParamSlots: 1, @@ -73,6 +91,36 @@ func Load_Math_SimpleDateFormat() { GFunction: ghelpers.TrapFunction, } + ghelpers.MethodSignatures["java/text/SimpleDateFormat.formatToCharacterIterator(Ljava/lang/Object;)Ljava/text/AttributedCharacterIterator;"] = + ghelpers.GMeth{ + ParamSlots: 1, + GFunction: ghelpers.TrapFunction, + } + + ghelpers.MethodSignatures["java/text/SimpleDateFormat.get2DigitYearStart()Ljava/util/Date;"] = + ghelpers.GMeth{ + ParamSlots: 0, + GFunction: ghelpers.TrapFunction, + } + + ghelpers.MethodSignatures["java/text/SimpleDateFormat.getAvailableLocales()[Ljava/util/Locale;"] = + ghelpers.GMeth{ + ParamSlots: 0, + GFunction: ghelpers.TrapFunction, + } + + ghelpers.MethodSignatures["java/text/SimpleDateFormat.getDateFormatSymbols()Ljava/text/DateFormatSymbols;"] = + ghelpers.GMeth{ + ParamSlots: 0, + GFunction: ghelpers.TrapFunction, + } + + ghelpers.MethodSignatures["java/text/SimpleDateFormat.hashCode()I"] = + ghelpers.GMeth{ + ParamSlots: 0, + GFunction: ghelpers.TrapFunction, + } + ghelpers.MethodSignatures["java/text/SimpleDateFormat.parse(Ljava/lang/String;)Ljava/util/Date;"] = ghelpers.GMeth{ ParamSlots: 1, @@ -85,6 +133,24 @@ func Load_Math_SimpleDateFormat() { GFunction: ghelpers.TrapFunction, } + ghelpers.MethodSignatures["java/text/SimpleDateFormat.parseObject(Ljava/lang/String;Ljava/text/ParsePosition;)Ljava/lang/Object;"] = + ghelpers.GMeth{ + ParamSlots: 2, + GFunction: ghelpers.TrapFunction, + } + + ghelpers.MethodSignatures["java/text/SimpleDateFormat.set2DigitYearStart(Ljava/util/Date;)V"] = + ghelpers.GMeth{ + ParamSlots: 1, + GFunction: ghelpers.TrapFunction, + } + + ghelpers.MethodSignatures["java/text/SimpleDateFormat.setDateFormatSymbols(Ljava/text/DateFormatSymbols;)V"] = + ghelpers.GMeth{ + ParamSlots: 1, + GFunction: ghelpers.TrapFunction, + } + ghelpers.MethodSignatures["java/text/SimpleDateFormat.toLocalizedPattern()Ljava/lang/String;"] = ghelpers.GMeth{ ParamSlots: 0, diff --git a/src/wholeClassTests/Hello2_test.go b/src/wholeClassTests/Hello2_test.go index 5a82fb0f..e9bc878c 100644 --- a/src/wholeClassTests/Hello2_test.go +++ b/src/wholeClassTests/Hello2_test.go @@ -65,7 +65,7 @@ func initVarsHello2() error { } _JACOBIN = os.Getenv("JACOBIN_EXE") // returns "" if JACOBIN_EXE has not been specified. - _JVM_ARGS = "" + _JVM_ARGS = "-trace:inst" _TESTCLASS = "Hello2.class" // the class to test _APP_ARGS = "" @@ -130,14 +130,77 @@ func TestRunHello2(t *testing.T) { } // Here begin the actual tests on the output to stderr and stdout - slurp, _ := io.ReadAll(stderr) - if len(slurp) != 0 { - t.Errorf("Got unexpected output to stderr: %s", string(slurp)) + bStderr, _ := io.ReadAll(stderr) + bStdout, _ := io.ReadAll(stdout) + strStdout := string(bStdout) + + // Wait for completion + err = cmd.Wait() + + // Success? + if err != nil { + t.Errorf("Got unexpected output to stderr: %s", string(bStderr)) + } + + if !strings.Contains(strStdout, "-1") && !strings.Contains(strStdout, "17") { + t.Errorf("Did not get expected output to stdout. Got: %s", strStdout) + } +} + +func TestRunHello2CauseFail(t *testing.T) { + if testing.Short() { // don't run if running quick tests only. (Used primarily so GitHub doesn't run and bork) + t.Skip() + } + + initErr := initVarsHello2() + if initErr != nil { + t.Fatalf("Test failure due to: %s", initErr.Error()) + } + var cmd *exec.Cmd + + if testing.Short() { // don't run if running quick tests only. (Used primarily so GitHub doesn't run and bork) + t.Skip() + } + + // run the various combinations of args. This is necessary b/c the empty string is viewed as + // an actual specified option on the command line. + _TESTCLASS = "Hello2CauseFail.class" + if len(_JVM_ARGS) > 0 { + if len(_APP_ARGS) > 0 { + cmd = exec.Command(_JACOBIN, _JVM_ARGS, _TESTCLASS, _APP_ARGS) + } else { + cmd = exec.Command(_JACOBIN, _JVM_ARGS, _TESTCLASS) + } + } else { + if len(_APP_ARGS) > 0 { + cmd = exec.Command(_JACOBIN, _TESTCLASS, _APP_ARGS) + } else { + cmd = exec.Command(_JACOBIN, _TESTCLASS) + } } - slurp, _ = io.ReadAll(stdout) + // get the stdout and stderr contents from the file execution + stderr, err := cmd.StderrPipe() + stdout, err := cmd.StdoutPipe() + if err != nil { + log.Fatal(err) + } + + // run the command + if err = cmd.Start(); err != nil { + t.Errorf("Got error running Jacobin: %s", err.Error()) + } + + // Here begin the actual tests on the output to stderr and stdout + _, _ = io.ReadAll(stderr) + bStdout, _ := io.ReadAll(stdout) + strStdout := string(bStdout) + + // Wait for completion + err = cmd.Wait() - if !strings.Contains(string(slurp), "-1") && !strings.Contains(string(slurp), "17") { - t.Errorf("Did not get expected output to stdout. Got: %s", string(slurp)) + // Did it fail as expected? + if err == nil { + t.Errorf("Expected failure but it passed, stdout: %s", strStdout) } }