From: Thomas Walker Lynch Date: Tue, 5 Nov 2024 15:19:13 +0000 (+0000) Subject: adds tests for the utility classes, cleans up docs X-Git-Url: https://git.reasoningtechnology.com/style/static/git-favicon.png?a=commitdiff_plain;h=0d147f43f2c3f2d4a7917d8306453e0b8bb3cbcf;p=Ariadne adds tests for the utility classes, cleans up docs --- diff --git a/developer/document/GraphDirectedAcyclic.txt b/developer/document/GraphDirectedAcyclic.txt new file mode 100644 index 0000000..3da0b12 --- /dev/null +++ b/developer/document/GraphDirectedAcyclic.txt @@ -0,0 +1,77 @@ +Comment that was on the cycle detector code. Was useful for defining +the problem and limitations when defining the code. Might turn +into a list of constraints the user needs to adhere for the algorithm +to be guaranteed to function per spec. Has potential +to be turned into a proof of the algorithm. Begins by laying +out the assumptions the code is working under. + + +/* +Our build tool graph is directed from targets to dependencies. + +It must be cycle free. This class extends `Graph` by marking +cycles that are found when descending from root nodes. Then +`lookup` will not return these nodes. + +If: + + 1. The production functions produce the same output given the + same input. (Which is a given for the map definition portion of + the graph). + + 2. There are a finite number of states. + + 3. Any input values that are used in the definition of the graph are not + changed after some point in time when the graph is said to have been 'defined'. + + 4. No computed values are used for changing the graph definition. + + 5. No computed values direct graph traversal. + +Then: + + We can write an algorithm that in turn starts at each node + in the graph and searches for cycles, and will find all + cycles. + + Our GraphDirectedAcyclic constructor would then not need + to know the root nodes of the traversal. + +However: + + Had the graph definition been limited to the map object, and there is no + interaction with the build functions, we would meet the criteria. + + However, our bestowed upon the user the ability to define 'production' + functions, which are used to build the graph dynamically at run time. + + With such production functions is possible that a a graph definition would + emerge after a finite number of calls to the build function, and thus we still + meet the above criteria, and do not need to give a root node list to the + GraphDirectedAcyclic. + + When a graph is to be used with the build tool, it is required that the graph + meet the criteria above ** when starting from the root nodes **. However, it + is not generally required. Hence, we provide the root nodes to this function. + + It is possible that the user defines one or more production functions, + intentionally nor not, that results in building an unbounded graph definition. + Further it is possible for a user to define a production that has an unbounded + nature that results in the cycle marking method of this class from never + finishing. + + As examples, suppose that the a production follows the digits of pi, giving + a different node definition each time it is fed a label to recognize. Or + suppose that a production returns an ever longer node label each time it + is called. Such a production would cause the graph definition to be open, + and potentially for this cycle detection algorithm to never complete. + + A production for a conventional build environment will not do these things, + However, a buggy production for build environment, or an unconventional + build environment not imagined at this time, could. + + A breadth first search combined programmed as a generator would be able + to handle such cases without hanging. Where as this algorithm plunges + down depth first, and returns when it has the answer. + +*/ diff --git a/developer/document/dependency_graph.html b/developer/document/dependency_graph.html index 378c52d..a728d42 100644 --- a/developer/document/dependency_graph.html +++ b/developer/document/dependency_graph.html @@ -1,137 +1,151 @@ - Dependency Build Algorithm + Class and mature functions reference + -

Cycle Detection in Dependency Graph

-

Overview

-

- The is_acyclic_q function is designed to detect cycles in a dependency graph using a depth-first search (DFS) algorithm. It starts from a list of root node labels and traverses the graph to ensure that there are no cycles. If a cycle is detected, the function marks the nodes involved and continues to explore other parts of the graph. -

-

Key Concepts

- -

Functions

-

1. is_acyclic_q

-

- Purpose: To determine if the dependency graph is acyclic (i.e., contains no cycles). -

-

- Parameters: -

-

-

- Returns: -

-

-

- Process: -

-

-

2. is_acyclic_q_descend

-

- Purpose: To perform the actual DFS traversal and cycle detection for a given path. -

-

- Parameters: -

-

-

- Returns: -

-

-

- Process: -

-

-

Usage

-

