check point
authorThomas Walker Lynch <xtujpz@reasoningtechnology.com>
Fri, 25 Oct 2024 15:58:27 +0000 (15:58 +0000)
committerThomas Walker Lynch <xtujpz@reasoningtechnology.com>
Fri, 25 Oct 2024 15:58:27 +0000 (15:58 +0000)
developer/javac/IO.java
developer/javac/TestBench.java [new file with mode: 0644]
developer/javac/TestBench.javax [deleted file]
developer/javac/Util.java
tester/javac/TestIO.java

index da21e2d..4514377 100644 (file)
 package com.ReasoningTechnology.Mosaic;
+/*
+  The primary purpose of this class is to redirect I/O to buffers,
+  sot that a test can check the I/O behavior of a function under test.
+*/
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
+import java.io.FileOutputStream;
+import java.io.FileInputStream;
+import java.io.FileDescriptor;
 import java.io.PrintStream;
 import java.io.InputStream;
 
-public class IO {
+public class IO{
 
-    private PrintStream original_out;
-    private PrintStream original_err;
-    private InputStream original_in;
+  private PrintStream original_out;
+  private PrintStream original_err;
+  private InputStream original_in;
 
-    private ByteArrayOutputStream out_content;
-    private ByteArrayOutputStream err_content;
-    private ByteArrayInputStream in_content;
+  private ByteArrayOutputStream out_content;
+  private ByteArrayOutputStream err_content;
+  private ByteArrayInputStream in_content;
+  private boolean streams_foobar = false;
+  private boolean uninitialized = true;
 
-    public void redirect_io(String input_data){
-        original_out = System.out;
-        original_err = System.err;
-        original_in = System.in;
 
-        out_content = new ByteArrayOutputStream();
-        err_content = new ByteArrayOutputStream();
-        in_content = new ByteArrayInputStream(input_data.getBytes());
+  // IO currently has no constructors defined, uses default
 
-        System.setOut(new PrintStream(out_content));
-        System.setErr(new PrintStream(err_content));
-        System.setIn(in_content);
-    }
 
-    public void restore_io(){
-        // Flush the output streams to prevent carrying over data
-        flush_buffers();
+  // Redirects IO streams, logs and handles errors if redirection fails.
+  //
+  // Most tests do not do I/O checks, so rather than throwing an error
+  // it will set the streams_foobar flag, then throw an error if the I/O
+  // functions are used.
+  //
+  // This is the only method that can set the streams_foobar flag.
+  public boolean redirect(){
+
+    try{
+      original_out = System.out;
+      original_err = System.err;
+      original_in = System.in;
+
+      out_content = new ByteArrayOutputStream();
+      err_content = new ByteArrayOutputStream();
+      in_content = new ByteArrayInputStream(new byte[0]);
+
+      System.setOut( new PrintStream(out_content) );
+      System.setErr( new PrintStream(err_content) );
+      System.setIn(in_content);
+
+      uninitialized = false;
+      return true;
+
+    } catch(Exception e){
+      restore_hard();
+      streams_foobar = true;
+      return false;
 
-        System.setOut(original_out);
-        System.setErr(original_err);
-        System.setIn(original_in);
     }
+  }
 
-    public void clear_buffers(){
-        out_content.reset();
-        err_content.reset();
+  // Hard restore of the streams, resetting to system defaults
+  public void restore_hard(){
+    System.setOut(new PrintStream( new FileOutputStream(FileDescriptor.out)) );
+    System.setErr(new PrintStream( new FileOutputStream(FileDescriptor.err))) ;
+    System.setIn(new FileInputStream(FileDescriptor.in));
+  }
+
+  // Restores original IO streams, ensuring foobar and uninitialized states are checked.
+  // If anything goes wrong reverse to restore_hard.
+  public void restore(){
+    if(unitialized || streams_foobar){
+      restore_hard();
+      return;
+    }
+    try{
+      System.setOut(original_out);
+      System.setErr(original_err);
+      System.setIn(original_in);
+    } catch{Throwable e){
+      restore_hard();
     }
+  }
 
-    public void flush_buffers(){
-        // Clear the buffers for the next use
-        out_content.reset();
-        err_content.reset();
+  // Clears output, error, and input buffers, checks for foobar state only.
+  public void clear_buffers(){
+    if(streams_foobar){
+      throw new IllegalStateException("Cannot clear buffers: IO object is in foobar state.");
     }
+    out_content.reset();
+    err_content.reset();
+    in_content = new ByteArrayInputStream( new byte[0] ); // Reset to EOF
+    System.setIn(in_content);
+  }
 
-    public ByteArrayInputStream get_in_content(){
-        return in_content;
+  // Returns stdout content as a string, checks foobar state only.
+  public String get_out_content(){
+    if(streams_foobar){
+      throw new IllegalStateException
+        (
+         "Cannot access stdout content: IO object is in foobar state."
+         );
     }
+    return out_content.toString();
+  }
 
-    public ByteArrayOutputStream get_out_content(){
-        return out_content;
+  // Returns stderr content as a string, checks foobar state only.
+  public String get_err_content(){
+    if(streams_foobar){
+      throw new IllegalStateException
+        (
+         "Cannot access stderr content: IO object is in foobar state."
+         );
     }
+    return err_content.toString();
+  }
 
-    public ByteArrayOutputStream get_err_content(){
-        return err_content;
+  // Pushes input string onto stdin, checks foobar state only.
+  public void push_input(String input_data){
+    if(streams_foobar){
+      throw new IllegalStateException("Cannot push input: IO object is in foobar state.");
     }
+    in_content = new ByteArrayInputStream( input_data.getBytes() );
+    System.setIn(in_content);
+  }
 }
diff --git a/developer/javac/TestBench.java b/developer/javac/TestBench.java
new file mode 100644 (file)
index 0000000..5eb1ac2
--- /dev/null
@@ -0,0 +1,356 @@
+package com.ReasoningTechnology.Mosaic;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.lang.reflect.Method;
+import java.util.Map;
+
+public class TestBench{
+
+  /* --------------------------------------------------------------------------------
+    Static Data
+  */
+
+  private static PrintStream original_out;
+  private static PrintStream original_err;
+  private static InputStream original_in;
+  
+  private static ByteArrayOutputStream out_content;
+  private static ByteArrayOutputStream err_content;
+  private static InputStream in_content;
+
+  public static boolean method_is_wellformed(Method method) {
+    // Check if the method returns boolean
+    if(!method.getReturnType().equals(boolean.class)){
+      System.out.println("Structural problem: " + method.getName() + " does not return boolean.");
+      return false;
+    }
+
+    // Check if the method has exactly three arguments
+    Class<?>[] parameterTypes = method.getParameterTypes();
+    if(parameterTypes == null || parameterTypes.length != 3){
+      System.out.println("Structural problem: " + method.getName() + " does not have three arguments.");
+      return false;
+    }
+
+    // Check that all parameters are ByteArrayOutputStream
+    if(
+       !parameterTypes[0].equals(ByteArrayOutputStream.class) // Check first parameter
+       || !parameterTypes[1].equals(ByteArrayOutputStream.class) // Check second parameter
+       || !parameterTypes[2].equals(ByteArrayOutputStream.class) // Check third parameter
+       ){
+      System.out.println("Structural problem: " + method.getName() + " has incorrect argument types.");
+      return false;
+    }
+
+    return true;
+  }
+
+  public static boolean run_test(){
+    String test_name = method.getName()
+
+
+      // Ways a test can fail ,not exclusive
+      boolean fail_malformed = false;
+    boolean fail_reported = false;
+    boolean fail_exception = false;
+    boolean fail_extraneous_stdout = false;
+    boolean fail_extraneous_stderr = false;
+
+    if( !io.redirect() ){
+      Util.log_message
+        (
+         "Mosaic::TestBench::run redirect I/O failed before running test \'"
+         + test_name
+         "\', so most class IO methods will throw an uncaught error if called."
+         );
+      Ssytem.out.println
+        (
+         "Mosaic::TestBench::run Immediately before running test, \""
+         + test 
+         + "\' I/O redirect failed."
+         );
+    }else{
+      io.clear_buffers();
+    }
+
+    // the method_is_wellformed prints more specific messages than found here
+    if( !method_is_wellformed(method) ){
+      System.out.println
+        (
+         "Mosaic::TestBench::run test \'" 
+         + test_name 
+         + "\' has incorrect type signature for a TestBench test, calling it a failure."
+         );
+      failed_test++;
+      continue;
+    }
+
+    // Finally the gremlins run the test!
+    try{
+
+      Object result = method.invoke(test_suite ,in_content ,out_content ,err_content);
+      fail_reported = !Boolean.TRUE.equals(result); // test passes if ,and only if ,it returns exactly 'true'.
+
+      // A test fails when there is extraneous output
+      fail_extraneous_stdout = out_content.size() > 0;
+      fail_extraneous_stderr = err_content.size() > 0;
+
+      // We keep it to log it
+      if(fail_extraneous_stdout){ stdout_string = out_content.toString(); }
+      if(fail_extraneous_stderr){ stderr_string = err_content.toString(); }
+
+    } catch(Exception e){
+
+      // A test fails when there is an unhandled exception.
+      fail_exception = true;
+
+      // We keep it to report it
+      exception_string = e.toString();
+
+    } finally{
+        
+      // Restore original stdin ,stdout ,and stderr
+      System.setOut(original_out);
+      System.setErr(original_err);
+      System.setIn(original_in);
+    }
+
+    if(fail_reported) System.out.println("failed: \'" + test_name + "\' by report from test.");
+    if(fail_exception) System.out.println("failed: \'" + test_name + "\' due to unhandled exception: " + exception_string);
+    if(fail_extraneous_stdout){
+      System.out.println("failed: \'" + test_name + "\' due extraneous stdout output ,see log.");
+      log_output(test_name ,"stdout" ,stdout_string);
+    }
+    if(fail_extraneous_stderr){
+      System.out.println("failed: \'" + test_name + "\' due extraneous stderr output ,see log.");
+      log_output(test_name ,"stderr" ,stderr_string);
+    }
+
+    boolean test_failed =
+      fail_reported 
+      || fail_exception 
+      || fail_extraneous_stdout
+      || fail_extraneous_stderr
+      ;
+
+    return !test_failed;
+  }
+
+
+  public static void run(Object test_suite){
+
+    int failed_test = 0;
+    int passed_test = 0;
+
+    Method[] methods = test_suite.getClass().getDeclaredMethods();
+    io = new IO();
+
+    for(Method method : methods){
+
+      // Ways a test can fail ,not exclusive
+      boolean fail_malformed = false;
+      boolean fail_reported = false;
+      boolean fail_exception = false;
+      boolean fail_extraneous_stdout = false;
+      boolean fail_extraneous_stderr = false;
+
+      if( !io.redirect() ){
+        Util.log_message
+          (
+           "Mosaic::TestBench::run redirect I/O failed before running test \'"
+           + test_name
+           "\', so most class IO methods will throw an uncaught error if called."
+           );
+        Ssytem.out.println
+          (
+           "Mosaic::TestBench::run Immediately before running test, \""
+           + test 
+           + "\' I/O redirect failed."
+           );
+      }else{
+        io.clear_buffers();
+      }
+
+      // the method_is_wellformed prints more specific messages than found here
+      if( !method_is_wellformed(method) ){
+        System.out.println
+          (
+           "Mosaic::TestBench::run test \'" 
+           + test_name 
+           + "\' has incorrect type signature for a TestBench test, calling it a failure."
+           );
+        failed_test++;
+        continue;
+      }
+
+      // Finally the gremlins run the test!
+      try{
+
+        Object result = method.invoke(test_suite ,in_content ,out_content ,err_content);
+        fail_reported = !Boolean.TRUE.equals(result); // test passes if ,and only if ,it returns exactly 'true'.
+
+        // A test fails when there is extraneous output
+        fail_extraneous_stdout = out_content.size() > 0;
+        fail_extraneous_stderr = err_content.size() > 0;
+
+        // We keep it to log it
+        if(fail_extraneous_stdout){ stdout_string = out_content.toString(); }
+        if(fail_extraneous_stderr){ stderr_string = err_content.toString(); }
+
+      } catch(Exception e){
+
+        // A test fails when there is an unhandled exception.
+        fail_exception = true;
+
+        // We keep it to report it
+        exception_string = e.toString();
+
+      } finally{
+        
+        // Restore original stdin ,stdout ,and stderr
+        System.setOut(original_out);
+        System.setErr(original_err);
+        System.setIn(original_in);
+      }
+
+      // Report the test result.
+      if(
+         fail_reported 
+         || fail_exception 
+         || fail_extraneous_stdout
+         || fail_extraneous_stderr
+         ){
+
+        failed_test++;
+
+        if(fail_reported) System.out.println("failed: \'" + test_name + "\' by report from test.");
+        if(fail_exception) System.out.println("failed: \'" + test_name + "\' due to unhandled exception: " + exception_string);
+        if(fail_extraneous_stdout){
+          System.out.println("failed: \'" + test_name + "\' due extraneous stdout output ,see log.");
+          log_output(test_name ,"stdout" ,stdout_string);
+        }
+        if(fail_extraneous_stderr){
+          System.out.println("failed: \'" + test_name + "\' due extraneous stderr output ,see log.");
+          log_output(test_name ,"stderr" ,stderr_string);
+        }
+
+      } else{
+        passed_test++;
+      }
+
+    }
+
+    // Summarize all the test results
+    System.out.println("Total tests run: " + (passed_test + failed_test));
+    System.out.println("Total tests passed: " + passed_test);
+    System.out.println("Total tests failed: " + failed_test);
+  }
+
+}
+
+-----------------
+  package com.ReasoningTechnology.Mosaic;
+
+import java.lang.reflect.Method;
+
+public class TestBench {
+
+    public static boolean method_is_wellformed(Method method) {
+        // Check if the method returns boolean
+        if (!method.getReturnType().equals(boolean.class)) {
+            System.out.println("Structural problem: " + method.getName() + " does not return boolean.");
+            return false;
+        }
+
+        // Check if the method has exactly three arguments
+        Class<?>[] parameterTypes = method.getParameterTypes();
+        if (parameterTypes == null || parameterTypes.length != 3) {
+            System.out.println("Structural problem: " + method.getName() + " does not have three arguments.");
+            return false;
+        }
+
+        // Check that all parameters are ByteArrayOutputStream
+        if (
+            !parameterTypes[0].equals(ByteArrayOutputStream.class) ||
+            !parameterTypes[1].equals(ByteArrayOutputStream.class) ||
+            !parameterTypes[2].equals(ByteArrayOutputStream.class)
+        ) {
+            System.out.println("Structural problem: " + method.getName() + " has incorrect argument types.");
+            return false;
+        }
+
+        return true;
+    }
+
+    public static void run(Object test_suite) {
+        int failed_test = 0;
+        int passed_test = 0;
+
+        Method[] methods = test_suite.getClass().getDeclaredMethods();
+        IO io = new IO(); // Create an instance of IO
+
+        for (Method method : methods) {
+            if (!method_is_wellformed(method)) {
+                System.out.println("TestBench: malformed test counted as a failure: \'" + method.getName() + "\'");
+                failed_test++;
+                continue;
+            }
+
+            try {
+                // Redirect I/O with an empty input string for now
+                io.redirectIO("");
+            } catch (Throwable e) {
+                failed_test++;
+                System.out.println("TestBench:: Error during test preparation: " + e.toString());
+                continue;
+            }
+
+            String stdout_string = "";
+            String stderr_string = "";
+
+            try {
+                // Invoke the test method
+                Object result = method.invoke(test_suite, io.getInContent(), io.getOutContent(), io.getErrContent());
+                boolean fail_reported = !Boolean.TRUE.equals(result);
+
+                // Check for extraneous output
+                stdout_string = io.getOutContent().toString();
+                stderr_string = io.getErrContent().toString();
+                boolean fail_extraneous_stdout = stdout_string.length() > 0;
+                boolean fail_extraneous_stderr = stderr_string.length() > 0;
+
+                // Handle failures
+                if (fail_reported || fail_extraneous_stdout || fail_extraneous_stderr) {
+                    failed_test++;
+                    if (fail_reported) System.out.println("failed: \'" + method.getName() + "\' by report from test.");
+                    if (fail_extraneous_stdout) {
+                        System.out.println("failed: \'" + method.getName() + "\' due extraneous stdout output, see log.");
+                        log_output(method.getName(), "stdout", stdout_string);
+                    }
+                    if (fail_extraneous_stderr) {
+                        System.out.println("failed: \'" + method.getName() + "\' due extraneous stderr output, see log.");
+                        log_output(method.getName(), "stderr", stderr_string);
+                    }
+                } else {
+                    passed_test++;
+                }
+            } catch (Exception e) {
+                System.out.println("failed: \'" + method.getName() + "\' due to unhandled exception: " + e.toString());
+                failed_test++;
+            } finally {
+                // Restore I/O
+                io.restoreIO();
+            }
+        }
+
+        // Summarize all the test results
+        System.out.println("Total tests run: " + (passed_test + failed_test));
+        System.out.println("Total tests passed: " + passed_test);
+        System.out.println("Total tests failed: " + failed_test);
+    }
+}
diff --git a/developer/javac/TestBench.javax b/developer/javac/TestBench.javax
deleted file mode 100644 (file)
index eb09d6e..0000000
+++ /dev/null
@@ -1,293 +0,0 @@
-package com.ReasoningTechnology.Mosaic;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.PrintStream;
-import java.lang.reflect.Method;
-import java.util.Map;
-
-public class TestBench{
-
-  /* --------------------------------------------------------------------------------
-    Static Data
-  */
-
-  private static PrintStream original_out;
-  private static PrintStream original_err;
-  private static InputStream original_in;
-  
-  private static ByteArrayOutputStream out_content;
-  private static ByteArrayOutputStream err_content;
-  private static InputStream in_content;
-
-  public static boolean method_is_wellformed(Method method) {
-    // Check if the method returns boolean
-    if(!method.getReturnType().equals(boolean.class)){
-      System.out.println("Structural problem: " + method.getName() + " does not return boolean.");
-      return false;
-    }
-
-    // Check if the method has exactly three arguments
-    Class<?>[] parameterTypes = method.getParameterTypes();
-    if(parameterTypes == null || parameterTypes.length != 3){
-      System.out.println("Structural problem: " + method.getName() + " does not have three arguments.");
-      return false;
-    }
-
-    // Check that all parameters are ByteArrayOutputStream
-    if(
-       !parameterTypes[0].equals(ByteArrayOutputStream.class) // Check first parameter
-       || !parameterTypes[1].equals(ByteArrayOutputStream.class) // Check second parameter
-       || !parameterTypes[2].equals(ByteArrayOutputStream.class) // Check third parameter
-       ){
-      System.out.println("Structural problem: " + method.getName() + " has incorrect argument types.");
-      return false;
-    }
-
-    return true;
-  }
-  
-  public static void flush_stdin() throws IOException{
-    while(System.in.available() > 0){
-      System.in.read();
-    }
-  }
-
-  public static void set_test_input(String input_data){
-    ByteArrayInputStream test_in = new ByteArrayInputStream(input_data.getBytes());
-    System.setIn(test_in);
-  }
-
-
-  public static void run(Object test_suite){
-
-    int failed_test = 0;
-    int passed_test = 0;
-
-    Method[] methods = test_suite.getClass().getDeclaredMethods();
-
-    for(Method method : methods){
-
-      // Ways a test can fail ,not exclusive
-      boolean fail_testbench = false;
-      boolean fail_malformed = false;
-      boolean fail_reported = false;
-      boolean fail_exception = false;
-      boolean fail_extraneous_stdout = false;
-      boolean fail_extraneous_stderr = false;
-
-      if( !method_is_wellformed(method) ){
-        // the malformed check prints specific messages
-        System.out.println("TestBench: malformed test counted as a failure:\'" + method.getName() + "\'");
-        failed_test++;
-        continue;
-      }
-
-      PrintStream original_out = null;
-      PrintStream original_err = null;
-      InputStream original_in  = null;
-
-      ByteArrayOutputStream out_content = null;
-      ByteArrayOutputStream err_content = null;
-      ByteArrayInputStream in_content = null;
-
-      try{
-        // Redirect the I/O channels so the tests can manipulate them as data.
-        original_out = System.out;
-        original_err = System.err;
-        original_in = System.in;
-  
-        out_content = new ByteArrayOutputStream();
-        err_content = new ByteArrayOutputStream();
-        in_content = new ByteArrayInputStream();
-
-        System.setOut(new PrintStream(out_content));
-        System.setErr(new PrintStream(err_content));
-        System.setIn(in_content);
-
-      } catch(Throwable e){  // Catches both Errors and Exceptions
-        // Restore stdout ,stderr ,and stdin before reporting the error
-        System.setOut(original_out);
-        System.setErr(original_err);
-        System.setIn(original_in);
-
-        // Report the error
-        System.out.println("TestBench:: when redirecting i/o in preparation for running test \'" + method.getName() + "\' ,test bench itself throws error: " + e.toString());
-        failed_test++;
-        continue;
-      }
-
-      // Capture detritus 
-      String exception_string = "";
-      String stdout_string = "";
-      String stderr_string = "";
-
-      // Finally the gremlins run the test!
-      try{
-
-        Object result = method.invoke(test_suite ,in_content ,out_content ,err_content);
-        fail_reported = !Boolean.TRUE.equals(result); // test passes if ,and only if ,it returns exactly 'true'.
-
-        // A test fails when there is extraneous output
-        fail_extraneous_stdout = out_content.size() > 0;
-        fail_extraneous_stderr = err_content.size() > 0;
-
-        // We keep it to log it
-        if(fail_extraneous_stdout){ stdout_string = out_content.toString(); }
-        if(fail_extraneous_stderr){ stderr_string = err_content.toString(); }
-
-      } catch(Exception e){
-
-        // A test fails when there is an unhandled exception.
-        fail_exception = true;
-
-        // We keep it to report it
-        exception_string = e.toString();
-
-      } finally{
-        
-        // Restore original stdin ,stdout ,and stderr
-        System.setOut(original_out);
-        System.setErr(original_err);
-        System.setIn(original_in);
-      }
-
-      // Report the test result.
-      if(
-         fail_reported 
-         || fail_exception 
-         || fail_extraneous_stdout
-         || fail_extraneous_stderr
-         ){
-
-        failed_test++;
-
-        if(fail_reported) System.out.println("failed: \'" + method.getName() + "\' by report from test.");
-        if(fail_exception) System.out.println("failed: \'" + method.getName() + "\' due to unhandled exception: " + exception_string);
-        if(fail_extraneous_stdout){
-          System.out.println("failed: \'" + method.getName() + "\' due extraneous stdout output ,see log.");
-          log_output(method.getName() ,"stdout" ,stdout_string);
-        }
-        if(fail_extraneous_stderr){
-          System.out.println("failed: \'" + method.getName() + "\' due extraneous stderr output ,see log.");
-          log_output(method.getName() ,"stderr" ,stderr_string);
-        }
-
-      } else{
-        passed_test++;
-      }
-
-    }
-
-    // Summarize all the test results
-    System.out.println("Total tests run: " + (passed_test + failed_test));
-    System.out.println("Total tests passed: " + passed_test);
-    System.out.println("Total tests failed: " + failed_test);
-  }
-
-}
-
------------------
-  package com.ReasoningTechnology.Mosaic;
-
-import java.lang.reflect.Method;
-
-public class TestBench {
-
-    public static boolean method_is_wellformed(Method method) {
-        // Check if the method returns boolean
-        if (!method.getReturnType().equals(boolean.class)) {
-            System.out.println("Structural problem: " + method.getName() + " does not return boolean.");
-            return false;
-        }
-
-        // Check if the method has exactly three arguments
-        Class<?>[] parameterTypes = method.getParameterTypes();
-        if (parameterTypes == null || parameterTypes.length != 3) {
-            System.out.println("Structural problem: " + method.getName() + " does not have three arguments.");
-            return false;
-        }
-
-        // Check that all parameters are ByteArrayOutputStream
-        if (
-            !parameterTypes[0].equals(ByteArrayOutputStream.class) ||
-            !parameterTypes[1].equals(ByteArrayOutputStream.class) ||
-            !parameterTypes[2].equals(ByteArrayOutputStream.class)
-        ) {
-            System.out.println("Structural problem: " + method.getName() + " has incorrect argument types.");
-            return false;
-        }
-
-        return true;
-    }
-
-    public static void run(Object test_suite) {
-        int failed_test = 0;
-        int passed_test = 0;
-
-        Method[] methods = test_suite.getClass().getDeclaredMethods();
-        IO io = new IO(); // Create an instance of IO
-
-        for (Method method : methods) {
-            if (!method_is_wellformed(method)) {
-                System.out.println("TestBench: malformed test counted as a failure: \'" + method.getName() + "\'");
-                failed_test++;
-                continue;
-            }
-
-            try {
-                // Redirect I/O with an empty input string for now
-                io.redirectIO("");
-            } catch (Throwable e) {
-                failed_test++;
-                System.out.println("TestBench:: Error during test preparation: " + e.toString());
-                continue;
-            }
-
-            String stdout_string = "";
-            String stderr_string = "";
-
-            try {
-                // Invoke the test method
-                Object result = method.invoke(test_suite, io.getInContent(), io.getOutContent(), io.getErrContent());
-                boolean fail_reported = !Boolean.TRUE.equals(result);
-
-                // Check for extraneous output
-                stdout_string = io.getOutContent().toString();
-                stderr_string = io.getErrContent().toString();
-                boolean fail_extraneous_stdout = stdout_string.length() > 0;
-                boolean fail_extraneous_stderr = stderr_string.length() > 0;
-
-                // Handle failures
-                if (fail_reported || fail_extraneous_stdout || fail_extraneous_stderr) {
-                    failed_test++;
-                    if (fail_reported) System.out.println("failed: \'" + method.getName() + "\' by report from test.");
-                    if (fail_extraneous_stdout) {
-                        System.out.println("failed: \'" + method.getName() + "\' due extraneous stdout output, see log.");
-                        log_output(method.getName(), "stdout", stdout_string);
-                    }
-                    if (fail_extraneous_stderr) {
-                        System.out.println("failed: \'" + method.getName() + "\' due extraneous stderr output, see log.");
-                        log_output(method.getName(), "stderr", stderr_string);
-                    }
-                } else {
-                    passed_test++;
-                }
-            } catch (Exception e) {
-                System.out.println("failed: \'" + method.getName() + "\' due to unhandled exception: " + e.toString());
-                failed_test++;
-            } finally {
-                // Restore I/O
-                io.restoreIO();
-            }
-        }
-
-        // Summarize all the test results
-        System.out.println("Total tests run: " + (passed_test + failed_test));
-        System.out.println("Total tests passed: " + passed_test);
-        System.out.println("Total tests failed: " + failed_test);
-    }
-}
index 13e2c14..e4d59c7 100644 (file)
@@ -6,6 +6,9 @@ import java.io.FileWriter;
 import java.io.IOException;
 import java.io.PrintStream;
 import java.lang.reflect.Method;
+import java.time.Instant;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
 
 public class Util{
 
@@ -25,18 +28,35 @@ public class Util{
     for( boolean condition : conditions ) condition = true;
   }
 
+  public static String iso_utc_time(){
+    return Instant.now().atOffset(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT);
+  }
 
-
+  // used to report if a test completed with data still on an output streams
   public static void log_output(String test_name ,String stream ,String output_data){
     try(FileWriter log_writer = new FileWriter("test_log.txt" ,true)){  // Append mode
+      log_writer.write("\n" + iso_utc_time() + " -----------------------------------------------------------\n");
       log_writer.write("Test: " + test_name + "\n");
       log_writer.write("Stream: " + stream + "\n");
       log_writer.write("Output:\n" + output_data + "\n");
-      log_writer.write("----------------------------------------\n");
     } catch(IOException e) {
       System.err.println("Error writing to log for test: " + test_name + ", stream: " + stream);
       e.printStackTrace(System.err);
     }
   }
 
+  // used to log a general message about a test
+  public static void log_message(String test_name ,String message){
+    try(FileWriter log_writer = new FileWriter("test_log.txt" ,true)){  // Append mode
+      log_writer.write("\n" + iso_utc_time() + " -----------------------------------------------------------\n");
+      log_writer.write("Test: " + test_name + "\n");
+      log_writer.write("Message:\n" + message + "\n");
+    } catch(IOException e) {
+      System.err.println("Error writing to log for test: " + test_name + ", stream: " + stream);
+      e.printStackTrace(System.err);
+    }
+  }
+
+
+
 }
index 1e0ecba..0b0ffbf 100644 (file)
@@ -16,12 +16,12 @@ public class TestIO{
 
       // Count remaining characters until EOF
       int count = 0;
-      while( System.in.read() != -1 ){
+      while(System.in.read() != -1){
         count++;
       }
 
       return count;
-    } catch( Exception e ){
+    } catch(Exception e){
       e.printStackTrace();
       return -1; // Error case
     }
@@ -29,30 +29,32 @@ public class TestIO{
 
   public static int run(){
     IO io = new IO();
-    String input_data = "abcdefg"; // Sample input
     boolean[] condition = new boolean[3];
 
     // Redirect IO streams
-    io.redirect_io(input_data);
+    io.redirect();
+
+    // Provide input for the function under test
+    io.push_input("abcdefg");
 
     // Execute function under test
     int result = fut();
 
     // Check stdout content
-    String stdout = io.get_out_content().toString();
-    condition[0] = stdout.equals("ab");
+    String stdout_string = io.get_out_content();
+    condition[0] = stdout_string.equals("ab");
 
     // Check stderr content
-    String stderr = io.get_err_content().toString();
-    condition[1] = stderr.equals("cd");
+    String stderr_string = io.get_err_content();
+    condition[1] = stderr_string.equals("cd");
 
-    // Check returned character count (3 remaining characters: 'e' ,'f' ,'g')
+    // Check returned character count (3 remaining characters: 'e','f','g')
     condition[2] = result == 3;
 
     // Restore original IO streams
-    io.restore_io();
+    io.restore();
 
-    if( !Util.all(condition) ){
+    if(!Util.all(condition)){
       System.out.println("TestIO failed");
       return 1;
     }
@@ -68,3 +70,5 @@ public class TestIO{
   }
 
 }
+
+