From 60681417d3fdbe159fbcc03c7c09f7c272021fa5 Mon Sep 17 00:00:00 2001 From: Thomas Walker Lynch Date: Fri, 8 Nov 2024 10:07:08 +0000 Subject: [PATCH] release v1.1 prepends to class names to ameliorate java aliasing on import problems, addition of some docs, some small changes --- ...anscript.txt => build_transcript_v1.0.txt} | 0 developer/document/build_transcript_v1.1.txt | 63 ++++++++++ developer/document/the_build_environmet.txt | 84 +++++++++++++ developer/javac/{IO.java => Mosaic_IO.java} | 2 +- .../javac/{Mosaic.java => Mosaic_Mosaic.java} | 6 +- .../{TestBench.java => Mosaic_Testbench.java} | 18 +-- .../javac/{Util.java => Mosaic_Util.java} | 2 +- document/class_name.txt | 33 +++++ document/todo.txt | 34 +++-- env_administrator | 2 +- release/Mosaic.jar | Bin 8217 -> 8278 bytes .../Tests_Writing_Output_Stream_Policy.html | 112 ----------------- tester/document/Writing a test.txt | 50 ++++++++ tester/document/about_the_tests.html | 118 ------------------ ...ript.txt => build_run_transcript_v1.0.txt} | 6 +- tester/document/build_run_transcript_v1.1.txt | 74 +++++++++++ tester/javac/Test0.java | 4 +- tester/javac/TestMosaic_0.javax | 60 --------- tester/javac/Test_IO.java | 8 +- ...t_MockClass.java => Test_MockClass_0.java} | 34 ++--- ...est_TestBench.java => Test_Testbench.java} | 48 +++---- tester/javac/Test_Util.java | 30 ++--- tester/jvm/Test_Mosaic.jar | Bin 7671 -> 7683 bytes tester/shell/Test_MockClass | 2 - tester/shell/Test_MockClass_0 | 2 + tester/shell/Test_TestBench | 2 - tester/shell/Test_Testbench | 2 + tester/shell/test_log.txt | 4 +- tester/tool/shell_wrapper_list | 2 +- tool/.githolder | 0 tool/env | 42 ++++--- tool/shell_wrapper_list | 2 - tool_shared/bespoke/bashrc | 51 ++++++++ tool_shared/bespoke/version | 3 +- 34 files changed, 481 insertions(+), 419 deletions(-) rename developer/document/{build_transcript.txt => build_transcript_v1.0.txt} (100%) create mode 100644 developer/document/build_transcript_v1.1.txt create mode 100644 developer/document/the_build_environmet.txt rename developer/javac/{IO.java => Mosaic_IO.java} (99%) rename developer/javac/{Mosaic.java => Mosaic_Mosaic.java} (73%) rename developer/javac/{TestBench.java => Mosaic_Testbench.java} (87%) rename developer/javac/{Util.java => Mosaic_Util.java} (99%) create mode 100644 document/class_name.txt delete mode 100644 tester/document/Tests_Writing_Output_Stream_Policy.html create mode 100644 tester/document/Writing a test.txt delete mode 100644 tester/document/about_the_tests.html rename tester/document/{build_run_transcript.txt => build_run_transcript_v1.0.txt} (90%) create mode 100644 tester/document/build_run_transcript_v1.1.txt delete mode 100644 tester/javac/TestMosaic_0.javax rename tester/javac/{Test_MockClass.java => Test_MockClass_0.java} (67%) rename tester/javac/{Test_TestBench.java => Test_Testbench.java} (58%) delete mode 100755 tester/shell/Test_MockClass create mode 100755 tester/shell/Test_MockClass_0 delete mode 100755 tester/shell/Test_TestBench create mode 100755 tester/shell/Test_Testbench create mode 100644 tool/.githolder delete mode 100755 tool/shell_wrapper_list create mode 100644 tool_shared/bespoke/bashrc diff --git a/developer/document/build_transcript.txt b/developer/document/build_transcript_v1.0.txt similarity index 100% rename from developer/document/build_transcript.txt rename to developer/document/build_transcript_v1.0.txt diff --git a/developer/document/build_transcript_v1.1.txt b/developer/document/build_transcript_v1.1.txt new file mode 100644 index 0000000..0a00aba --- /dev/null +++ b/developer/document/build_transcript_v1.1.txt @@ -0,0 +1,63 @@ + +--- setting up the environment: + + +024-11-08T07:40:57Z[] +Thomas-developer@Blossac§/var/user_data/Thomas-developer§ +> bash + +2024-11-08T07:41:19Z[] +Thomas-developer@Blossac§/var/user_data/Thomas-developer§ +> cd Mosaic + +2024-11-08T07:41:25Z[] +Thomas-developer@Blossac§/var/user_data/Thomas-developer/Mosaic§ +> . env_developer +REPO_HOME /var/user_data/Thomas-developer/Mosaic +PROJECT Mosaic +ENV tool_shared/bespoke/env +ENV developer/tool/env + +2024-11-08T07:41:34Z[Mosaic_developer] +Thomas-developer@Blossac§/var/user_data/Thomas-developer/Mosaic/developer§ +> emacs & + + +--- building the release candidate + +2024-11-08T09:58:08Z[Mosaic_developer] +Thomas-developer@Blossac§/var/user_data/Thomas-developer/Mosaic/developer§ +> clean_build_directories ++ cd /var/user_data/Thomas-developer/Mosaic/developer ++ rm -r scratchpad/com ++ rm jvm/Mosaic.jar ++ rm shell/Mosaic ++ set +x +clean_build_directories done. + +2024-11-08T09:58:16Z[Mosaic_developer] +Thomas-developer@Blossac§/var/user_data/Thomas-developer/Mosaic/developer§ +> make +Compiling files... ++ javac -g -d scratchpad javac/Mosaic_IO.java javac/Mosaic_Mosaic.java javac/Mosaic_Testbench.java javac/Mosaic_Util.java ++ set +x +Creating JAR file... ++ jar_file=jvm/Mosaic.jar ++ mkdir -p jvm ++ jar cf jvm/Mosaic.jar -C scratchpad . ++ set +x +JAR file created successfully: jvm/Mosaic.jar +Creating shell wrappers... +developer/tool/make done. + +2024-11-08T09:58:21Z[Mosaic_developer] +Thomas-developer@Blossac§/var/user_data/Thomas-developer/Mosaic/developer§ +> release +Starting release process... +Installed Mosaic.jar to /var/user_data/Thomas-developer/Mosaic/release with permissions ug+r +Installed Mosaic to /var/user_data/Thomas-developer/Mosaic/release with permissions ug+r+x +developer/tool/release done. + +2024-11-08T09:58:24Z[Mosaic_developer] +Thomas-developer@Blossac§/var/user_data/Thomas-developer/Mosaic/developer§ +> diff --git a/developer/document/the_build_environmet.txt b/developer/document/the_build_environmet.txt new file mode 100644 index 0000000..cd491db --- /dev/null +++ b/developer/document/the_build_environmet.txt @@ -0,0 +1,84 @@ +1. Tool + +The directory called `tool` has tools for the developer. There are comments at +the top of each that says what it does. + +In the tool directory, `env` sets the PATH, CLASSPATH, and prepares the developer's +environment. Noting will work right until this is sourced. (This is similar to +Python's `venv`.) + +The tool called `make` builds the project. This is not the venerable `/bin/make` +but is a simple bash script. It is going to compile everything in the `javac` +directory. + +The tool called `shall_wrapper_list` gives a list of classes names that are to +be given direct call shell wrappers. `make` will put these in the `shell` +directory. + +The `clean_` scripts are there to delete files so that developers do not have +to type `rm` commands. This helps prevent accidents. Note the +$REPO_HOME/tool_shared/bespoke/wipe_release script will remove files from the +../release directory. + +2. build + +`make` runs `javac` which puts the class files into the `scratch_pad` directory. +It will `makedir` a directory hierarchy in `scratch_pad` that mirrors the +package name. + +After compiling `make` then gathers the class files found in the scratchpad +directory hierarchy and puts them into a `.jar` file. Said `.jar` file will +be located in the directory `jvm`. + +The `scratch_pad` directory is not pushed to the repo. It can be cleaned +at any time, because it can always be rebuilt. + +3. release + +The `release` script will make a copy of the scripts in `shell` and the `.jar` +file in `jvm` and put them in the `$REPO_HOME/release` directory. This +comprises the release candidate. After a release branch is made, this becomes +the actual release. Note the script in `$REPO_HOME/bespoke/version` which +outputs the version for released code. + + +4. debug + +If you use emacs note the file `$REPO_HOME/test_shared/bespoke/emacs.el'. + +Edit `make` to add or remove the `-g` flag from `javac`. This controls putting +source code information into the class files. + +After `javac` is compiled with the `-g` flag, and in the `jdb` debugger, `jdb` +will look into the `scratchpad` directory hierarchy where the sources were +put to find the sources files to display when single stepping etc. + +The `distribute_source` tool adds links into the `scratchpad` directory hierarchy +the point back into the `javac` directory. After these links are made, `jdb` +will show the sources, and should the sources be edited, the originals located +in the `javac` directory will be modified. + +5. debug from the `tester` environment + +The tester environment points at the release candidate located in the +$REPO_HOME/release directory to find the java classes. + +If this release candidate was compiled with the `-g` flag, then it will have +embedded in it source information pointing back into the +`$REPO_HOME/developer/scratchpad` directory. + +If the `distribute_source` was not called by the developer, or the scratchpad +contents have been cleaned, jdb will not be able to find the sources. +If jdb does find the sources, and the tester edits them, then the originals +in the `$REPO_HOME/developer/javac` directory will be modified. If this +behavior is not desired, then put the tester on a `core_tester_branch`, then +inspect changes before merging them back to the `core_developer_branch`. + +This setup makes it possible for developers to use the tester environment +to work, without having to be on a separate branch, or for testers to +work separately. + + + + + diff --git a/developer/javac/IO.java b/developer/javac/Mosaic_IO.java similarity index 99% rename from developer/javac/IO.java rename to developer/javac/Mosaic_IO.java index 90107e1..fe6bdff 100644 --- a/developer/javac/IO.java +++ b/developer/javac/Mosaic_IO.java @@ -12,7 +12,7 @@ import java.io.FileDescriptor; import java.io.PrintStream; import java.io.InputStream; -public class IO{ +public class Mosaic_IO{ private PrintStream original_out; private PrintStream original_err; diff --git a/developer/javac/Mosaic.java b/developer/javac/Mosaic_Mosaic.java similarity index 73% rename from developer/javac/Mosaic.java rename to developer/javac/Mosaic_Mosaic.java index aeb992e..51e57d0 100644 --- a/developer/javac/Mosaic.java +++ b/developer/javac/Mosaic_Mosaic.java @@ -1,13 +1,13 @@ package com.ReasoningTechnology.Mosaic; -import com.ReasoningTechnology.Mosaic.Util; /* -Mosaic currently does not have shell commands. +The Mosaic shell callable wrapper is currently a placeholder. Perhaps someday we +can find something for this to do. */ -public class Mosaic{ +public class Mosaic_Mosaic{ public static Boolean test_is_true(){ return true; diff --git a/developer/javac/TestBench.java b/developer/javac/Mosaic_Testbench.java similarity index 87% rename from developer/javac/TestBench.java rename to developer/javac/Mosaic_Testbench.java index 01dbba7..c8e0644 100644 --- a/developer/javac/TestBench.java +++ b/developer/javac/Mosaic_Testbench.java @@ -2,7 +2,7 @@ package com.ReasoningTechnology.Mosaic; import java.lang.reflect.Method; -public class TestBench { +public class Mosaic_Testbench { /* -------------------------------------------------------------------------------- Validate the structure of a test method @@ -14,10 +14,10 @@ public class TestBench { return false; } - // Check if the method has exactly one argument of type IO + // Check if the method has exactly one argument of type Mosaic_IO Class[] parameterTypes = method.getParameterTypes(); - if(parameterTypes == null || parameterTypes.length != 1 || !parameterTypes[0].equals(IO.class)){ - System.out.println("Structural problem: " + method.getName() + " does not accept a single IO argument."); + if(parameterTypes == null || parameterTypes.length != 1 || !parameterTypes[0].equals(Mosaic_IO.class)){ + System.out.println("Structural problem: " + method.getName() + " does not accept a single Mosaic_IO argument."); return false; } @@ -27,7 +27,7 @@ public class TestBench { /* -------------------------------------------------------------------------------- Run a single test method */ - public static Boolean run_test(Object test_suite, Method method, IO io){ + public static Boolean run_test(Object test_suite, Method method, Mosaic_IO io){ String test_name = method.getName(); // Tracking possible test failures @@ -49,7 +49,7 @@ public class TestBench { if(successful_redirect){ io.clear_buffers(); // Start each test with empty buffers } else { - Util.log_message(test_name, "Error: I/O redirection failed before running the test."); + Mosaic_Util.log_message(test_name, "Error: I/O redirection failed before running the test."); System.out.println("Warning: Failed to redirect I/O for test: " + test_name); } @@ -71,11 +71,11 @@ public class TestBench { if(fail_exception) System.out.println("Test failed: '" + test_name + "' threw an exception: " + exception_string); if(fail_extraneous_stdout){ System.out.println("Test failed: '" + test_name + "' produced extraneous stdout."); - Util.log_output(test_name, "stdout", io.get_out_content()); + Mosaic_Util.log_output(test_name, "stdout", io.get_out_content()); } if(fail_extraneous_stderr){ System.out.println("Test failed: '" + test_name + "' produced extraneous stderr."); - Util.log_output(test_name, "stderr", io.get_err_content()); + Mosaic_Util.log_output(test_name, "stderr", io.get_err_content()); } // Determine final test result @@ -89,7 +89,7 @@ public class TestBench { int failed_tests = 0; int passed_tests = 0; Method[] methods = test_suite.getClass().getDeclaredMethods(); - IO io = new IO(); + Mosaic_IO io = new Mosaic_IO(); for(Method method : methods){ if(run_test(test_suite, method, io)) passed_tests++; else failed_tests++; diff --git a/developer/javac/Util.java b/developer/javac/Mosaic_Util.java similarity index 99% rename from developer/javac/Util.java rename to developer/javac/Mosaic_Util.java index 03796a9..3a2cdbf 100644 --- a/developer/javac/Util.java +++ b/developer/javac/Mosaic_Util.java @@ -11,7 +11,7 @@ import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.util.function.Predicate; -public class Util{ +public class Mosaic_Util{ // Linear search with a predicate public static T find( T[] elements ,Predicate predicate ){ diff --git a/document/class_name.txt b/document/class_name.txt new file mode 100644 index 0000000..dda2904 --- /dev/null +++ b/document/class_name.txt @@ -0,0 +1,33 @@ +Java has long been criticized for its lack of support for `import as`, despite +years of requests and proposals. + +The Java platform’s approach to aliasing issues relies on using fully qualified +names, which poses challenges given the length of package names, especially when +they include reversed domain names. + +Because `Mosaic` is used to help with testing and is not part of the project +being tested, when aliasing conflicts arise, it is typically the `Mosaic` identifiers +that need to be fully qualified. Such a renamed identifier can exceed 34 +characters! + +One proposal to get around this was to use an `In` class where the members were +class extensions of imported classes. Then all imports would have the prefix `In.`. +However, this did not work out because constructors are not +inherited, and Java’s restrictions on `final` classes prevent the use of +`LocalClass extends ImportClass {}` to give no names to classes. + +Another proposal was to use the `alias` project on GitHub, which offers an XML-based +approach to aliasing. However, it introduces complexities, as it requires XML +configurations to be supplied to the compiler, adding setup overhead. Perhaps +another tool could create these. + +We studied a preprocessing proposal where `import as` statements would be +replaced with fully qualified names before compilation. However, this approach +changes the tool flow for users and would require additional steps to ensure +`jdb` points to the original source files rather than intermediate files, which +complicates debugging. For both this proposal and the prior, we wanted to avoid +joining the world of java tool development. + +So we have a simple solution, it is not ideal, but it is not bad. We prefix +the string `Mosaic_` to the front of all the class names in the Mosaic library. +As a shop we are adopting this convention for all packaged java code. diff --git a/document/todo.txt b/document/todo.txt index 6ff1508..9bbf201 100644 --- a/document/todo.txt +++ b/document/todo.txt @@ -1,31 +1,25 @@ -Updates for Ariadne +1. More languages support, notably nodejs. -1. reflect project skeleton changes. - replaced literal `Ariadne` with `$PROJECT` - in top level env choices, PROJECT -> PROMPT_DECOR +2. This message: - note in 'release' there is a variable name with the project name embedded in it: - Ariadne_jar_fp -> project_jar_fp - Change slashes to dots in the wrapper maker of 'make' + Running Test_File_0...Structural problem: unpack_file_path_0 does not accept a single IO argument. + Error: unpack_file_path_0 has an invalid structure. -2. should do something about `wrapper` as it appears in multiple places making - editing it a pain. - in all places `wrapper` appears, now calls `shell_wrapper_list` - in both developer and tester + Perhaps only the second one, getting rid of 'Error:' -3. clean_make -> clean_make_output + "Bad type signature for method: unpack_file_path_0 does not accept a single IO argument." -4. version outputs a `v` in front of the number +3. TestBench -> Testbench perhaps? -5. fix many shebangs to be: #!/usr/bin/env bash - -6. scratch_pad -> scratchpad - -5. make_source_tree also integrated into make - -6. replacement for bespoke/env and all other env files, related document. +4. fix emacs.el so that jdbx doesn't always start with Test_Util. (note the + prior start can be found with M-x p +5. should include a tool for aggregating test suite runs + FYI, I'm using +6. need an example .bashrc for setting the prompt now that I removed references +to the 'resource' project and plan to deprecate it. +7. should check stdin for unused input and report error also. diff --git a/env_administrator b/env_administrator index 0fc10de..bb09700 100644 --- a/env_administrator +++ b/env_administrator @@ -6,5 +6,5 @@ if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then fi source tool_shared/bespoke/env - +source tool/env diff --git a/release/Mosaic.jar b/release/Mosaic.jar index f1f8c7a9b8334ccdd657dc94f527074a8994b4b5..576d66e549b3f79e16666e6cab8593130c4a86e2 100644 GIT binary patch delta 7243 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 b**pFBtx^8yst5>}f3C$ppMsh4uj>B+771yq diff --git a/tester/document/Tests_Writing_Output_Stream_Policy.html b/tester/document/Tests_Writing_Output_Stream_Policy.html deleted file mode 100644 index 29bd872..0000000 --- a/tester/document/Tests_Writing_Output_Stream_Policy.html +++ /dev/null @@ -1,112 +0,0 @@ - - - - - - - Output Stream Policy - Mosaic Project - - - -
-

Output Stream Policy for Tests

- -

Overview of the IO Object

- -

Each test function is given an IO object, which provides - methods for inspecting stdout and stderr output - streams, programmatically adding data to the stdin input stream, - and clearing output streams as needed. Although the IO object is - optional, it is available for cases where I/O validation or cleanup is - essential to the test.

- -

Purpose

- -

Each test function is responsible for managing any output generated - on stdout or stderr by the function under test - (fut). TestBench will automatically clear the streams before - each test begins and will check them after the test completes, treating any - remaining output as unintended and marking the test as a failure. This policy - ensures that tests intentionally handle output by either validating, - clearing, or ignoring it, thereby maintaining a clean and predictable testing - environment.

- -

Policy Guidelines

-
    -
  • 1. Define an Output Handling Policy:
  • -
      -
    • Every test should have a defined policy for how it handles output generated by the fut. There are three primary approaches:
    • -
        -
      • Validation: Check the fut output and confirm its correctness.
      • -
      • Intentional Ignoring: If output validation isn’t relevant to the test, the output should still be acknowledged and cleared to avoid unintended failures.
      • -
      • Mixed Policy: A test can validate specific output while ignoring others, as long as any remaining output is cleared before the test returns.
      • -
      -
    - -
  • 2. When to Validate Output:
  • -
      -
    • If the test expects specific output from the fut, it should retrieve and check the content on stdout and stderr using methods like io.get_out_content() or io.get_err_content(). The test passes if the actual output matches the expected content.
    • -
    • After validating, the test should clear the output buffers (io.clear_buffers()) if further output handling is not needed to avoid residual content.
    • -
    - -
  • 3. When to Ignore Output:
  • -
      -
    • If the test does not require output verification, it should acknowledge the output by clearing the streams before returning.
    • -
    • This approach signals to TestBench that any output generated was intentionally disregarded and avoids marking the test as failed.
    • -
    - -
  • 4. Failure Due to Residual Output:
  • -
      -
    • No Defined Policy: If a test leaves output on the streams without a clear handling policy (validation or intentional clearing), TestBench will flag this as a failure.
    • -
    • Ensuring Clean Tests: To avoid unexpected failures, verify that each test has no residual output before returning by either validating or clearing output streams.
    • -
    -
- -

Example Scenarios

-
    -
  • 1. Output Validation:
  • -
    public static Boolean test_with_output_verification(IO io) {
    -  System.out.println("Expected output");
    -  String output = io.get_out_content();
    -  boolean isCorrect = output.equals("Expected output");
    -  io.clear_buffers(); // Clear remaining content if not needed
    -  return isCorrect;
    -}
    - -
  • 2. Ignoring Output:
  • -
    public static Boolean test_without_output_verification(IO io) {
    -  System.out.println("Output not needed for this test");
    -  io.clear_buffers(); // Clear output since it’s intentionally ignored
    -  return true;
    -}
    -
- -

Summary

-

Each test should manage its output streams with an intentional policy:

-
    -
  • Validate output if it is relevant to the test.
  • -
  • Acknowledge and clear output if it is not relevant.
  • -
  • Avoid residual output to prevent TestBench from marking the test as failed.
  • -
-

This approach ensures that tests remain clean and focused on their primary objectives without unintended side effects from unhandled output.

-
- - diff --git a/tester/document/Writing a test.txt b/tester/document/Writing a test.txt new file mode 100644 index 0000000..d2d02ed --- /dev/null +++ b/tester/document/Writing a test.txt @@ -0,0 +1,50 @@ + +I did not use Mosaic to test itself, although Test_MockClass_0 comes close. + +TestMockClass has the general form of a test that uses Mosaic, though MockClass +itself does not exist. This general form: + +*. For block testing there conventionally be a correspondence between + The test classes and the a class being tested, so each test class will + be named: + + `Test__'. + + Typically the lowest `number` will be zero, and it will correspond to + smoke tests. + +* A `Test__' class will have inside of it another class + called `TestSuite`. By convention each method in this class is a test routine. For block + testing a test routine will has a correspondence to the method being tested, + and has the name: + + `test__`. + + This convention is not always followed, no that in `Test_MackClass_0` you will + notice that tests are named after the expected results rather than a method + that is being tested. + + Test routines can run a number of tests on a RUT, each of which is referred to + as a test case. So we have this hierarchy: + + `Test__' > `TestSuite` > test_routine > test_case + +*. The main call for a Test class will parse arguments and options, setup + the testing environment, make a `TestSuite` object, pass said object to + the `TestBench`, then take the return value from the `Testbench`, and set + the return value from the test. + +* A test routines will return `true` if the test passes. Any other return + value, any uncaught exception, or anything left on the stdout or stderr + will cause the test to be interpreted as a failure. (On the todo list is + an item to make unused stdin an error as well.) + +* A test reoutine (nor the contained test cases) should not themselves print + any messages. Generally it has always been this way, even before the Testbench + redirected and the i/o streams. Rather the test should simply return true + for a pass. This is because in testing we are looking for function failures, + and not for faults. The fault will be searched for later in the debugger. + + If a test routine has an internal error, such that the routine itself + has a problem (not the RUT it is testing), this can be put in a log + entry. See the Mosaic_Util for the log methods. diff --git a/tester/document/about_the_tests.html b/tester/document/about_the_tests.html deleted file mode 100644 index 18d6cc2..0000000 --- a/tester/document/about_the_tests.html +++ /dev/null @@ -1,118 +0,0 @@ - - - - - - - About the Tests - Mosaic Project - - - -
- -

About the Tests

- -

This document provides an operational guide for running and expanding - tests of the Mosaic TestBench. I.e. it is not about running the Mosaic - TestBench, rather it is about testing the Mosaic TestBench

- -

These tests are primarily ad hoc, as we avoid using the TestBench to test - itself. Despite being ad hoc, the tests follow a core philosophy: the goal - is to identify which functions fail, rather than diagnose why they fail. In - the argot of the field, we are looking for function failures ad are not - identifying falts. Hence, tests do not print messages but signal if they - fail, or not.

- -

Accordingly, only pass/fail counts and the names of failing functions are - recorded. For more detailed investigation, for locating the fault, the - developer can run a failed test using a debugging tool such - as jdb.

- -

1. Running the Tests

-

To run all tests and gather results, follow these steps:

-
    -
  1. Make sure no old files are hanging about by running clean_build_directories.
  2. -
  3. Run make to compile the project and prepare all test class shell wrappers.
  4. -
  5. Run run_tests to run the tests. Each test class will output - its results, identifying tests that failed.
  6. -
- -

2. Ad Hoc Block Tests

-

The block tests are ad hoc and do not use TestBench directly. It would - have been nice to have used the TestBench, but doing so would have - introduce unnecessary complexity.

-
    -
  • 2.1 Each test group is a class.
  • -
      -
    • Each group of related tests is organized within its own class, keeping tests modular and focused.
    • -
    -
  • 2.2 Key Methods
  • -
      -
    • main: The entry point for command-line execution.
    • -
    • run: Aggregates test results, runs all methods in the class, and reports outcomes.
    • -
    -
  • 2.3 Helper and Test Methods
  • -
      -
    • Test methods take no arguments and return true if they pass; any other return value counts as a failure.
    • -
    -
- -

3. Integration Tests

-

After completion of the ad hoc block testing, integration of the blocks - is tested with one or more tests that make use of the TestBench. The - TestBench framework offers a structured testing approach. Classes using - TestBench are referred to as Test Suites, each method within which is - treated as an independent test.

-
    -
  • 3.1 Test Suites
  • -
      - -
    • Each Test Suite class extends - the TestBench class. Each method in a Test Suite runs as a - separate test when the suite is executed.
    • -
    -
  • 3.2 Method Structure
  • -
      -
    • Each test method accepts a - single IO argument (a utility class handling input/output - streams) and returns a Object. Only a return value - of Boolean true is counted as a pass. Any other return - value, any uncaught exceptions, or any data left on stdin, or stdout - are taken to mean the test failed.
    • -
    -
- -

4. Adding a Test

-

To extend the testing suite, new tests can be added as follows:

-
    -
  • 4.1 Create or Extend a Test Class
  • -
      -
    • Add a new test class as required or append methods to an existing one.
    • -
    -
  • 4.2 Integrate the Test Class
  • -
      -
    • For classes with a main function, add the class name to tool/shell_wrapper_list to ensure it is included in the test environment.
    • -
    -
- -
- - diff --git a/tester/document/build_run_transcript.txt b/tester/document/build_run_transcript_v1.0.txt similarity index 90% rename from tester/document/build_run_transcript.txt rename to tester/document/build_run_transcript_v1.0.txt index d5c1d45..615640a 100644 --- a/tester/document/build_run_transcript.txt +++ b/tester/document/build_run_transcript_v1.0.txt @@ -1,9 +1,7 @@ This shows all tests passing. -It can be a bit confusing to read, but the failure results from the tests named -'test_failure_X' are actually passing when they report that they failed. This is -because we are testing a test bench, and we are testing the feature of the test -bench where it fails bad code. +Tests named `test_failure_` should fail. We need to know that the `TestBench` +can fail tests, so this is part of testing the `TestBench`. > cd Mosaic > source env_tester diff --git a/tester/document/build_run_transcript_v1.1.txt b/tester/document/build_run_transcript_v1.1.txt new file mode 100644 index 0000000..feb0d04 --- /dev/null +++ b/tester/document/build_run_transcript_v1.1.txt @@ -0,0 +1,74 @@ +This shows all tests passing. + +Tests named `test_failure_` should fail. We need to know that the `TestBench` +can fail tests, so this is part of testing the `TestBench`. + +Staring the environment: + +2024-11-08T07:41:48Z[] +Thomas-developer@Blossac§/var/user_data/Thomas-developer§ +> bash + +2024-11-08T07:41:51Z[] +Thomas-developer@Blossac§/var/user_data/Thomas-developer§ +> cd Mosaic + +2024-11-08T07:41:54Z[] +Thomas-developer@Blossac§/var/user_data/Thomas-developer/Mosaic§ +> . env_tester +REPO_HOME /var/user_data/Thomas-developer/Mosaic +PROJECT Mosaic +ENV tool_shared/bespoke/env +ENV tester/tool/env + +2024-11-08T07:42:04Z[Mosaic_tester] +Thomas-developer@Blossac§/var/user_data/Thomas-developer/Mosaic/tester§ +> emacs & + +Running the tests: + +2024-11-08T09:58:40Z[Mosaic_tester] +Thomas-developer@Blossac§/var/user_data/Thomas-developer/Mosaic/tester§ +> clean_build_directories ++ cd /var/user_data/Thomas-developer/Mosaic/tester ++ rm -r scratchpad/Test0.class scratchpad/Test_IO.class 'scratchpad/Test_MockClass_0$TestSuite.class' scratchpad/Test_MockClass_0.class scratchpad/Test_Testbench.class scratchpad/Test_Util.class ++ rm jvm/Test_Mosaic.jar ++ rm shell/Test0 shell/Test_IO shell/test_log.txt shell/Test_MockClass_0 shell/Test_Testbench shell/Test_Util ++ set +x +clean_build_directories done. + +2024-11-08T09:58:46Z[Mosaic_tester] +Thomas-developer@Blossac§/var/user_data/Thomas-developer/Mosaic/tester§ +> make +Compiling files... ++ cd /var/user_data/Thomas-developer/Mosaic/tester ++ javac -g -d scratchpad javac/Test0.java javac/Test_IO.java javac/Test_MockClass_0.java javac/Test_Testbench.java javac/Test_Util.java ++ jar cf jvm/Test_Mosaic.jar -C scratchpad . ++ set +x +Creating shell wrappers... +tester/tool/make done. + +2024-11-08T09:58:50Z[Mosaic_tester] +Thomas-developer@Blossac§/var/user_data/Thomas-developer/Mosaic/tester§ +> run_tests +Running Test0...Test0 passed +Running Test_Util...Test_Util passed +Running Test_IO...Test_IO passed +Running Test_Testbench...Expected output: Structural problem message for dummy_invalid_return_method. +Structural problem: dummy_invalid_return_method does not return Boolean. +Test_Testbench Total tests run: 3 +Test_Testbench Total tests passed: 3 +Test_Testbench Total tests failed: 0 +Running Test_MockClass_0...Test failed: 'test_failure_0' reported failure. +Structural problem: test_failure_1 does not return Boolean. +Error: test_failure_1 has an invalid structure. +Test failed: 'test_failure_2' threw an exception: java.lang.reflect.InvocationTargetException +Test failed: 'test_failure_3' produced extraneous stdout. +Test failed: 'test_failure_4' produced extraneous stderr. +Total tests run: 9 +Total tests passed: 4 +Total tests failed: 5 + +2024-11-08T09:58:55Z[Mosaic_tester] +Thomas-developer@Blossac§/var/user_data/Thomas-developer/Mosaic/tester§ +> diff --git a/tester/javac/Test0.java b/tester/javac/Test0.java index e8a4810..c4abc4a 100644 --- a/tester/javac/Test0.java +++ b/tester/javac/Test0.java @@ -1,4 +1,4 @@ -import com.ReasoningTechnology.Mosaic.Util; +import com.ReasoningTechnology.Mosaic.Mosaic_Util; /* Test Zero @@ -18,7 +18,7 @@ public class Test0{ condition[0] = test_is_true(); int i = 0; - if( !Util.all(condition) ){ + if( !Mosaic_Util.all(condition) ){ System.out.println("Test0 failed"); return 1; } diff --git a/tester/javac/TestMosaic_0.javax b/tester/javac/TestMosaic_0.javax deleted file mode 100644 index 85ab091..0000000 --- a/tester/javac/TestMosaic_0.javax +++ /dev/null @@ -1,60 +0,0 @@ -/* -Component smoke test. At least call each method of each class. - -*/ - -import com.ReasoningTechnology.Ariadne.*; -import com.ReasoningTechnology.TestBench.*; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.PrintStream; -import java.lang.reflect.Method; -import java.util.List; -import java.util.Map; - -public class TestTestBench extends TestBench{ - - public static class TestSuite{ - - TestSuite(){ - } - - public Boolean test_pass(ByteArrayOutputStream out_content, ByteArrayOutputStream err_content){ - return true; - } - - public Boolean test_fail_0(ByteArrayOutputStream out_content, ByteArrayOutputStream err_content){ - return false; - } - - // Tests if exception uncaught by the test correctly causes a failure from the TestBench. - public static Boolean test_fail_1() throws Exception { - int randomInt = (int) (Math.random() * 100); // Generate a random integer - // Always returns true, but Java will not complain that following code is unreachable - if( - (randomInt % 2 != 0 && ((randomInt * randomInt - 1) % 8 == 0)) - || (randomInt % 2 == 0 && (randomInt * randomInt) % 4 == 0) - ){ - throw new Exception("Condition met, error thrown."); - } - - return true; // If the condition fails, return true - } - - } - - // Method to run all tests - public static void test_TestBench(){ - System.out.println("TestTestBench: running tests. Note that two failures is normal"); - TestSuite test_suite = new TestSuite(); - TestBench.run( test_suite ); - } - - // Main function to provide a shell interface for running tests - public static void main(String[] args){ - // tests currently takes no arguments or options - test_TestBench(); // Calls the method to run all tests - } - -} - diff --git a/tester/javac/Test_IO.java b/tester/javac/Test_IO.java index 7298b1d..a7f8248 100644 --- a/tester/javac/Test_IO.java +++ b/tester/javac/Test_IO.java @@ -1,5 +1,5 @@ -import com.ReasoningTechnology.Mosaic.IO; -import com.ReasoningTechnology.Mosaic.Util; +import com.ReasoningTechnology.Mosaic.Mosaic_IO; +import com.ReasoningTechnology.Mosaic.Mosaic_Util; public class Test_IO{ @@ -27,7 +27,7 @@ public class Test_IO{ } public static int run(){ - IO io = new IO(); + Mosaic_IO io = new Mosaic_IO(); Boolean[] condition = new Boolean[3]; // Redirect IO streams @@ -53,7 +53,7 @@ public class Test_IO{ // Restore original IO streams io.restore(); - if(!Util.all(condition)){ + if(!Mosaic_Util.all(condition)){ System.out.println("Test_IO failed"); return 1; } diff --git a/tester/javac/Test_MockClass.java b/tester/javac/Test_MockClass_0.java similarity index 67% rename from tester/javac/Test_MockClass.java rename to tester/javac/Test_MockClass_0.java index 64bc962..0f02a64 100644 --- a/tester/javac/Test_MockClass.java +++ b/tester/javac/Test_MockClass_0.java @@ -1,14 +1,14 @@ /* -------------------------------------------------------------------------------- - Integration tests directly simulate the use cases for TestBench. - Each test method validates a specific feature of TestBench ,including pass, + Integration tests directly simulate the use cases for Mosaic_Testbench. + Each test method validates a specific feature of Mosaic_Testbench ,including pass, fail ,error handling ,and I/O interactions. */ import java.util.Scanner; -import com.ReasoningTechnology.Mosaic.IO; -import com.ReasoningTechnology.Mosaic.TestBench; +import com.ReasoningTechnology.Mosaic.Mosaic_IO; +import com.ReasoningTechnology.Mosaic.Mosaic_Testbench; -public class Test_MockClass{ +public class Test_MockClass_0{ public class TestSuite{ @@ -16,39 +16,39 @@ public class Test_MockClass{ // no special initialization of data for this test } - public Boolean test_failure_0(IO io){ + public Boolean test_failure_0(Mosaic_IO io){ return false; } // returns a non-Boolean - public Object test_failure_1(IO io){ + public Object test_failure_1(Mosaic_IO io){ return 1; } // has an uncaught error - public Boolean test_failure_2(IO io) throws Exception { + public Boolean test_failure_2(Mosaic_IO io) throws Exception { throw new Exception("Intentional exception for testing error handling"); } // extraneous characters on stdout - public Boolean test_failure_3(IO io) throws Exception { + public Boolean test_failure_3(Mosaic_IO io) throws Exception { System.out.println("Intentional extraneous chars to stdout for testing"); return true; } // extraneous characters on stderr - public Boolean test_failure_4(IO io) throws Exception { + public Boolean test_failure_4(Mosaic_IO io) throws Exception { System.err.println("Intentional extraneous chars to stderr for testing."); return true; } - public Boolean test_success_0(IO io){ + public Boolean test_success_0(Mosaic_IO io){ return true; } // pushing input for testing - public Boolean test_success_1(IO io){ + public Boolean test_success_1(Mosaic_IO io){ io.push_input("input for the fut"); Scanner scanner = new Scanner(System.in); @@ -60,7 +60,7 @@ public class Test_MockClass{ } // checking fut stdout - public Boolean test_success_2(IO io){ + public Boolean test_success_2(Mosaic_IO io){ System.out.println("fut stdout"); // suppose the fut does this: String peek_at_futs_output = io.get_out_content(); Boolean flag0 = io.has_out_content(); @@ -70,7 +70,7 @@ public class Test_MockClass{ } // checking fut stderr - public Boolean test_success_3(IO io){ + public Boolean test_success_3(Mosaic_IO io){ System.err.print("fut stderr"); // suppose the fut does this: String peek_at_futs_output = io.get_err_content(); Boolean flag0 = io.has_err_content(); @@ -82,16 +82,16 @@ public class Test_MockClass{ } public static void main(String[] args) { - Test_MockClass outer = new Test_MockClass(); + Test_MockClass_0 outer = new Test_MockClass_0(); TestSuite suite = outer.new TestSuite(); // Non-static instantiation /* for debug - IO io = new IO(); + Mosaic_IO io = new Mosaic_IO(); io.redirect(); suite.test_success_2(io); */ - int result = TestBench.run(suite); // Pass the suite instance to TestBench + int result = Mosaic_Testbench.run(suite); // Pass the suite instance to Mosaic_Testbench System.exit(result); } diff --git a/tester/javac/Test_TestBench.java b/tester/javac/Test_Testbench.java similarity index 58% rename from tester/javac/Test_TestBench.java rename to tester/javac/Test_Testbench.java index a4ae469..56f9e21 100644 --- a/tester/javac/Test_TestBench.java +++ b/tester/javac/Test_Testbench.java @@ -1,73 +1,73 @@ import java.lang.reflect.Method; -import com.ReasoningTechnology.Mosaic.IO; -import com.ReasoningTechnology.Mosaic.TestBench; +import com.ReasoningTechnology.Mosaic.Mosaic_IO; +import com.ReasoningTechnology.Mosaic.Mosaic_Testbench; -public class Test_TestBench { +public class Test_Testbench { /* -------------------------------------------------------------------------------- - Test methods to validate TestBench functionality - Each method tests a specific aspect of the TestBench class, with a focus on + Test methods to validate Testbench functionality + Each method tests a specific aspect of the Testbench class, with a focus on ensuring that well-formed and ill-formed test cases are correctly identified and handled. */ - // Tests if a correctly formed method is recognized as well-formed by TestBench - public static Boolean test_method_is_wellformed_0(IO io) { + // Tests if a correctly formed method is recognized as well-formed by Testbench + public static Boolean test_method_is_wellformed_0(Mosaic_IO io) { try { - Method validMethod = Test_TestBench.class.getMethod("dummy_test_method", IO.class); - return Boolean.TRUE.equals(TestBench.method_is_wellformed(validMethod)); + Method validMethod = Test_Testbench.class.getMethod("dummy_test_method", Mosaic_IO.class); + return Boolean.TRUE.equals(Mosaic_Testbench.method_is_wellformed(validMethod)); } catch (NoSuchMethodException e) { return false; } } - // Tests if a method with an invalid return type is identified as malformed by TestBench - public static Boolean test_method_is_wellformed_1(IO io) { + // Tests if a method with an invalid return type is identified as malformed by Testbench + public static Boolean test_method_is_wellformed_1(Mosaic_IO io) { System.out.println("Expected output: Structural problem message for dummy_invalid_return_method."); try { - Method invalidReturnMethod = Test_TestBench.class.getMethod("dummy_invalid_return_method", IO.class); - return Boolean.FALSE.equals(TestBench.method_is_wellformed(invalidReturnMethod)); + Method invalidReturnMethod = Test_Testbench.class.getMethod("dummy_invalid_return_method", Mosaic_IO.class); + return Boolean.FALSE.equals(Mosaic_Testbench.method_is_wellformed(invalidReturnMethod)); } catch (NoSuchMethodException e) { return false; } } - // Tests if a valid test method runs successfully with the TestBench - public static Boolean test_run_test_0(IO io) { + // Tests if a valid test method runs successfully with the Testbench + public static Boolean test_run_test_0(Mosaic_IO io) { try { - Method validMethod = Test_TestBench.class.getMethod("dummy_test_method", IO.class); - return Boolean.TRUE.equals(TestBench.run_test(new Test_TestBench(), validMethod, io)); + Method validMethod = Test_Testbench.class.getMethod("dummy_test_method", Mosaic_IO.class); + return Boolean.TRUE.equals(Mosaic_Testbench.run_test(new Test_Testbench(), validMethod, io)); } catch (NoSuchMethodException e) { return false; } } /* Dummy methods for testing */ - public Boolean dummy_test_method(IO io) { + public Boolean dummy_test_method(Mosaic_IO io) { return true; // Simulates a passing test case } - public void dummy_invalid_return_method(IO io) { + public void dummy_invalid_return_method(Mosaic_IO io) { // Simulates a test case with an invalid return type } /* -------------------------------------------------------------------------------- - Manually run all tests and summarize results without using TestBench itself. + Manually run all tests and summarize results without using Testbench itself. Each test's name is printed if it fails, and only pass/fail counts are summarized. */ public static int run() { int passed_tests = 0; int failed_tests = 0; - IO io = new IO(); + Mosaic_IO io = new Mosaic_IO(); if (test_method_is_wellformed_0(io)) passed_tests++; else { System.out.println("test_method_is_wellformed_0"); failed_tests++; } if (test_method_is_wellformed_1(io)) passed_tests++; else { System.out.println("test_method_is_wellformed_1"); failed_tests++; } if (test_run_test_0(io)) passed_tests++; else { System.out.println("test_run_test_0"); failed_tests++; } // Summary for all the tests - System.out.println("Test_TestBench Total tests run: " + (passed_tests + failed_tests)); - System.out.println("Test_TestBench Total tests passed: " + passed_tests); - System.out.println("Test_TestBench Total tests failed: " + failed_tests); + System.out.println("Test_Testbench Total tests run: " + (passed_tests + failed_tests)); + System.out.println("Test_Testbench Total tests passed: " + passed_tests); + System.out.println("Test_Testbench Total tests failed: " + failed_tests); return (failed_tests > 0) ? 1 : 0; } diff --git a/tester/javac/Test_Util.java b/tester/javac/Test_Util.java index 23a869e..b959d5e 100644 --- a/tester/javac/Test_Util.java +++ b/tester/javac/Test_Util.java @@ -1,4 +1,4 @@ -import com.ReasoningTechnology.Mosaic.Util; +import com.ReasoningTechnology.Mosaic.Mosaic_Util; /* Test_Util @@ -10,23 +10,23 @@ public class Test_Util{ public static Boolean test_all(){ // Test with zero condition Boolean[] condition0 = {}; - Boolean result = !Util.all(condition0); // Empty condition list is false. + Boolean result = !Mosaic_Util.all(condition0); // Empty condition list is false. // Test with one condition Boolean[] condition1_true = {true}; Boolean[] condition1_false = {false}; - result &= Util.all(condition1_true); // should return true - result &= !Util.all(condition1_false); // should return false + result &= Mosaic_Util.all(condition1_true); // should return true + result &= !Mosaic_Util.all(condition1_false); // should return false // Test with two condition Boolean[] condition2_true = {true, true}; Boolean[] condition2_false1 = {true, false}; Boolean[] condition2_false2 = {false, true}; Boolean[] condition2_false3 = {false, false}; - result &= Util.all(condition2_true); // should return true - result &= !Util.all(condition2_false1); // should return false - result &= !Util.all(condition2_false2); // should return false - result &= !Util.all(condition2_false3); // should return false + result &= Mosaic_Util.all(condition2_true); // should return true + result &= !Mosaic_Util.all(condition2_false1); // should return false + result &= !Mosaic_Util.all(condition2_false2); // should return false + result &= !Mosaic_Util.all(condition2_false3); // should return false // Test with three condition Boolean[] condition3_false1 = {true, true, false}; @@ -34,24 +34,24 @@ public class Test_Util{ Boolean[] condition3_false2 = {true, false, true}; Boolean[] condition3_false3 = {false, true, true}; Boolean[] condition3_false4 = {false, false, false}; - result &= !Util.all(condition3_false1); // should return false - result &= Util.all(condition3_true); // should return true - result &= !Util.all(condition3_false2); // should return false - result &= !Util.all(condition3_false3); // should return false - result &= !Util.all(condition3_false4); // should return false + result &= !Mosaic_Util.all(condition3_false1); // should return false + result &= Mosaic_Util.all(condition3_true); // should return true + result &= !Mosaic_Util.all(condition3_false2); // should return false + result &= !Mosaic_Util.all(condition3_false3); // should return false + result &= !Mosaic_Util.all(condition3_false4); // should return false return result; } public static Boolean test_all_set_false(){ Boolean[] condition_list = {true, true, true}; - Util.all_set_false(condition_list); + Mosaic_Util.all_set_false(condition_list); return !condition_list[0] && !condition_list[1] && !condition_list[2]; } public static Boolean test_all_set_true(){ Boolean[] condition_list = {false, false, false}; - Util.all_set_true(condition_list); + Mosaic_Util.all_set_true(condition_list); return condition_list[0] && condition_list[1] && condition_list[2]; } diff --git a/tester/jvm/Test_Mosaic.jar b/tester/jvm/Test_Mosaic.jar index 9d9305e416452d706e212527f0143e3dced2adfd..71d53deed1ff8e84513edab7bfb26c2b31042edf 100644 GIT binary patch literal 7683 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 JRTOvM{s-y8re**D literal 7671 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