- The is_acyclic_q function is used to ensure that the dependency graph defined in the build file is free of cycles. This is crucial for preventing infinite loops and ensuring that the build process can proceed smoothly. -

+
- - + A very rough first draft of a reference to the classes. + +

Cycle Detection on a Dependency Graph

+

Overview

-

2. Run Build Scripts

-
    -
  1. Traverse the queue starting from the tail (the most recently added nodes).
  2. -
  3. For each node, attempt to build it by checking the file dates of the target node and its dependencies: -
      -
    1. If the target file is older than any dependency, execute the node’s build function.
    2. -
    3. After building, recheck the file dates. If the file date has been updated, mark the node as successfully built.
    4. -
    5. If the build fails or the file date is not updated, mark the node with an error in its property list.
    6. -
    -
  4. -
  5. Nodes with dependencies marked with errors will not be built, and errors will propagate up the dependency tree.
  6. -
+

A Dependency Graph: Is a directed acyclic graph + where non-leaf nodes are build targets, which are either symbolic, or + correspond to files in the file system. Leave nodes correspond to files + in the file system, and the only edge property is 'dependency'.

-

3. Final Reporting and Status

-
    -
  1. If the root node is successfully built, report the success and any other successfully built nodes.
  2. -
  3. If an error has propagated to the root, report the failure.
  4. -
  5. Keep a list of all successfully built nodes and provide a final summary of the build status.
  6. -
+

Functions

-

4. Node Definitions

-

Each node in the dependency graph is defined by a property dictionary. A node is either a symbol or a path:

-
    -
  1. Symbol Nodes: These represent abstract concepts or commands and always trigger a build unless marked with an error.
  2. -
  3. Path Nodes: These represent file paths. A path node is considered built if its target file is newer than its dependencies.
  4. -
-

Both node types are identified by a label, and their dependencies are stored as a list of node labels. The presence of an error property indicates that the node has failed to build or encountered a problem during processing.

+

1. is_acyclic_q

+

+ Purpose: To determine if the dependency graph is acyclovir. +

+

+ Parameters: +

+

+

+ Returns: +

+

+

+ Process: +

+

+

2. is_acyclic_q_descend

+

+ Purpose: To perform the actual DFS traversal and cycle detection for a given path. +

+

+ Parameters: +

+

+

+ Returns: +

+

+

+ Process: +

+

+

Usage

+

+ The is_acyclic_q function is used to ensure that the dependency graph defined in the build file is free of cycles. This is crucial for preventing infinite loops and ensuring that the build process can proceed smoothly. +

