1-
2- ///usr/bin/env jbang "$0" "$@" ; exit $?
1+ /// usr/bin/env jbang "$0" "$@" ; exit $?
32
43//SOURCES JythonCli.java
54
87//DEPS org.junit.platform:junit-platform-console:1.13.3
98
109import java .io .IOException ;
10+ import java .io .StringReader ;
1111
1212import static org .junit .jupiter .api .Assertions .*;
13- import org .junit .jupiter .api .Test ;
1413
14+ import org .junit .jupiter .api .Disabled ;
15+ import org .junit .jupiter .api .Test ;
1516import org .junit .platform .console .ConsoleLauncher ;
1617
1718/**
18- * A class to run tests on aspects of {@link JythonCli} by delegating to the
19- * JUnit console {@link ConsoleLauncher}.
19+ * A class to run tests on aspects of {@link JythonCli} by delegating to
20+ * the JUnit console {@link ConsoleLauncher}.
2021 */
2122public class TestJythonCli {
2223
23- static final String [] ARGS_DEBUG_FOO = {"--cli-debug" , "foo.py" , "bar" , "baz" };
24- static final String [] ARGS_FOO = {"--version" , "foo.py" , "bar.py" , "baz" };
24+ static final String [] ARGS_DEBUG_FOO =
25+ {"--cli-debug" , "foo.py" , "bar" , "baz" };
26+ static final String [] ARGS_FOO =
27+ {"--version" , "foo.py" , "bar.py" , "baz" };
28+ static final String [] ARGS_NONE = {"--cli-debug" };
2529
2630 /** The {@code --debug-cli} flag is spotted */
2731 @ Test
@@ -40,7 +44,7 @@ void testScriptFound() throws IOException {
4044 assertEquals ("foo.py" , cli .scriptFilename );
4145 }
4246
43- /** Argumnents to the Jython command are assembled in order. */
47+ /** Arguments to the Jython command are assembled in order. */
4448 @ Test
4549 void testJythonArgs () throws IOException {
4650 JythonCli cli = new JythonCli ();
@@ -51,6 +55,119 @@ void testJythonArgs() throws IOException {
5155 assertEquals ("baz" , cli .jythonArgs .get (3 ));
5256 }
5357
58+ /** An unterminated {@code jbang} block is an error. */
59+ @ Test
60+ @ Disabled ("readJBangBlock does not throw on an unterminated block" )
61+ void testUnterminated () throws IOException {
62+ String script = """
63+ # /// jbang
64+ # requires-jython = "2.7.2"
65+ # requires-java = "17"
66+ import sys
67+ """ ;
68+ JythonCli cli = new JythonCli ();
69+ assertThrows (Exception .class , () -> processScript (cli , script ));
70+ }
71+
72+ /**
73+ * An unterminated block may gobble up a {@code jbang} block. This
74+ * is not detectable by {@link JythonCli} as the text of a
75+ * {@code jbang} header could be legitimate content.
76+ */
77+ @ Test
78+ void testGobbledBlock () throws IOException {
79+ JythonCli cli = new JythonCli ();
80+ processScript (cli , """
81+ # /// script
82+ # requires-python = ">=3.11"
83+ # /// jbang
84+ # requires-jython = "2.7.2"
85+ # requires-java = "8"
86+ # ///
87+ """ );
88+ assertTrue (cli .tomlText .isEmpty (), "Check TOML text is empty" );
89+ assertNull (cli .tpr , "Check TOML parse not done" );
90+ }
91+
92+ /**
93+ * An unterminated {@code jbang} block should gobble up a following
94+ * block. This ought to be detectable by {@link JythonCli}. It isn't
95+ * actually a fault with the block delimiting: but the gobbled
96+ * block-start is not valid TOML.
97+ */
98+ @ Test
99+ @ Disabled ("interpretJBangBlock does not throw for invalid TOML" )
100+ void testCollision () throws IOException {
101+ String script = """
102+ # /// jbang
103+ # requires-jython = "2.7.2"
104+ # requires-java = "8"
105+ # /// script
106+ # requires-python = ">=3.11"
107+ # ///
108+ """ ;
109+ JythonCli cli = new JythonCli ();
110+ assertThrows (Exception .class , () -> processScript (cli , script ));
111+ assertFalse (cli .tomlText .isEmpty (), "Detect TOML text is empty" );
112+ assertTrue (cli .tpr .hasErrors (), "Check TOML parse reports errors" );
113+ }
114+
115+ /** Two {@code jbang} blocks is an error. */
116+ @ Test
117+ @ Disabled ("readJBangBlock does not throw on a second jbang block" )
118+ void testTwoBlocks () throws IOException {
119+ String script = """
120+ # /// jbang
121+ # requires-jython = "2.7.2"
122+ # requires-java = "8"
123+ # ///
124+
125+ # Valid but not for us
126+ # /// script
127+ # requires-python = ">=3.11"
128+ # ///
129+
130+ # /// jbang
131+ # requires-jython = "2.7.3"
132+ # ///
133+ """ ;
134+ JythonCli cli = new JythonCli ();
135+ assertThrows (Exception .class , () -> processScript (cli , script ));
136+ }
137+
138+ /** Invalid TOML is an error. */
139+ @ Test
140+ @ Disabled ("interpretJBangBlock does not throw for invalid TOML" )
141+ void testInvalidTOML () throws IOException {
142+ String script = """
143+ # /// jbang
144+ # requires-java = "8"
145+ # stuff = {
146+ # nonsense = 42
147+ # Quatsch =::
148+ # }
149+ # ///
150+ print("Hello World!")
151+ """ ;
152+ JythonCli cli = new JythonCli ();
153+ assertThrows (Exception .class , () -> processScript (cli , script ));
154+ }
155+
156+ /**
157+ * Take an initialised {@link JythonCli} and have it process (but
158+ * not run) the given {@code String} as if the contents of a file.
159+ *
160+ * @param cli to exercise
161+ * @param script to process as script
162+ * @throws IOException on StringReader errors
163+ */
164+ void processScript (JythonCli cli , String script )
165+ throws IOException {
166+ cli .initEnvironment (ARGS_NONE );
167+ cli .readJBangBlock (new StringReader (script ));
168+ cli .interpretJBangBlock ();
169+ }
170+
54171 /**
55172 * Run the JUnit console with arguments from our command line.
56173 *
0 commit comments