+
diff --git a/developer/document/unique_node_label_check.txt b/developer/document/unique_node_label_check.txt deleted file mode 100644 index b978a74..0000000 --- a/developer/document/unique_node_label_check.txt +++ /dev/null @@ -1,15 +0,0 @@ - -predicate == is_well_formed_q - -We can not check that the node labels are unique because the given value -is a single node, and the code is stateless. Besides there is no contract with -the programmer on how to use the predicated, so the programmer could call the -predicate multiple times on the same node. Now can we test this condition in -our do_markup_graph routine because of the way lookup works, it will always -return the same node for the same label. This would be a truly difficult check -to perform because the map does not given an error but just takes the second of -the duplicate key definitions (is this really true?) besides, it would require -a formal proof of the recognizer functions that they do not return different -definitions for different keys to match regexprs against. I've been mulling -this over. As we currently the programmer provides the map and function -definitions, we don't even know which nodes will be in the graph... diff --git a/developer/javac/File.java b/developer/javac/File.java index b101ea8..109d7b6 100644 --- a/developer/javac/File.java +++ b/developer/javac/File.java @@ -1,8 +1,11 @@ package com.ReasoningTechnology.Ariadne; -import java.io.*; -import java.nio.file.*; -import java.util.*; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import com.ReasoningTechnology.Mosaic.IO; public class File { static boolean debug = false; diff --git a/developer/javac/GraphDirectedAcyclic.java b/developer/javac/GraphDirectedAcyclic.java index 51950d8..c71a2b9 100644 --- a/developer/javac/GraphDirectedAcyclic.java +++ b/developer/javac/GraphDirectedAcyclic.java @@ -1,75 +1,5 @@ package com.ReasoningTechnology.Ariadne; -/* -Our build tool graph is directed from targets to dependencies. - -It must be cycle free. This class extends `Graph` by marking -cycles that are found when descending from root nodes. Then -`lookup` will not return these nodes. - -If: - - 1. The production functions produce the same output given the - same input. (Which is a given for the map definition portion of - the graph). - - 2. There are a finite number of states. - - 3. Any input values that are used in the definition of the graph are not - changed after some point in time when the graph is said to have been 'defined'. - - 4. No computed values are used for changing the graph definition. - - 5. No computed values direct graph traversal. - -Then: - - We can write an algorithm that in turn starts at each node - in the graph and searches for cycles, and will find all - cycles. - - Our GraphDirectedAcyclic constructor would then not need - to know the root nodes of the traversal. - -However: - - Had the graph definition been limited to the map object, and there is no - interaction with the build functions, we would meet the criteria. - - However, our bestowed upon the user the ability to define 'production' - functions, which are used to build the graph dynamically at run time. - - With such production functions is possible that a a graph definition would - emerge after a finite number of calls to the build function, and thus we still - meet the above criteria, and do not need to give a root node list to the - GraphDirectedAcyclic. - - When a graph is to be used with the build tool, it is required that the graph - meet the criteria above ** when starting from the root nodes **. However, it - is not generally required. Hence, we provide the root nodes to this function. - - It is possible that the user defines one or more production functions, - intentionally nor not, that results in building an unbounded graph definition. - Further it is possible for a user to define a production that has an unbounded - nature that results in the cycle marking method of this class from never - finishing. - - As examples, suppose that the a production follows the digits of pi, giving - a different node definition each time it is fed a label to recognize. Or - suppose that a production returns an ever longer node label each time it - is called. Such a production would cause the graph definition to be open, - and potentially for this cycle detection algorithm to never complete. - - A production for a conventional build environment will not do these things, - However, a buggy production for build environment, or an unconventional - build environment not imagined at this time, could. - - A breadth first search combined programmed as a generator would be able - to handle such cases without hanging. Where as this algorithm plunges - down depth first, and returns when it has the answer. - -*/ - import java.util.HashMap; import java.util.Map; import java.util.List; diff --git a/developer/scratchpad/com/ReasoningTechnology/Ariadne/File.class b/developer/scratchpad/com/ReasoningTechnology/Ariadne/File.class new file mode 100644 index 0000000..ff433cb Binary files /dev/null and b/developer/scratchpad/com/ReasoningTechnology/Ariadne/File.class differ diff --git a/developer/scratchpad/com/ReasoningTechnology/Ariadne/Graph.class b/developer/scratchpad/com/ReasoningTechnology/Ariadne/Graph.class new file mode 100644 index 0000000..36d6001 Binary files /dev/null and b/developer/scratchpad/com/ReasoningTechnology/Ariadne/Graph.class differ diff --git a/developer/scratchpad/com/ReasoningTechnology/Ariadne/GraphDirectedAcyclic$1.class b/developer/scratchpad/com/ReasoningTechnology/Ariadne/GraphDirectedAcyclic$1.class new file mode 100644 index 0000000..f3158db Binary files /dev/null and b/developer/scratchpad/com/ReasoningTechnology/Ariadne/GraphDirectedAcyclic$1.class differ diff --git a/developer/scratchpad/com/ReasoningTechnology/Ariadne/GraphDirectedAcyclic$2.class b/developer/scratchpad/com/ReasoningTechnology/Ariadne/GraphDirectedAcyclic$2.class new file mode 100644 index 0000000..9214c15 Binary files /dev/null and b/developer/scratchpad/com/ReasoningTechnology/Ariadne/GraphDirectedAcyclic$2.class differ diff --git a/developer/scratchpad/com/ReasoningTechnology/Ariadne/GraphDirectedAcyclic.class b/developer/scratchpad/com/ReasoningTechnology/Ariadne/GraphDirectedAcyclic.class new file mode 100644 index 0000000..e987c4b Binary files /dev/null and b/developer/scratchpad/com/ReasoningTechnology/Ariadne/GraphDirectedAcyclic.class differ diff --git a/developer/scratchpad/com/ReasoningTechnology/Ariadne/Label.class b/developer/scratchpad/com/ReasoningTechnology/Ariadne/Label.class new file mode 100644 index 0000000..0bd129e Binary files /dev/null and b/developer/scratchpad/com/ReasoningTechnology/Ariadne/Label.class differ diff --git a/developer/scratchpad/com/ReasoningTechnology/Ariadne/LabelList.class b/developer/scratchpad/com/ReasoningTechnology/Ariadne/LabelList.class new file mode 100644 index 0000000..40f1a97 Binary files /dev/null and b/developer/scratchpad/com/ReasoningTechnology/Ariadne/LabelList.class differ diff --git a/developer/scratchpad/com/ReasoningTechnology/Ariadne/Node.class b/developer/scratchpad/com/ReasoningTechnology/Ariadne/Node.class new file mode 100644 index 0000000..a00c7a5 Binary files /dev/null and b/developer/scratchpad/com/ReasoningTechnology/Ariadne/Node.class differ diff --git a/developer/scratchpad/com/ReasoningTechnology/Ariadne/NodeList.class b/developer/scratchpad/com/ReasoningTechnology/Ariadne/NodeList.class new file mode 100644 index 0000000..4897461 Binary files /dev/null and b/developer/scratchpad/com/ReasoningTechnology/Ariadne/NodeList.class differ diff --git a/developer/scratchpad/com/ReasoningTechnology/Ariadne/Production.class b/developer/scratchpad/com/ReasoningTechnology/Ariadne/Production.class new file mode 100644 index 0000000..8fb153c Binary files /dev/null and b/developer/scratchpad/com/ReasoningTechnology/Ariadne/Production.class differ diff --git a/developer/scratchpad/com/ReasoningTechnology/Ariadne/ProductionList.class b/developer/scratchpad/com/ReasoningTechnology/Ariadne/ProductionList.class new file mode 100644 index 0000000..73b5e2c Binary files /dev/null and b/developer/scratchpad/com/ReasoningTechnology/Ariadne/ProductionList.class differ diff --git a/developer/scratchpad/com/ReasoningTechnology/Ariadne/Token.class b/developer/scratchpad/com/ReasoningTechnology/Ariadne/Token.class new file mode 100644 index 0000000..9c65237 Binary files /dev/null and b/developer/scratchpad/com/ReasoningTechnology/Ariadne/Token.class differ diff --git a/developer/scratchpad/com/ReasoningTechnology/Ariadne/TokenSet.class b/developer/scratchpad/com/ReasoningTechnology/Ariadne/TokenSet.class new file mode 100644 index 0000000..ec7275e Binary files /dev/null and b/developer/scratchpad/com/ReasoningTechnology/Ariadne/TokenSet.class differ diff --git a/developer/scratchpad/com/ReasoningTechnology/Ariadne/Util.class b/developer/scratchpad/com/ReasoningTechnology/Ariadne/Util.class new file mode 100644 index 0000000..4e01d3d Binary files /dev/null and b/developer/scratchpad/com/ReasoningTechnology/Ariadne/Util.class differ diff --git a/developer/shell/Build b/developer/shell/Build new file mode 100755 index 0000000..2a18026 --- /dev/null +++ b/developer/shell/Build @@ -0,0 +1,2 @@ +#!/bin/bash +java com.ReasoningTechnology."Ariadne".Build diff --git a/developer/shell/build b/developer/shell/build deleted file mode 100755 index f4d3bbc..0000000 --- a/developer/shell/build +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -java com/ReasoningTechnology/Ariadne/build diff --git a/document/todo.txt b/document/todo.txt index c8a6c76..1b081de 100644 --- a/document/todo.txt +++ b/document/todo.txt @@ -1,7 +1,7 @@ 2024-10-16T07:12:41Z[Ariadne_tester] -1. TestBench should be extracted as its own project. It holds the project independent +[done] 1. TestBench should be extracted as its own project. It holds the project independent part of the TestBench. 2. Project skeleton. @@ -9,10 +9,27 @@ part of the TestBench. PaintIt is the current project skeleton, it needs to be updated to match the structure of this project. -3. Because this is a Java Project + [Will circle back to PaintIt when Ariadne is done.] - 'executables' have a standard form (the JVM) so I allowed the 'executable' - directories to be checked into the repo. +3. Implementation in additional languges. + + It is a one language build environment. Currently that language is Java. The + graph definition is a Java map, the productions are Java functions, and the + triggered build functions are Java code. + + The build code could build anything that can be built by running Java code, so + this could be projects in other languages. Still after doing everything else + in Java it feels natural to use the tool to build Java programs. + + There is no reason this could not all be done in nodejs, for example, though + nodejs is not compiled, so there is no point in this. + + I think it could be a C++ program, though there is a dynamic portion to it, as + the graph definition is read by the running program, and the running program + expects to read the map, and call the loaded production functions. + + This would be an easy program to write to write in nodejs, or Lisp, but + development in those languages do not need this tool, as it already exists in + Java, it is not clear that benefits of having a 'cleaner' implementation would + justify the work. - In the future, if we want to allow binary release, there will be multiple - release directories with suffixes for the target platform. diff --git a/release/Ariadne.jar b/release/Ariadne.jar index e4b7b37..af08da9 100644 Binary files a/release/Ariadne.jar and b/release/Ariadne.jar differ diff --git a/release/Build b/release/Build new file mode 100755 index 0000000..2a18026 --- /dev/null +++ b/release/Build @@ -0,0 +1,2 @@ +#!/bin/bash +java com.ReasoningTechnology."Ariadne".Build diff --git a/release/build b/release/build deleted file mode 100755 index f4d3bbc..0000000 --- a/release/build +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -java com/ReasoningTechnology/Ariadne/build diff --git a/tester/data_Test_File_0/I_exist b/tester/data_Test_File_0/I_exist new file mode 100644 index 0000000..e69de29 diff --git a/tester/data_Test_File_0/file_0 b/tester/data_Test_File_0/file_0 new file mode 100644 index 0000000..e69de29 diff --git a/tester/data_Test_File_0/file_1 b/tester/data_Test_File_0/file_1 new file mode 100644 index 0000000..e69de29 diff --git a/tester/data_Test_File_0/file_2 b/tester/data_Test_File_0/file_2 new file mode 100644 index 0000000..e69de29 diff --git a/tester/data_Test_File_0/file_3 b/tester/data_Test_File_0/file_3 new file mode 100644 index 0000000..e69de29 diff --git a/tester/document/transcript_first_block_test.txt b/tester/document/transcript_first_block_test.txt deleted file mode 100644 index 06d4db2..0000000 --- a/tester/document/transcript_first_block_test.txt +++ /dev/null @@ -1,44 +0,0 @@ -2024-10-16T07:05:25Z[] -Thomas-developer@Blossac§/var/user_data/Thomas-developer§ -> cd Ariadne - -2024-10-16T07:05:29Z[] -Thomas-developer@Blossac§/var/user_data/Thomas-developer/Ariadne§ -> source env_tester -REPO_HOME /var/user_data/Thomas-developer/Ariadne/ -ENV tool_shared/bespoke/env -PROJECT Ariadne -ENV tester/tool/env - -2024-10-16T07:05:43Z[Ariadne_tester] -Thomas-developer@Blossac§/var/user_data/Thomas-developer/Ariadne/tester§ -> clean_build_directories -+ cd /var/user_data/Thomas-developer/Ariadne//tester -+ rm -r scratch_pad/com -+ rm jvm/TestBenchAriadne.jar -+ rm shell/TestBenchAriadne -+ set +x -clean_build_directories done. - -2024-10-16T07:05:53Z[Ariadne_tester] -Thomas-developer@Blossac§/var/user_data/Thomas-developer/Ariadne/tester§ -> make -Compiling files... -+ cd /var/user_data/Thomas-developer/Ariadne//tester -+ javac -d scratch_pad javac/TestBenchAriadne.java javac/TestBench.java -+ jar cf jvm/TestBenchAriadne.jar -C scratch_pad . -+ set +x -Creating shell wrappers... -tester/tool/environment done. - -2024-10-16T07:05:57Z[Ariadne_tester] -Thomas-developer@Blossac§/var/user_data/Thomas-developer/Ariadne/tester§ -> ./shell/TestBenchAriadne -Running Ariadne tests... -Total test_map run: 1 -Total test_map passed: 1 -Total test_map failed: 0 - -2024-10-16T07:06:00Z[Ariadne_tester] -Thomas-developer@Blossac§/var/user_data/Thomas-developer/Ariadne/tester§ -> diff --git a/tester/document/what_the_tests_do.txt b/tester/document/what_the_tests_do.txt deleted file mode 100644 index cba1483..0000000 --- a/tester/document/what_the_tests_do.txt +++ /dev/null @@ -1,9 +0,0 @@ - -test0 - see if the tool will compile when given an empty graph. - -test1 - see what happens with a single symbolic node - -javac/TestBenchAriadne - the remainder of the tests. - - - diff --git a/tester/javac/#Test2.javax# b/tester/javac/#Test2.javax# new file mode 100644 index 0000000..c38d8d5 --- /dev/null +++ b/tester/javac/#Test2.javax# @@ -0,0 +1,216 @@ +package com.ReasoningTechnology.Ariadne.TestBench; + +/* +Component smoke test. At least call each method of each class. + +*/ + + +import com.ReasoningTechnology.Ariadne.*; +import com.ReasoningTechnology.TestBench.*; +import java.util.List; +import java.util.Map; +import java.util.ArrayList; +import java.util.HashMap; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; + + +public class Test2 extends TestBench{ + + public static boolean test_Label_0(){ + boolean[] conditions = new boolean[2]; + int i = 0; + + // Test input + Label test_label = new Label("test"); + + // Expected output + String expected_value = "test"; + + // Actual output + conditions[i++] = test_label.get().equals(expected_value); + conditions[i++] = test_label.toString().equals(expected_value); + + return all(conditions); + } + + public static boolean test_Token_0(){ + boolean[] conditions = new boolean[4]; + int i = 0; + + // Test input + Token token = new Token("test_value"); + + // Check if the value is correctly stored and retrieved + conditions[i++] = token.get().equals("test_value"); + + // Check if the string representation is correct + conditions[i++] = token.toString().equals("test_value"); + + // Check equality with another Token object with the same value + Token another_token = new Token("test_value"); + conditions[i++] = token.equals( another_token ); + + // Check the hashCode consistency + conditions[i++] = token.hashCode() == another_token.hashCode(); + + return all(conditions); + } + + public static boolean test_LabelList_0(){ + LabelList label_list = new LabelList(); // Use the constructor + + // Add a label and check the size + label_list.add(new Label("test")); + return label_list.size() == 1; + } + + public static boolean test_Node_0(){ + Node node = new Node(); // Use the constructor + node.put("key", new Object()); + return node.containsKey("key"); + } + + public static boolean test_NodeList_0(){ + NodeList node_list = new NodeList(); // Use the constructor + + // Add a node and check the size + node_list.add(new Node()); // Use Node constructor + return node_list.size() == 1; + } + + public static boolean test_Production_0(){ + Production production = label -> new Node(); // Use the Node constructor + + // Apply the production function + Node node = production.apply(new Label("test")); + return node != null; + } + + public static boolean test_ProductionList_0(){ + ProductionList production_list = new ProductionList(); // Use the constructor + + // Add a production and check the size + production_list.add(label -> new Node()); // Use the Node constructor + return production_list.size() == 1; + } + + public static boolean test_TokenSet_0(){ + TokenSet token_set = new TokenSet(); // Use the constructor + + // Add a token and check if it's contained in the set + token_set.add(new Token("test")); + return token_set.contains(new Token("test")); + } + + public static boolean test_Graph_0() { + boolean[] conditions = new boolean[3]; + int i = 0; + + // Create an empty node map and a production list + Map node_map = new HashMap<>(); + ProductionList production_list = new ProductionList(); + + // Initialize the Graph + Graph graph = new Graph(node_map, production_list); + + // Test that lookup returns null for a non-existent node + Label non_existent_label = new Label("non_existent"); + conditions[i++] = graph.lookup(non_existent_label, false) == null; + + // Add a node to the map and test lookup + Node test_node = new Node(); + Label test_label = new Label("test"); + node_map.put(test_label, test_node); + conditions[i++] = graph.lookup(test_label, false) == test_node; + + // Test lookup with verbosity + conditions[i++] = graph.lookup(test_label).equals(test_node); + + // Return true if all conditions are met + return all(conditions); + } + + public static boolean test_Util_print_list_0(){ + boolean[] conditions = new boolean[1]; + int i = 0; + + String prefix = "Test List:"; + List items = new ArrayList<>(); + items.add("item1"); + items.add("item2"); + items.add("item3"); + + String expectedOutput = "Test List: 'item1', 'item2', 'item3'.\n"; + + ByteArrayOutputStream outContent = new ByteArrayOutputStream(); + PrintStream originalOut = System.out; + System.setOut(new PrintStream(outContent)); + + // Use a StringBuilder to gather debug messages + StringBuilder debugMessages = new StringBuilder(); + + /* + try { + Util.print_list(prefix, items); + String result = outContent.toString(); + + // Gather debug messages + debugMessages.append("Captured output: ").append(result).append("\n"); + debugMessages.append("Expected output: ").append(expectedOutput).append("\n"); + + conditions[i++] = result.equals(expectedOutput); + } catch (Exception e) { + conditions[i++] = false; + } finally { + System.setOut(originalOut); // Restore System.out + + // Now print the gathered debug messages + System.out.print(debugMessages.toString()); + } + */ + + try { + Util.print_list(prefix, items); + String result = outContent.toString(); + conditions[i++] = result.equals(expectedOutput); + } catch (Exception e) { + conditions[i++] = false; + } finally { + System.setOut(originalOut); + } + + return all(conditions); + } + + + // Method to run all tests + public static void test_Ariadne(){ + Map test_map = new HashMap<>(); + + // Adding tests to the map + test_map.put( "test_File_unpack_file_path_0", test_File_unpack_file_path_0() ); + test_map.put( "test_Label_0", test_Label_0() ); + test_map.put( "test_Token_0", test_Label_0() ); + test_map.put( "test_LabelList_0", test_LabelList_0() ); + test_map.put( "test_Node_0", test_Node_0() ); + test_map.put( "test_NodeList_0", test_NodeList_0() ); + test_map.put( "test_Production_0", test_Production_0() ); + test_map.put( "test_ProductionList_0", test_ProductionList_0() ); + test_map.put( "test_TokenSet_0", test_TokenSet_0() ); + test_map.put("test_Graph_0", test_Graph_0()); + test_map.put("test_Util_print_list_0", test_Util_print_list_0()); + + // Run the tests using TestBench + TestBench.run( test_map ); + } + + // Main function to provide a shell interface for running tests + public static void main(String[] args){ + System.out.println("Running Ariadne tests..."); + test_Ariadne(); // Calls the method to run all tests + } + +} + diff --git a/tester/javac/TestBench.java b/tester/javac/TestBench.java deleted file mode 100644 index 642d09f..0000000 --- a/tester/javac/TestBench.java +++ /dev/null @@ -1,220 +0,0 @@ -package com.ReasoningTechnology.TestBench; - -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; - - /* -------------------------------------------------------------------------------- - Test utility methods - */ - - // typically used to gather results before a return - public static boolean all(boolean[] conditions){ - for( boolean condition : conditions ){ - if( !condition ){ - return false; - } - } - return true; - } - - /* -------------------------------------------------------------------------------- - Test run helpers - */ - 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("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); - } - } - - 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); - } - -} diff --git a/tester/javac/TestTestBench.java b/tester/javac/TestTestBench.java deleted file mode 100644 index f9af752..0000000 --- a/tester/javac/TestTestBench.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.ReasoningTechnology.TestBench; - -/* -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_File_0.java b/tester/javac/Test_File_0.java new file mode 100644 index 0000000..383544d --- /dev/null +++ b/tester/javac/Test_File_0.java @@ -0,0 +1,109 @@ + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.attribute.FileTime; +import java.util.List; +import java.util.Map; + +import com.ReasoningTechnology.Ariadne.File; +import com.ReasoningTechnology.Mosaic.*; + +public class Test_File_0{ + + public class TestSuite{ + + public Boolean unpack_file_path_0(IO io){ + Boolean[] conditions = new Boolean[5]; + int i = 0; + + // Test input + String test_fp = "/home/user/test.txt"; + + // Expected output + String expected_dp = "/home/user/"; + String expected_fn = "test.txt"; + String expected_fn_base = "test"; + String expected_fn_ext = "txt"; + + // Actual output + Map result = File.unpack_file_path( test_fp ); + + conditions[i++] = result.get("dp").equals( expected_dp ); + conditions[i++] = result.get("fn").equals( expected_fn ); + conditions[i++] = result.get("fn_base").equals( expected_fn_base ); + conditions[i++] = result.get("fn_ext").equals( expected_fn_ext ); + conditions[i++] = result.size() == 4; + + // Return true if all conditions are met + return MU.all( conditions ); + } + + public Boolean file_exists_q_0(IO io) { + Boolean[] conditions = new Boolean[2]; + int i = 0; + + // Test file paths, assuming $REPO_HOME is set in the environment + String repoHome = System.getenv("REPO_HOME"); + String existingFilePath = repoHome + "/tester/data_Test_File_0/I_exist"; + String nonExistentFilePath = repoHome + "/tester/data_Test_File_0/I_do_not_exist"; + + // Test cases + conditions[i++] = File.file_exists_q(existingFilePath); // Expect true for existing file + conditions[i++] = !File.file_exists_q(nonExistentFilePath); // Expect false for non-existent file + + // Return true if both conditions are met + return MU.all(conditions); + } + + public Boolean newer_than_all_0(IO io) throws IOException { + Boolean[] conditions = new Boolean[5]; + int i = 0; + + String repoHome = System.getenv("REPO_HOME"); + + // Define paths for existing and missing files + String file_0 = repoHome + "/tester/data_Test_File_0/file_0"; + String file_1 = repoHome + "/tester/data_Test_File_0/file_1"; + String file_2 = repoHome + "/tester/data_Test_File_0/file_2"; + String file_3 = repoHome + "/tester/data_Test_File_0/file_3"; + String missing_file_0 = repoHome + "/tester/data_Test_File_0/missing_file_0"; + + // Set modification times: file_0 is the youngest, file_3 is the oldest + Files.setLastModifiedTime(Paths.get(file_3), FileTime.fromMillis(System.currentTimeMillis() - 20000)); + Files.setLastModifiedTime(Paths.get(file_2), FileTime.fromMillis(System.currentTimeMillis() - 15000)); + Files.setLastModifiedTime(Paths.get(file_1), FileTime.fromMillis(System.currentTimeMillis() - 10000)); + Files.setLastModifiedTime(Paths.get(file_0), FileTime.fromMillis(System.currentTimeMillis() - 5000)); + + // Test case 1: file_0 is newer than all other files + conditions[i++] = File.newer_than_all(file_0, List.of(file_1, file_2, file_3)); // Expect true + + // Test case 2: file_0 is newer than some, but not all (make file_2 newer) + Files.setLastModifiedTime(Paths.get(file_2), FileTime.fromMillis(System.currentTimeMillis() + 10000)); // file_2 is now newer + conditions[i++] = !File.newer_than_all(file_0, List.of(file_1, file_2, file_3)); // Expect false + + // Test case 3: file_0 is not newer than any (make both file_1 and file_2 newer) + Files.setLastModifiedTime(Paths.get(file_1), FileTime.fromMillis(System.currentTimeMillis() + 15000)); + conditions[i++] = !File.newer_than_all(file_0, List.of(file_1, file_2, file_3)); // Expect false + + // Test case 4: file_0 does not exist + conditions[i++] = !File.newer_than_all(missing_file_0, List.of(file_1, file_2, file_3)); // Expect false + + // Test case 5: Some files in the list are missing + conditions[i++] = !File.newer_than_all(file_0, List.of(file_1, missing_file_0)); // Expect false + + // Return true if all conditions pass + return MU.all(conditions); + } + + } + + public static void main(String[] args) { + TestSuite suite = new Test_File_0().new TestSuite(); + int result = TestBench.run(suite); + System.exit(result); + } + +} + diff --git a/tester/javac/Test_LabelList_0.java b/tester/javac/Test_LabelList_0.java new file mode 100644 index 0000000..ce17cd6 --- /dev/null +++ b/tester/javac/Test_LabelList_0.java @@ -0,0 +1,37 @@ +import java.util.List; +import java.util.Arrays; + +import com.ReasoningTechnology.Ariadne.Label; +import com.ReasoningTechnology.Ariadne.LabelList; +import com.ReasoningTechnology.Mosaic.*; + +public class Test_LabelList_0 { + + public class TestSuite { + + public Boolean labelList_creation_0(IO io) { + Boolean[] conditions = new Boolean[2]; + int i = 0; + + // Test the default constructor + LabelList emptyList = new LabelList(); + conditions[i++] = emptyList.isEmpty(); // Expect true for an empty list + + // Test the constructor with a list of labels + List