From ab06b3bcf9196306b3822aa83f18ade64c5e5991 Mon Sep 17 00:00:00 2001 From: Love Leifland Date: Mon, 19 Oct 2020 11:12:49 +0200 Subject: [PATCH 1/2] Enable code style check. --- build.gradle | 1 + config/checkstyle/checkstyle.xml | 108 +++++++++++++++++++++++++++++++ cypher-shell/build.gradle | 4 ++ 3 files changed, 113 insertions(+) create mode 100644 config/checkstyle/checkstyle.xml diff --git a/build.gradle b/build.gradle index 975ce1fa..c3522575 100644 --- a/build.gradle +++ b/build.gradle @@ -11,6 +11,7 @@ buildscript { allprojects { apply plugin: 'java' + apply plugin: 'checkstyle' sourceCompatibility = 1.8 targetCompatibility = 1.8 diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml new file mode 100644 index 00000000..fdc322ba --- /dev/null +++ b/config/checkstyle/checkstyle.xml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cypher-shell/build.gradle b/cypher-shell/build.gradle index 9945b5ea..096b0531 100644 --- a/cypher-shell/build.gradle +++ b/cypher-shell/build.gradle @@ -70,3 +70,7 @@ dependencies { testCompile "org.hamcrest:java-hamcrest:$hamcrestVersion" testCompileOnly "com.google.code.findbugs:annotations:$findbugsVersion" } + +checkstyle { + toolVersion = '8.35' +} \ No newline at end of file From 08c9b2ae6a40a78397380aa28486a026398ef60e Mon Sep 17 00:00:00 2001 From: Love Leifland Date: Mon, 19 Oct 2020 22:34:43 +0200 Subject: [PATCH 2/2] Apply mono repo code style. --- config/checkstyle/checkstyle.xml | 3 + .../org/neo4j/shell/MainIntegrationTest.java | 548 ++++++++------ .../org/neo4j/shell/StringLinePrinter.java | 35 +- .../CypherShellFailureIntegrationTest.java | 36 +- .../commands/CypherShellIntegrationTest.java | 22 +- ...pherShellMultiDatabaseIntegrationTest.java | 19 + .../CypherShellPlainIntegrationTest.java | 98 ++- .../CypherShellProtocolIntegrationTest.java | 59 +- ...CypherShellTransactionIntegrationTest.java | 21 +- .../CypherShellVerboseIntegrationTest.java | 196 +++-- .../org/neo4j/shell/ConnectionConfig.java | 92 ++- .../main/java/org/neo4j/shell/Connector.java | 33 +- .../java/org/neo4j/shell/CypherShell.java | 196 +++-- .../java/org/neo4j/shell/DatabaseManager.java | 26 +- .../main/java/org/neo4j/shell/Historian.java | 46 +- .../src/main/java/org/neo4j/shell/Main.java | 272 ++++--- .../java/org/neo4j/shell/ParameterMap.java | 32 +- .../org/neo4j/shell/ShellParameterMap.java | 25 +- .../java/org/neo4j/shell/ShellRunner.java | 160 ++-- .../org/neo4j/shell/StatementExecuter.java | 31 +- .../org/neo4j/shell/TransactionHandler.java | 25 +- .../java/org/neo4j/shell/TriFunction.java | 24 +- .../org/neo4j/shell/UserMessagesHandler.java | 69 +- .../java/org/neo4j/shell/build/Build.java | 62 +- .../shell/cli/AddParamArgumentAction.java | 32 +- .../org/neo4j/shell/cli/CliArgHelper.java | 283 +++---- .../java/org/neo4j/shell/cli/CliArgs.java | 238 +++--- .../java/org/neo4j/shell/cli/Encryption.java | 33 +- .../org/neo4j/shell/cli/FailBehavior.java | 22 +- .../org/neo4j/shell/cli/FileHistorian.java | 110 ++- .../main/java/org/neo4j/shell/cli/Format.java | 36 +- .../shell/cli/InteractiveShellRunner.java | 251 ++++--- .../shell/cli/NonInteractiveShellRunner.java | 76 +- .../java/org/neo4j/shell/commands/Begin.java | 57 +- .../org/neo4j/shell/commands/Command.java | 30 +- .../shell/commands/CommandExecutable.java | 22 +- .../neo4j/shell/commands/CommandHelper.java | 160 ++-- .../java/org/neo4j/shell/commands/Commit.java | 53 +- .../java/org/neo4j/shell/commands/Exit.java | 53 +- .../java/org/neo4j/shell/commands/Help.java | 143 ++-- .../org/neo4j/shell/commands/History.java | 67 +- .../java/org/neo4j/shell/commands/Param.java | 66 +- .../java/org/neo4j/shell/commands/Params.java | 109 ++- .../org/neo4j/shell/commands/Rollback.java | 53 +- .../java/org/neo4j/shell/commands/Source.java | 52 +- .../java/org/neo4j/shell/commands/Use.java | 55 +- .../exception/AnsiFormattedException.java | 48 +- .../shell/exception/CommandException.java | 41 +- .../exception/DuplicateCommandException.java | 27 +- .../neo4j/shell/exception/ExitException.java | 28 +- .../IncompleteStatementException.java | 22 +- .../shell/exception/NoMoreInputException.java | 25 +- .../UnconsumedStatementException.java | 22 +- .../neo4j/shell/log/AnsiFormattedText.java | 143 ++-- .../java/org/neo4j/shell/log/AnsiLogger.java | 165 +++-- .../main/java/org/neo4j/shell/log/Logger.java | 67 +- .../java/org/neo4j/shell/log/NullLogger.java | 19 + .../java/org/neo4j/shell/log/NullLogging.java | 19 + .../shell/parser/ShellStatementParser.java | 171 +++-- .../neo4j/shell/parser/StatementParser.java | 30 +- .../prettyprint/CypherVariablesFormatter.java | 52 +- .../neo4j/shell/prettyprint/LinePrinter.java | 24 +- .../shell/prettyprint/OutputFormatter.java | 389 ++++++---- .../neo4j/shell/prettyprint/PrettyConfig.java | 48 +- .../shell/prettyprint/PrettyPrinter.java | 98 ++- .../prettyprint/SimpleOutputFormatter.java | 73 +- .../prettyprint/StatisticsCollector.java | 112 ++- .../prettyprint/TableOutputFormatter.java | 252 ++++--- .../shell/prettyprint/TablePlanFormatter.java | 599 +++++++++------ .../org/neo4j/shell/state/BoltResult.java | 30 +- .../neo4j/shell/state/BoltStateHandler.java | 418 +++++++---- .../ErrorWhileInTransactionException.java | 19 + .../org/neo4j/shell/state/ListBoltResult.java | 50 +- .../org/neo4j/shell/state/ParamValue.java | 31 +- .../shell/state/StatementBoltResult.java | 37 +- .../java/org/neo4j/shell/system/Utils.java | 29 +- .../org/neo4j/shell/util/ParameterSetter.java | 89 ++- .../java/org/neo4j/shell/util/Version.java | 56 +- .../java/org/neo4j/shell/util/Versions.java | 92 ++- .../org/neo4j/shell/ConnectionConfigTest.java | 110 ++- .../java/org/neo4j/shell/CypherShellTest.java | 271 ++++--- .../java/org/neo4j/shell/HistorianTest.java | 29 +- .../test/java/org/neo4j/shell/MainTest.java | 487 ++++++------ .../org/neo4j/shell/OfflineTestShell.java | 35 +- .../neo4j/shell/ShellParameterMapTest.java | 55 +- .../java/org/neo4j/shell/ShellRunnerTest.java | 36 +- .../neo4j/shell/UserMessagesHandlerTest.java | 52 +- .../java/org/neo4j/shell/build/BuildTest.java | 33 +- .../org/neo4j/shell/cli/CliArgHelperTest.java | 269 ++++--- .../java/org/neo4j/shell/cli/CliArgsTest.java | 126 ++-- .../neo4j/shell/cli/CommandHelperTest.java | 49 +- .../neo4j/shell/cli/FileHistorianTest.java | 63 +- .../shell/cli/InteractiveShellRunnerTest.java | 690 ++++++++++-------- .../cli/NonInteractiveShellRunnerTest.java | 128 ++-- .../org/neo4j/shell/commands/BeginTest.java | 47 +- .../org/neo4j/shell/commands/CommitTest.java | 49 +- .../org/neo4j/shell/commands/ExitTest.java | 50 +- .../org/neo4j/shell/commands/HelpTest.java | 142 ++-- .../org/neo4j/shell/commands/HistoryTest.java | 64 +- .../org/neo4j/shell/commands/ParamTest.java | 196 +++-- .../org/neo4j/shell/commands/ParamsTest.java | 151 ++-- .../neo4j/shell/commands/RollbackTest.java | 51 +- .../org/neo4j/shell/commands/SourceTest.java | 75 +- .../org/neo4j/shell/commands/UseTest.java | 56 +- .../shell/log/AnsiFormattedTextTest.java | 96 ++- .../org/neo4j/shell/log/AnsiLoggerTest.java | 203 +++--- .../parser/ShellStatementParserTest.java | 432 ++++++----- .../CypherVariablesFormatterTest.java | 62 +- .../prettyprint/OutputFormatterTest.java | 32 +- .../shell/prettyprint/PrettyPrinterTest.java | 567 +++++++------- .../prettyprint/StatisticsCollectorTest.java | 50 +- .../prettyprint/TableOutputFormatterTest.java | 587 ++++++++------- .../prettyprint/TablePlanFormatterTest.java | 214 +++--- .../prettyprint/ToStringLinePrinter.java | 35 +- .../shell/state/BoltStateHandlerTest.java | 673 +++++++++-------- .../test/java/org/neo4j/shell/test/Util.java | 54 +- .../org/neo4j/shell/test/bolt/FakeDriver.java | 70 +- .../org/neo4j/shell/test/bolt/FakeRecord.java | 264 ++++--- .../org/neo4j/shell/test/bolt/FakeResult.java | 139 ++-- .../shell/test/bolt/FakeResultSummary.java | 68 +- .../neo4j/shell/test/bolt/FakeSession.java | 88 ++- .../shell/test/bolt/FakeTransaction.java | 53 +- .../org/neo4j/shell/test/bolt/FakeValue.java | 352 +++++---- .../org/neo4j/shell/util/VersionsTest.java | 52 +- ...expected-pretty-print-plan-information.txt | 14 + 125 files changed, 9465 insertions(+), 5410 deletions(-) create mode 100644 cypher-shell/src/test/resources/org/neo4j/shell/prettyprint/expected-pretty-print-plan-information.txt diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index fdc322ba..b4885d2b 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -97,9 +97,12 @@ + + diff --git a/cypher-shell/src/integration-test/java/org/neo4j/shell/MainIntegrationTest.java b/cypher-shell/src/integration-test/java/org/neo4j/shell/MainIntegrationTest.java index d7de275e..617da537 100644 --- a/cypher-shell/src/integration-test/java/org/neo4j/shell/MainIntegrationTest.java +++ b/cypher-shell/src/integration-test/java/org/neo4j/shell/MainIntegrationTest.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell; import org.junit.Before; @@ -50,19 +69,6 @@ public class MainIntegrationTest { private static String USER = "neo4j"; private static String PASSWORD = "neo"; - - private static class ShellAndConnection - { - CypherShell shell; - ConnectionConfig connectionConfig; - - ShellAndConnection( CypherShell shell, ConnectionConfig connectionConfig ) - { - this.shell = shell; - this.connectionConfig = connectionConfig; - } - } - @Rule public final ExpectedException exception = ExpectedException.none(); private String inputString = String.format( "%s%n%s%n", USER, PASSWORD ); @@ -76,131 +82,148 @@ private static class ShellAndConnection private ByteBuffer inputBuffer; @Before - public void setup() { + public void setup() + { // given - inputBuffer = ByteBuffer.allocate(256); - inputBuffer.put(inputString.getBytes()); - inputStream = new ByteArrayInputStream(inputBuffer.array()); + inputBuffer = ByteBuffer.allocate( 256 ); + inputBuffer.put( inputString.getBytes() ); + inputStream = new ByteArrayInputStream( inputBuffer.array() ); baos = new ByteArrayOutputStream(); - printStream = new PrintStream(baos); + printStream = new PrintStream( baos ); - main = new Main(inputStream, printStream); + main = new Main( inputStream, printStream ); cliArgs = new CliArgs(); - cliArgs.setUsername("", ""); - cliArgs.setPassword("", ""); + cliArgs.setUsername( "", "" ); + cliArgs.setPassword( "", "" ); ShellAndConnection sac = getShell( cliArgs ); shell = sac.shell; connectionConfig = sac.connectionConfig; } - private void ensureUser() throws Exception { - if (majorVersion(shell.getServerVersion() ) >= 4) { - shell.execute(":use " + SYSTEM_DB_NAME); - shell.execute("CREATE OR REPLACE USER foo SET PASSWORD 'pass';"); - shell.execute("GRANT ROLE reader TO foo;"); - shell.execute(":use"); - } else { - try { - shell.execute("CALL dbms.security.createUser('foo', 'pass', true)"); - } catch (ClientException e) { - if (e.code().equalsIgnoreCase("Neo.ClientError.General.InvalidArguments") && e.getMessage().contains("already exists")) { - shell.execute("CALL dbms.security.deleteUser('foo')"); - shell.execute("CALL dbms.security.createUser('foo', 'pass', true)"); + private void ensureUser() throws Exception + { + if ( majorVersion( shell.getServerVersion() ) >= 4 ) + { + shell.execute( ":use " + SYSTEM_DB_NAME ); + shell.execute( "CREATE OR REPLACE USER foo SET PASSWORD 'pass';" ); + shell.execute( "GRANT ROLE reader TO foo;" ); + shell.execute( ":use" ); + } + else + { + try + { + shell.execute( "CALL dbms.security.createUser('foo', 'pass', true)" ); + } + catch ( ClientException e ) + { + if ( e.code().equalsIgnoreCase( "Neo.ClientError.General.InvalidArguments" ) && e.getMessage().contains( "already exists" ) ) + { + shell.execute( "CALL dbms.security.deleteUser('foo')" ); + shell.execute( "CALL dbms.security.createUser('foo', 'pass', true)" ); } } } } - private void ensureDefaultDatabaseStarted() throws Exception { + private void ensureDefaultDatabaseStarted() throws Exception + { CliArgs cliArgs = new CliArgs(); - cliArgs.setUsername("neo4j", ""); - cliArgs.setPassword("neo", ""); - cliArgs.setDatabase("system"); - ShellAndConnection sac = getShell(cliArgs); - main.connectMaybeInteractively(sac.shell, sac.connectionConfig, true, false, true); - sac.shell.execute("START DATABASE " + DatabaseManager.DEFAULT_DEFAULT_DB_NAME); + cliArgs.setUsername( "neo4j", "" ); + cliArgs.setPassword( "neo", "" ); + cliArgs.setDatabase( "system" ); + ShellAndConnection sac = getShell( cliArgs ); + main.connectMaybeInteractively( sac.shell, sac.connectionConfig, true, false, true ); + sac.shell.execute( "START DATABASE " + DatabaseManager.DEFAULT_DEFAULT_DB_NAME ); } @Test - public void promptsOnWrongAuthenticationIfInteractive() throws Exception { + public void promptsOnWrongAuthenticationIfInteractive() throws Exception + { // when - assertEquals("", connectionConfig.username()); - assertEquals("", connectionConfig.password()); + assertEquals( "", connectionConfig.username() ); + assertEquals( "", connectionConfig.password() ); - main.connectMaybeInteractively(shell, connectionConfig, true, true, true); + main.connectMaybeInteractively( shell, connectionConfig, true, true, true ); // then // should be connected - assertTrue(shell.isConnected()); + assertTrue( shell.isConnected() ); // should have prompted and set the username and password - assertEquals(format("username: neo4j%npassword: ***%n"), baos.toString()); - assertEquals("neo4j", connectionConfig.username()); - assertEquals("neo", connectionConfig.password()); + assertEquals( format( "username: neo4j%npassword: ***%n" ), baos.toString() ); + assertEquals( "neo4j", connectionConfig.username() ); + assertEquals( "neo", connectionConfig.password() ); } @Test - public void promptsOnPasswordChangeRequired() throws Exception { + public void promptsOnPasswordChangeRequired() throws Exception + { int majorVersion = getVersionAndCreateUserWithPasswordChangeRequired(); - connectionConfig = getConnectionConfig(cliArgs); - assertEquals("", connectionConfig.username()); - assertEquals("", connectionConfig.password()); + connectionConfig = getConnectionConfig( cliArgs ); + assertEquals( "", connectionConfig.username() ); + assertEquals( "", connectionConfig.password() ); // when - inputBuffer.put(String.format("foo%npass%nnewpass%n").getBytes()); + inputBuffer.put( String.format( "foo%npass%nnewpass%n" ).getBytes() ); baos.reset(); - main.connectMaybeInteractively(shell, connectionConfig, true, true, true); + main.connectMaybeInteractively( shell, connectionConfig, true, true, true ); // then - assertTrue(shell.isConnected()); - if (majorVersion >= 4) { + assertTrue( shell.isConnected() ); + if ( majorVersion >= 4 ) + { // should have prompted to change the password String expectedChangePasswordOutput = format( "username: foo%npassword: ****%nPassword change required%nnew password: *******%n" ); - assertEquals( expectedChangePasswordOutput, baos.toString()); - assertEquals("foo", connectionConfig.username()); - assertEquals("newpass", connectionConfig.password()); - assertNull(connectionConfig.newPassword()); + assertEquals( expectedChangePasswordOutput, baos.toString() ); + assertEquals( "foo", connectionConfig.username() ); + assertEquals( "newpass", connectionConfig.password() ); + assertNull( connectionConfig.newPassword() ); // Should be able to execute read query - shell.execute("MATCH (n) RETURN count(n)"); - } else { + shell.execute( "MATCH (n) RETURN count(n)" ); + } + else + { // in 3.x we do not get credentials expired exception on connection, but when we try to access data String expectedChangePasswordOutput = format( "username: foo%npassword: ****%n" ); - assertEquals( expectedChangePasswordOutput, baos.toString()); - assertEquals("foo", connectionConfig.username()); - assertEquals("pass", connectionConfig.password()); + assertEquals( expectedChangePasswordOutput, baos.toString() ); + assertEquals( "foo", connectionConfig.username() ); + assertEquals( "pass", connectionConfig.password() ); // Should get exception with instructions on how to change password using procedure - exception.expect(ClientException.class); - exception.expectMessage("CALL dbms.changePassword"); - shell.execute("MATCH (n) RETURN count(n)"); + exception.expect( ClientException.class ); + exception.expectMessage( "CALL dbms.changePassword" ); + shell.execute( "MATCH (n) RETURN count(n)" ); } } @Test - public void allowUserToUpdateExpiredPasswordInteractivelyWithoutBeingPrompted() throws Exception { + public void allowUserToUpdateExpiredPasswordInteractivelyWithoutBeingPrompted() throws Exception + { //given a user that require a password change int majorVersion = getVersionAndCreateUserWithPasswordChangeRequired(); //when the user attempts a non-interactive password update - assumeTrue(majorVersion >= 4 ); + assumeTrue( majorVersion >= 4 ); baos.reset(); assertEquals( EXIT_SUCCESS, main.runShell( args( SYSTEM_DB_NAME, "foo", "pass", - "ALTER CURRENT USER SET PASSWORD from \"pass\" to \"pass2\";" ), shell, mock( Logger.class ) ) ); + "ALTER CURRENT USER SET PASSWORD from \"pass\" to \"pass2\";" ), shell, mock( Logger.class ) ) ); //we shouldn't ask for a new password assertEquals( "", baos.toString() ); //then the new user should be able to successfully connect, and run a command assertEquals( format( "n%n42%n" ), - executeNonInteractively( args( DEFAULT_DEFAULT_DB_NAME, - "foo", "pass2", "RETURN 42 AS n" ) ) ); + executeNonInteractively( args( DEFAULT_DEFAULT_DB_NAME, + "foo", "pass2", "RETURN 42 AS n" ) ) ); } @Test - public void shouldFailIfNonInteractivelySettingPasswordOnNonSystemDb() throws Exception { + public void shouldFailIfNonInteractivelySettingPasswordOnNonSystemDb() throws Exception + { //given a user that require a password change int majorVersion = getVersionAndCreateUserWithPasswordChangeRequired(); @@ -209,11 +232,12 @@ public void shouldFailIfNonInteractivelySettingPasswordOnNonSystemDb() throws Ex //then assertEquals( EXIT_FAILURE, main.runShell( args( DEFAULT_DEFAULT_DB_NAME, "foo", "pass", - "ALTER CURRENT USER SET PASSWORD from \"pass\" to \"pass2\";" ), shell, mock( Logger.class ) ) ); + "ALTER CURRENT USER SET PASSWORD from \"pass\" to \"pass2\";" ), shell, mock( Logger.class ) ) ); } @Test - public void shouldBePromptedIfRunningNonInteractiveCypherThatDoesntUpdatePassword() throws Exception { + public void shouldBePromptedIfRunningNonInteractiveCypherThatDoesntUpdatePassword() throws Exception + { //given a user that require a password change int majorVersion = getVersionAndCreateUserWithPasswordChangeRequired(); @@ -224,19 +248,20 @@ public void shouldBePromptedIfRunningNonInteractiveCypherThatDoesntUpdatePasswor inputBuffer.put( String.format( "pass2%n" ).getBytes() ); baos.reset(); assertEquals( EXIT_SUCCESS, main.runShell( args( DEFAULT_DEFAULT_DB_NAME, "foo", "pass", - "MATCH (n) RETURN n" ), shell, mock( Logger.class ) ) ); + "MATCH (n) RETURN n" ), shell, mock( Logger.class ) ) ); //then should ask for a new password assertEquals( format( "Password change required%nnew password: *****%n" ), baos.toString() ); //then the new user should be able to successfully connect, and run a command assertEquals( format( "n%n42%n" ), - executeNonInteractively( args( DEFAULT_DEFAULT_DB_NAME, - "foo", "pass2", "RETURN 42 AS n" ) ) ); + executeNonInteractively( args( DEFAULT_DEFAULT_DB_NAME, + "foo", "pass2", "RETURN 42 AS n" ) ) ); } @Test - public void shouldNotBePromptedIfRunningWithExplicitNonInteractiveCypherThatDoesntUpdatePassword() throws Exception { + public void shouldNotBePromptedIfRunningWithExplicitNonInteractiveCypherThatDoesntUpdatePassword() throws Exception + { //given a user that require a password change int majorVersion = getVersionAndCreateUserWithPasswordChangeRequired(); @@ -253,35 +278,39 @@ public void shouldNotBePromptedIfRunningWithExplicitNonInteractiveCypherThatDoes } @Test - public void doesNotPromptToStdOutOnWrongAuthenticationIfOutputRedirected() throws Exception { + public void doesNotPromptToStdOutOnWrongAuthenticationIfOutputRedirected() throws Exception + { // when - assertEquals("", connectionConfig.username()); - assertEquals("", connectionConfig.password()); + assertEquals( "", connectionConfig.username() ); + assertEquals( "", connectionConfig.password() ); // Redirect System.in and System.out InputStream stdIn = System.in; PrintStream stdOut = System.out; - System.setIn(inputStream); - System.setOut(printStream); + System.setIn( inputStream ); + System.setOut( printStream ); // Create a Main with the standard in and out - try { + try + { Main realMain = new Main(); - realMain.connectMaybeInteractively(shell, connectionConfig, true, false, true); + realMain.connectMaybeInteractively( shell, connectionConfig, true, false, true ); // then // should be connected - assertTrue(shell.isConnected()); + assertTrue( shell.isConnected() ); // should have prompted silently and set the username and password - assertEquals("neo4j", connectionConfig.username()); - assertEquals("neo", connectionConfig.password()); + assertEquals( "neo4j", connectionConfig.username() ); + assertEquals( "neo", connectionConfig.password() ); String out = baos.toString(); - assertEquals("", out); - } finally { + assertEquals( "", out ); + } + finally + { // Restore in and out - System.setIn(stdIn); - System.setOut(stdOut); + System.setIn( stdIn ); + System.setOut( stdOut ); } } @@ -299,7 +328,7 @@ public void wrongPortWithBolt() throws Exception exception.expect( ServiceUnavailableException.class ); exception.expectMessage( "Unable to connect to localhost:1234, ensure the database is running and that there is a working network connection to it" ); - main.connectMaybeInteractively( shell, connectionConfig, true, true, true); + main.connectMaybeInteractively( shell, connectionConfig, true, true, true ); } @Test @@ -316,122 +345,131 @@ public void wrongPortWithNeo4j() throws Exception exception.expect( ServiceUnavailableException.class ); // The error message here may be subject to change and is not stable across versions so let us not assert on it - main.connectMaybeInteractively( shell, connectionConfig, true, true, true); + main.connectMaybeInteractively( shell, connectionConfig, true, true, true ); } @Test - public void shouldAskForCredentialsWhenConnectingWithAFile() throws Exception { + public void shouldAskForCredentialsWhenConnectingWithAFile() throws Exception + { //given - assertEquals("", connectionConfig.username()); - assertEquals("", connectionConfig.password()); + assertEquals( "", connectionConfig.username() ); + assertEquals( "", connectionConfig.password() ); //when CliArgs cliArgs = new CliArgs(); - cliArgs.setInputFilename(fileFromResource("single.cypher")); - ShellAndConnection sac = getShell(cliArgs); + cliArgs.setInputFilename( fileFromResource( "single.cypher" ) ); + ShellAndConnection sac = getShell( cliArgs ); CypherShell shell = sac.shell; ConnectionConfig connectionConfig = sac.connectionConfig; - main.connectMaybeInteractively( shell, connectionConfig, true, true, true); + main.connectMaybeInteractively( shell, connectionConfig, true, true, true ); // then we should have prompted and set the username and password assertEquals( format( "username: neo4j%npassword: ***%n" ), baos.toString() ); - assertEquals("neo4j", connectionConfig.username()); - assertEquals("neo", connectionConfig.password()); + assertEquals( "neo4j", connectionConfig.username() ); + assertEquals( "neo", connectionConfig.password() ); } @Test - public void shouldReadSingleCypherStatementsFromFile() throws Exception { - assertEquals(format( "result%n42%n" ), executeFileNonInteractively(fileFromResource("single.cypher"))); + public void shouldReadSingleCypherStatementsFromFile() throws Exception + { + assertEquals( format( "result%n42%n" ), executeFileNonInteractively( fileFromResource( "single.cypher" ) ) ); } @Test - public void shouldReadEmptyCypherStatementsFile() throws Exception { - assertEquals("", executeFileNonInteractively(fileFromResource("empty.cypher"))); + public void shouldReadEmptyCypherStatementsFile() throws Exception + { + assertEquals( "", executeFileNonInteractively( fileFromResource( "empty.cypher" ) ) ); } @Test - public void shouldReadMultipleCypherStatementsFromFile() throws Exception { - assertEquals(format( "result%n42%n" + + public void shouldReadMultipleCypherStatementsFromFile() throws Exception + { + assertEquals( format( "result%n42%n" + "result%n1337%n" + - "result%n\"done\"%n"), executeFileNonInteractively(fileFromResource("multiple.cypher"))); + "result%n\"done\"%n" ), executeFileNonInteractively( fileFromResource( "multiple.cypher" ) ) ); } @Test - public void shouldFailIfInputFileDoesntExist() throws Exception { + public void shouldFailIfInputFileDoesntExist() throws Exception + { //given ByteArrayOutputStream out = new ByteArrayOutputStream(); - Logger logger = new AnsiLogger( false, Format.VERBOSE, new PrintStream( out ), new PrintStream( out )); + Logger logger = new AnsiLogger( false, Format.VERBOSE, new PrintStream( out ), new PrintStream( out ) ); //when - executeFileNonInteractively("what.cypher", logger); + executeFileNonInteractively( "what.cypher", logger ); //then - assertEquals( format("what.cypher (No such file or directory)%n"), out.toString()); + assertEquals( format( "what.cypher (No such file or directory)%n" ), out.toString() ); } @Test - public void shouldHandleInvalidCypherFromFile() throws Exception { + public void shouldHandleInvalidCypherFromFile() throws Exception + { //given - Logger logger = mock(Logger.class); - + Logger logger = mock( Logger.class ); // when - String actual = executeFileNonInteractively( fileFromResource( "invalid.cypher" ), logger); + String actual = executeFileNonInteractively( fileFromResource( "invalid.cypher" ), logger ); //then we print the first valid row assertEquals( format( "result%n42%n" ), actual ); //and print errors to the error log - verify(logger).printError(any( ClientException.class )); - verifyNoMoreInteractions(logger); + verify( logger ).printError( any( ClientException.class ) ); + verifyNoMoreInteractions( logger ); } @Test - public void shouldReadSingleCypherStatementsFromFileInteractively() throws Exception { + public void shouldReadSingleCypherStatementsFromFileInteractively() throws Exception + { // given ToStringLinePrinter linePrinter = new ToStringLinePrinter(); CypherShell shell = interactiveShell( linePrinter ); // when - shell.execute( ":source " + fileFromResource( "single.cypher" )); + shell.execute( ":source " + fileFromResource( "single.cypher" ) ); exit( shell ); // then - assertEquals( format("result%n42%n"), linePrinter.result() ); + assertEquals( format( "result%n42%n" ), linePrinter.result() ); } @Test - public void shouldReadMultipleCypherStatementsFromFileInteractively() throws Exception { + public void shouldReadMultipleCypherStatementsFromFileInteractively() throws Exception + { // given ToStringLinePrinter linePrinter = new ToStringLinePrinter(); CypherShell shell = interactiveShell( linePrinter ); // when - shell.execute( ":source " + fileFromResource( "multiple.cypher" )); + shell.execute( ":source " + fileFromResource( "multiple.cypher" ) ); exit( shell ); // then - assertEquals(format( "result%n42%n" + - "result%n1337%n" + - "result%n\"done\"%n"), linePrinter.result() ); + assertEquals( format( "result%n42%n" + + "result%n1337%n" + + "result%n\"done\"%n" ), linePrinter.result() ); } @Test - public void shouldReadEmptyCypherStatementsFromFileInteractively() throws Exception { + public void shouldReadEmptyCypherStatementsFromFileInteractively() throws Exception + { // given ToStringLinePrinter linePrinter = new ToStringLinePrinter(); CypherShell shell = interactiveShell( linePrinter ); // when - shell.execute( ":source " + fileFromResource( "empty.cypher" )); + shell.execute( ":source " + fileFromResource( "empty.cypher" ) ); exit( shell ); // then - assertEquals("", linePrinter.result() ); + assertEquals( "", linePrinter.result() ); } @Test - public void shouldHandleInvalidCypherStatementsFromFileInteractively() throws Exception { + public void shouldHandleInvalidCypherStatementsFromFileInteractively() throws Exception + { // given ToStringLinePrinter linePrinter = new ToStringLinePrinter(); CypherShell shell = interactiveShell( linePrinter ); @@ -439,234 +477,261 @@ public void shouldHandleInvalidCypherStatementsFromFileInteractively() throws Ex // then exception.expect( ClientException.class ); exception.expectMessage( "Invalid input 'T" ); - shell.execute( ":source " + fileFromResource( "invalid.cypher" )); + shell.execute( ":source " + fileFromResource( "invalid.cypher" ) ); } @Test - public void shouldFailIfInputFileDoesntExistInteractively() throws Exception { + public void shouldFailIfInputFileDoesntExistInteractively() throws Exception + { // given ToStringLinePrinter linePrinter = new ToStringLinePrinter(); CypherShell shell = interactiveShell( linePrinter ); // expect - exception.expect( CommandException.class); + exception.expect( CommandException.class ); exception.expectMessage( "Cannot find file: 'what.cypher'" ); exception.expectCause( isA( FileNotFoundException.class ) ); shell.execute( ":source what.cypher" ); } @Test - public void doesNotStartWhenDefaultDatabaseUnavailableIfInteractive() throws Exception { - shell.setCommandHelper(new CommandHelper(mock(Logger.class), Historian.empty, shell)); - inputBuffer.put(String.format("neo4j%nneo%n").getBytes()); + public void doesNotStartWhenDefaultDatabaseUnavailableIfInteractive() throws Exception + { + shell.setCommandHelper( new CommandHelper( mock( Logger.class ), Historian.empty, shell ) ); + inputBuffer.put( String.format( "neo4j%nneo%n" ).getBytes() ); - assertEquals("", connectionConfig.username()); - assertEquals("", connectionConfig.password()); + assertEquals( "", connectionConfig.username() ); + assertEquals( "", connectionConfig.password() ); // when - main.connectMaybeInteractively(shell, connectionConfig, true, true, true); + main.connectMaybeInteractively( shell, connectionConfig, true, true, true ); // Multiple databases are only available from 4.0 assumeTrue( majorVersion( shell.getServerVersion() ) >= 4 ); // then // should be connected - assertTrue(shell.isConnected()); + assertTrue( shell.isConnected() ); // should have prompted and set the username and password String expectedLoginOutput = format( "username: neo4j%npassword: ***%n" ); - assertEquals(expectedLoginOutput, baos.toString()); - assertEquals("neo4j", connectionConfig.username()); - assertEquals("neo", connectionConfig.password()); + assertEquals( expectedLoginOutput, baos.toString() ); + assertEquals( "neo4j", connectionConfig.username() ); + assertEquals( "neo", connectionConfig.password() ); // Stop the default database - shell.execute(":use " + SYSTEM_DB_NAME); - shell.execute("STOP DATABASE " + DatabaseManager.DEFAULT_DEFAULT_DB_NAME); + shell.execute( ":use " + SYSTEM_DB_NAME ); + shell.execute( "STOP DATABASE " + DatabaseManager.DEFAULT_DEFAULT_DB_NAME ); - try { + try + { shell.disconnect(); // Should get exception that database is unavailable when trying to connect - main.connectMaybeInteractively(shell, connectionConfig, true, true, true); - fail("No exception thrown"); - } catch(TransientException|ServiceUnavailableException e) { - expectDatabaseUnavailable(e, "neo4j"); - } finally { + main.connectMaybeInteractively( shell, connectionConfig, true, true, true ); + fail( "No exception thrown" ); + } + catch ( TransientException | ServiceUnavailableException e ) + { + expectDatabaseUnavailable( e, "neo4j" ); + } + finally + { // Start the default database again ensureDefaultDatabaseStarted(); } } @Test - public void startsAgainstSystemDatabaseWhenDefaultDatabaseUnavailableIfInteractive() throws Exception { - shell.setCommandHelper(new CommandHelper(mock(Logger.class), Historian.empty, shell)); + public void startsAgainstSystemDatabaseWhenDefaultDatabaseUnavailableIfInteractive() throws Exception + { + shell.setCommandHelper( new CommandHelper( mock( Logger.class ), Historian.empty, shell ) ); - assertEquals("", connectionConfig.username()); - assertEquals("", connectionConfig.password()); + assertEquals( "", connectionConfig.username() ); + assertEquals( "", connectionConfig.password() ); // when - main.connectMaybeInteractively(shell, connectionConfig, true, true, true); + main.connectMaybeInteractively( shell, connectionConfig, true, true, true ); // Multiple databases are only available from 4.0 assumeTrue( majorVersion( shell.getServerVersion() ) >= 4 ); // then // should be connected - assertTrue(shell.isConnected()); + assertTrue( shell.isConnected() ); // should have prompted and set the username and password String expectedLoginOutput = format( "username: neo4j%npassword: ***%n" ); - assertEquals(expectedLoginOutput, baos.toString()); - assertEquals("neo4j", connectionConfig.username()); - assertEquals("neo", connectionConfig.password()); + assertEquals( expectedLoginOutput, baos.toString() ); + assertEquals( "neo4j", connectionConfig.username() ); + assertEquals( "neo", connectionConfig.password() ); // Stop the default database - shell.execute(":use " + SYSTEM_DB_NAME); - shell.execute("STOP DATABASE " + DatabaseManager.DEFAULT_DEFAULT_DB_NAME); + shell.execute( ":use " + SYSTEM_DB_NAME ); + shell.execute( "STOP DATABASE " + DatabaseManager.DEFAULT_DEFAULT_DB_NAME ); - try { + try + { shell.disconnect(); // Connect to system database CliArgs cliArgs = new CliArgs(); - cliArgs.setUsername("neo4j", ""); - cliArgs.setPassword("neo", ""); - cliArgs.setDatabase("system"); - ShellAndConnection sac = getShell(cliArgs); + cliArgs.setUsername( "neo4j", "" ); + cliArgs.setPassword( "neo", "" ); + cliArgs.setDatabase( "system" ); + ShellAndConnection sac = getShell( cliArgs ); // Use the new shell and connection config from here on shell = sac.shell; connectionConfig = sac.connectionConfig; - main.connectMaybeInteractively(shell, connectionConfig, true, false, true); + main.connectMaybeInteractively( shell, connectionConfig, true, false, true ); // then - assertTrue(shell.isConnected()); - } finally { + assertTrue( shell.isConnected() ); + } + finally + { // Start the default database again ensureDefaultDatabaseStarted(); } } @Test - public void switchingToUnavailableDatabaseIfInteractive() throws Exception { - shell.setCommandHelper(new CommandHelper(mock(Logger.class), Historian.empty, shell)); - inputBuffer.put(String.format("neo4j%nneo%n").getBytes()); + public void switchingToUnavailableDatabaseIfInteractive() throws Exception + { + shell.setCommandHelper( new CommandHelper( mock( Logger.class ), Historian.empty, shell ) ); + inputBuffer.put( String.format( "neo4j%nneo%n" ).getBytes() ); - assertEquals("", connectionConfig.username()); - assertEquals("", connectionConfig.password()); + assertEquals( "", connectionConfig.username() ); + assertEquals( "", connectionConfig.password() ); // when - main.connectMaybeInteractively(shell, connectionConfig, true, true, true); + main.connectMaybeInteractively( shell, connectionConfig, true, true, true ); // Multiple databases are only available from 4.0 - assumeTrue(majorVersion( shell.getServerVersion() ) >= 4); + assumeTrue( majorVersion( shell.getServerVersion() ) >= 4 ); // then // should be connected - assertTrue(shell.isConnected()); + assertTrue( shell.isConnected() ); // should have prompted and set the username and password String expectedLoginOutput = format( "username: neo4j%npassword: ***%n" ); - assertEquals(expectedLoginOutput, baos.toString()); - assertEquals("neo4j", connectionConfig.username()); - assertEquals("neo", connectionConfig.password()); + assertEquals( expectedLoginOutput, baos.toString() ); + assertEquals( "neo4j", connectionConfig.username() ); + assertEquals( "neo", connectionConfig.password() ); // Stop the default database - shell.execute(":use " + SYSTEM_DB_NAME); - shell.execute("STOP DATABASE " + DatabaseManager.DEFAULT_DEFAULT_DB_NAME); + shell.execute( ":use " + SYSTEM_DB_NAME ); + shell.execute( "STOP DATABASE " + DatabaseManager.DEFAULT_DEFAULT_DB_NAME ); - try { + try + { // Should get exception that database is unavailable when trying to connect - shell.execute(":use " + DatabaseManager.DEFAULT_DEFAULT_DB_NAME); - fail("No exception thrown"); - } catch(TransientException|ServiceUnavailableException e) { - expectDatabaseUnavailable(e, "neo4j"); - } finally { + shell.execute( ":use " + DatabaseManager.DEFAULT_DEFAULT_DB_NAME ); + fail( "No exception thrown" ); + } + catch ( TransientException | ServiceUnavailableException e ) + { + expectDatabaseUnavailable( e, "neo4j" ); + } + finally + { // Start the default database again ensureDefaultDatabaseStarted(); } } @Test - public void switchingToUnavailableDefaultDatabaseIfInteractive() throws Exception { - shell.setCommandHelper(new CommandHelper(mock(Logger.class), Historian.empty, shell)); - inputBuffer.put(String.format("neo4j%nneo%n").getBytes()); + public void switchingToUnavailableDefaultDatabaseIfInteractive() throws Exception + { + shell.setCommandHelper( new CommandHelper( mock( Logger.class ), Historian.empty, shell ) ); + inputBuffer.put( String.format( "neo4j%nneo%n" ).getBytes() ); - assertEquals("", connectionConfig.username()); - assertEquals("", connectionConfig.password()); + assertEquals( "", connectionConfig.username() ); + assertEquals( "", connectionConfig.password() ); // when - main.connectMaybeInteractively(shell, connectionConfig, true, true, true); + main.connectMaybeInteractively( shell, connectionConfig, true, true, true ); // Multiple databases are only available from 4.0 - assumeTrue(majorVersion( shell.getServerVersion() ) >= 4); + assumeTrue( majorVersion( shell.getServerVersion() ) >= 4 ); // then // should be connected - assertTrue(shell.isConnected()); + assertTrue( shell.isConnected() ); // should have prompted and set the username and password String expectedLoginOutput = format( "username: neo4j%npassword: ***%n" ); - assertEquals(expectedLoginOutput, baos.toString()); - assertEquals("neo4j", connectionConfig.username()); - assertEquals("neo", connectionConfig.password()); + assertEquals( expectedLoginOutput, baos.toString() ); + assertEquals( "neo4j", connectionConfig.username() ); + assertEquals( "neo", connectionConfig.password() ); // Stop the default database - shell.execute(":use " + SYSTEM_DB_NAME); - shell.execute("STOP DATABASE " + DatabaseManager.DEFAULT_DEFAULT_DB_NAME); + shell.execute( ":use " + SYSTEM_DB_NAME ); + shell.execute( "STOP DATABASE " + DatabaseManager.DEFAULT_DEFAULT_DB_NAME ); - try { + try + { // Should get exception that database is unavailable when trying to connect - shell.execute(":use"); - fail("No exception thrown"); - } catch(TransientException|ServiceUnavailableException e) { - expectDatabaseUnavailable(e, "neo4j"); - } finally { + shell.execute( ":use" ); + fail( "No exception thrown" ); + } + catch ( TransientException | ServiceUnavailableException e ) + { + expectDatabaseUnavailable( e, "neo4j" ); + } + finally + { // Start the default database again ensureDefaultDatabaseStarted(); } } - private void expectDatabaseUnavailable(Throwable e, String dbName) { - String msg = new AnsiLogger(false).getFormattedMessage(e); - assertThat(msg, anyOf( - containsString("Database '" + dbName +"' is unavailable"), - containsString("Unable to get a routing table for database '" + dbName + "' because this database is unavailable") - )); + private void expectDatabaseUnavailable( Throwable e, String dbName ) + { + String msg = new AnsiLogger( false ).getFormattedMessage( e ); + assertThat( msg, anyOf( + containsString( "Database '" + dbName + "' is unavailable" ), + containsString( "Unable to get a routing table for database '" + dbName + "' because this database is unavailable" ) + ) ); } - private String executeFileNonInteractively(String filename) { - return executeFileNonInteractively(filename, mock(Logger.class)); + private String executeFileNonInteractively( String filename ) + { + return executeFileNonInteractively( filename, mock( Logger.class ) ); } - private String executeFileNonInteractively(String filename, Logger logger) { + private String executeFileNonInteractively( String filename, Logger logger ) + { CliArgs cliArgs = new CliArgs(); cliArgs.setUsername( USER, "" ); cliArgs.setPassword( PASSWORD, "" ); - cliArgs.setInputFilename(filename); + cliArgs.setInputFilename( filename ); - return executeNonInteractively( cliArgs, logger ); + return executeNonInteractively( cliArgs, logger ); } - private String executeNonInteractively(CliArgs cliArgs) { - return executeNonInteractively(cliArgs, mock(Logger.class)); + private String executeNonInteractively( CliArgs cliArgs ) + { + return executeNonInteractively( cliArgs, mock( Logger.class ) ); } - private String executeNonInteractively(CliArgs cliArgs, Logger logger) + private String executeNonInteractively( CliArgs cliArgs, Logger logger ) { ToStringLinePrinter linePrinter = new ToStringLinePrinter(); ShellAndConnection sac = getShell( cliArgs, linePrinter ); CypherShell shell = sac.shell; - main.runShell(cliArgs, shell, logger); + main.runShell( cliArgs, shell, logger ); return linePrinter.result(); } - private String fileFromResource(String filename) + private String fileFromResource( String filename ) { - return getClass().getClassLoader().getResource(filename).getFile(); + return getClass().getClassLoader().getResource( filename ).getFile(); } private CypherShell interactiveShell( LinePrinter linePrinter ) throws Exception { PrettyConfig prettyConfig = new PrettyConfig( new CliArgs() ); CypherShell shell = new CypherShell( linePrinter, prettyConfig, true, new ShellParameterMap() ); - main.connectMaybeInteractively( shell, connectionConfig, true, true, true); - shell.setCommandHelper( new CommandHelper( mock( Logger.class ), Historian.empty, shell) ); + main.connectMaybeInteractively( shell, connectionConfig, true, true, true ); + shell.setCommandHelper( new CommandHelper( mock( Logger.class ), Historian.empty, shell ) ); return shell; } @@ -701,7 +766,7 @@ private void exit( CypherShell shell ) throws CommandException try { shell.execute( ":exit" ); - fail("Should have exited"); + fail( "Should have exited" ); } catch ( ExitException e ) { @@ -709,7 +774,7 @@ private void exit( CypherShell shell ) throws CommandException } } - private CliArgs args(String db, String user, String pass, String cypher) + private CliArgs args( String db, String user, String pass, String cypher ) { CliArgs cliArgs = new CliArgs(); cliArgs.setUsername( user, "" ); @@ -719,10 +784,11 @@ private CliArgs args(String db, String user, String pass, String cypher) return cliArgs; } - private int getVersionAndCreateUserWithPasswordChangeRequired() throws Exception { + private int getVersionAndCreateUserWithPasswordChangeRequired() throws Exception + { shell.setCommandHelper( new CommandHelper( mock( Logger.class ), Historian.empty, shell ) ); - main.connectMaybeInteractively( shell, connectionConfig, true, true, true); + main.connectMaybeInteractively( shell, connectionConfig, true, true, true ); String expectedLoginOutput = format( "username: neo4j%npassword: ***%n" ); assertEquals( expectedLoginOutput, baos.toString() ); ensureUser(); @@ -730,4 +796,16 @@ private int getVersionAndCreateUserWithPasswordChangeRequired() throws Exception shell.disconnect(); return majorVersion; } + + private static class ShellAndConnection + { + CypherShell shell; + ConnectionConfig connectionConfig; + + ShellAndConnection( CypherShell shell, ConnectionConfig connectionConfig ) + { + this.shell = shell; + this.connectionConfig = connectionConfig; + } + } } diff --git a/cypher-shell/src/integration-test/java/org/neo4j/shell/StringLinePrinter.java b/cypher-shell/src/integration-test/java/org/neo4j/shell/StringLinePrinter.java index ed03598b..973fd7ea 100644 --- a/cypher-shell/src/integration-test/java/org/neo4j/shell/StringLinePrinter.java +++ b/cypher-shell/src/integration-test/java/org/neo4j/shell/StringLinePrinter.java @@ -1,22 +1,45 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell; import org.neo4j.shell.prettyprint.LinePrinter; import org.neo4j.shell.prettyprint.OutputFormatter; -public class StringLinePrinter implements LinePrinter { +public class StringLinePrinter implements LinePrinter +{ private StringBuilder sb = new StringBuilder(); @Override - public void printOut(String line) { - sb.append(line).append(OutputFormatter.NEWLINE); + public void printOut( String line ) + { + sb.append( line ).append( OutputFormatter.NEWLINE ); } - public void clear() { - sb.setLength(0); + public void clear() + { + sb.setLength( 0 ); } - public String output() { + public String output() + { return sb.toString(); } } diff --git a/cypher-shell/src/integration-test/java/org/neo4j/shell/commands/CypherShellFailureIntegrationTest.java b/cypher-shell/src/integration-test/java/org/neo4j/shell/commands/CypherShellFailureIntegrationTest.java index 76722374..678573dd 100644 --- a/cypher-shell/src/integration-test/java/org/neo4j/shell/commands/CypherShellFailureIntegrationTest.java +++ b/cypher-shell/src/integration-test/java/org/neo4j/shell/commands/CypherShellFailureIntegrationTest.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.commands; import org.junit.Before; @@ -13,23 +32,26 @@ import org.neo4j.shell.exception.CommandException; import org.neo4j.shell.prettyprint.PrettyConfig; -public class CypherShellFailureIntegrationTest extends CypherShellIntegrationTest { +public class CypherShellFailureIntegrationTest extends CypherShellIntegrationTest +{ @Rule public final ExpectedException thrown = ExpectedException.none(); private StringLinePrinter linePrinter = new StringLinePrinter(); @Before - public void setUp() { + public void setUp() + { linePrinter.clear(); - shell = new CypherShell(linePrinter, new PrettyConfig(Format.VERBOSE, true, 1000), false, new ShellParameterMap()); + shell = new CypherShell( linePrinter, new PrettyConfig( Format.VERBOSE, true, 1000 ), false, new ShellParameterMap() ); } @Test - public void cypherWithNoPasswordShouldReturnValidError() throws CommandException { - thrown.expect(AuthenticationException.class); - thrown.expectMessage("The client is unauthorized due to authentication failure."); + public void cypherWithNoPasswordShouldReturnValidError() throws CommandException + { + thrown.expect( AuthenticationException.class ); + thrown.expectMessage( "The client is unauthorized due to authentication failure." ); - connect(""); + connect( "" ); } } diff --git a/cypher-shell/src/integration-test/java/org/neo4j/shell/commands/CypherShellIntegrationTest.java b/cypher-shell/src/integration-test/java/org/neo4j/shell/commands/CypherShellIntegrationTest.java index 20f13796..13e9f101 100644 --- a/cypher-shell/src/integration-test/java/org/neo4j/shell/commands/CypherShellIntegrationTest.java +++ b/cypher-shell/src/integration-test/java/org/neo4j/shell/commands/CypherShellIntegrationTest.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.commands; import org.neo4j.shell.ConnectionConfig; @@ -11,7 +30,8 @@ abstract class CypherShellIntegrationTest { CypherShell shell; - void connect(String password) throws CommandException { + void connect( String password ) throws CommandException + { shell.connect( new ConnectionConfig( "bolt", "localhost", 7687, "neo4j", password, Encryption.DEFAULT, ABSENT_DB_NAME ) ); } } diff --git a/cypher-shell/src/integration-test/java/org/neo4j/shell/commands/CypherShellMultiDatabaseIntegrationTest.java b/cypher-shell/src/integration-test/java/org/neo4j/shell/commands/CypherShellMultiDatabaseIntegrationTest.java index 0390a5c1..44d21d04 100644 --- a/cypher-shell/src/integration-test/java/org/neo4j/shell/commands/CypherShellMultiDatabaseIntegrationTest.java +++ b/cypher-shell/src/integration-test/java/org/neo4j/shell/commands/CypherShellMultiDatabaseIntegrationTest.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.commands; import org.junit.After; diff --git a/cypher-shell/src/integration-test/java/org/neo4j/shell/commands/CypherShellPlainIntegrationTest.java b/cypher-shell/src/integration-test/java/org/neo4j/shell/commands/CypherShellPlainIntegrationTest.java index afbdedeb..b48f104a 100644 --- a/cypher-shell/src/integration-test/java/org/neo4j/shell/commands/CypherShellPlainIntegrationTest.java +++ b/cypher-shell/src/integration-test/java/org/neo4j/shell/commands/CypherShellPlainIntegrationTest.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.commands; import org.junit.After; @@ -21,83 +40,90 @@ import static org.neo4j.shell.prettyprint.OutputFormatter.NEWLINE; import static org.neo4j.shell.util.Versions.version; -public class CypherShellPlainIntegrationTest extends CypherShellIntegrationTest { +public class CypherShellPlainIntegrationTest extends CypherShellIntegrationTest +{ @Rule public final ExpectedException thrown = ExpectedException.none(); private StringLinePrinter linePrinter = new StringLinePrinter(); @Before - public void setUp() throws Exception { + public void setUp() throws Exception + { linePrinter.clear(); - shell = new CypherShell(linePrinter, new PrettyConfig(Format.PLAIN, true, 1000), false, new ShellParameterMap()); + shell = new CypherShell( linePrinter, new PrettyConfig( Format.PLAIN, true, 1000 ), false, new ShellParameterMap() ); connect( "neo" ); } @After - public void tearDown() throws Exception { - shell.execute("MATCH (n) DETACH DELETE (n)"); + public void tearDown() throws Exception + { + shell.execute( "MATCH (n) DETACH DELETE (n)" ); } @Test - public void periodicCommitWorks() throws CommandException { - shell.execute("USING PERIODIC COMMIT\n" + - "LOAD CSV FROM 'https://neo4j.com/docs/cypher-refcard/3.2/csv/artists.csv' AS line\n" + - "CREATE (:Artist {name: line[1], year: toInteger(line[2])});"); + public void periodicCommitWorks() throws CommandException + { + shell.execute( "USING PERIODIC COMMIT\n" + + "LOAD CSV FROM 'https://neo4j.com/docs/cypher-refcard/3.2/csv/artists.csv' AS line\n" + + "CREATE (:Artist {name: line[1], year: toInteger(line[2])});" ); linePrinter.clear(); - shell.execute("MATCH (a:Artist) WHERE a.name = 'Europe' RETURN a.name"); + shell.execute( "MATCH (a:Artist) WHERE a.name = 'Europe' RETURN a.name" ); - assertThat(linePrinter.output(), containsString("a.name"+ NEWLINE+"\"Europe\"")); + assertThat( linePrinter.output(), containsString( "a.name" + NEWLINE + "\"Europe\"" ) ); } @Test - public void cypherWithProfileStatements() throws CommandException { + public void cypherWithProfileStatements() throws CommandException + { //when - shell.execute("CYPHER RUNTIME=INTERPRETED PROFILE RETURN null"); + shell.execute( "CYPHER RUNTIME=INTERPRETED PROFILE RETURN null" ); //then String actual = linePrinter.output(); // This assertion checks everything except for time and cypher - assertThat(actual, containsString("Plan: \"PROFILE\"")); - assertThat(actual, containsString("Statement: \"READ_ONLY\"")); - assertThat(actual, containsString("Planner: \"COST\"")); - assertThat(actual, containsString("Runtime: \"INTERPRETED\"")); - assertThat(actual, containsString("DbHits: 0")); - assertThat(actual, containsString("Rows: 1")); - assertThat(actual, containsString("null")); - assertThat(actual, containsString("NULL")); + assertThat( actual, containsString( "Plan: \"PROFILE\"" ) ); + assertThat( actual, containsString( "Statement: \"READ_ONLY\"" ) ); + assertThat( actual, containsString( "Planner: \"COST\"" ) ); + assertThat( actual, containsString( "Runtime: \"INTERPRETED\"" ) ); + assertThat( actual, containsString( "DbHits: 0" ) ); + assertThat( actual, containsString( "Rows: 1" ) ); + assertThat( actual, containsString( "null" ) ); + assertThat( actual, containsString( "NULL" ) ); } @Test - public void cypherWithProfileWithMemory() throws CommandException { + public void cypherWithProfileWithMemory() throws CommandException + { // given String serverVersion = shell.getServerVersion(); // Memory profile are only available from 4.1 - assumeThat( version(serverVersion), greaterThanOrEqualTo(version("4.1"))); + assumeThat( version( serverVersion ), greaterThanOrEqualTo( version( "4.1" ) ) ); //when - shell.execute("CYPHER RUNTIME=INTERPRETED PROFILE RETURN null"); + shell.execute( "CYPHER RUNTIME=INTERPRETED PROFILE RETURN null" ); //then String actual = linePrinter.output(); - System.out.println(actual); - assertThat(actual, containsString("Memory (Bytes): 0")); + System.out.println( actual ); + assertThat( actual, containsString( "Memory (Bytes): 0" ) ); } @Test - public void cypherWithExplainStatements() throws CommandException { + public void cypherWithExplainStatements() throws CommandException + { //when - shell.execute("CYPHER RUNTIME=INTERPRETED EXPLAIN RETURN null"); + shell.execute( "CYPHER RUNTIME=INTERPRETED EXPLAIN RETURN null" ); //then String actual = linePrinter.output(); // This assertion checks everything except for time and cypher - assertThat(actual, containsString("Plan: \"EXPLAIN\"")); - assertThat(actual, containsString("Statement: \"READ_ONLY\"")); - assertThat(actual, containsString("Planner: \"COST\"")); - assertThat(actual, containsString("Runtime: \"INTERPRETED\"")); + assertThat( actual, containsString( "Plan: \"EXPLAIN\"" ) ); + assertThat( actual, containsString( "Statement: \"READ_ONLY\"" ) ); + assertThat( actual, containsString( "Planner: \"COST\"" ) ); + assertThat( actual, containsString( "Runtime: \"INTERPRETED\"" ) ); } @Test @@ -106,15 +132,15 @@ public void shouldUseParamFromCLIArgs() throws EvaluationException, CommandExcep // given a CLI arg ShellParameterMap parameterMap = new ShellParameterMap(); parameterMap.setParameter( "foo", "'bar'" ); - shell = new CypherShell( linePrinter, new PrettyConfig( Format.PLAIN, true, 1000), false, parameterMap ); + shell = new CypherShell( linePrinter, new PrettyConfig( Format.PLAIN, true, 1000 ), false, parameterMap ); connect( "neo" ); //when - shell.execute("CYPHER RETURN $foo"); + shell.execute( "CYPHER RETURN $foo" ); //then String actual = linePrinter.output(); - assertThat(actual, containsString("$foo")); - assertThat(actual, containsString("bar")); + assertThat( actual, containsString( "$foo" ) ); + assertThat( actual, containsString( "bar" ) ); } } diff --git a/cypher-shell/src/integration-test/java/org/neo4j/shell/commands/CypherShellProtocolIntegrationTest.java b/cypher-shell/src/integration-test/java/org/neo4j/shell/commands/CypherShellProtocolIntegrationTest.java index a4d52547..c7715f06 100644 --- a/cypher-shell/src/integration-test/java/org/neo4j/shell/commands/CypherShellProtocolIntegrationTest.java +++ b/cypher-shell/src/integration-test/java/org/neo4j/shell/commands/CypherShellProtocolIntegrationTest.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.commands; import org.junit.Test; @@ -16,49 +35,55 @@ import static org.neo4j.shell.util.Versions.majorVersion; import static org.neo4j.shell.util.Versions.minorVersion; -public class CypherShellProtocolIntegrationTest{ +public class CypherShellProtocolIntegrationTest +{ @Test - public void shouldConnectWithBoltProtocol() throws Exception { - CypherShell shell = new CypherShell( new StringLinePrinter(), new PrettyConfig( Format.PLAIN, true, 1000), false, new ShellParameterMap()); + public void shouldConnectWithBoltProtocol() throws Exception + { + CypherShell shell = new CypherShell( new StringLinePrinter(), new PrettyConfig( Format.PLAIN, true, 1000 ), false, new ShellParameterMap() ); shell.connect( new ConnectionConfig( "bolt", "localhost", 7687, "neo4j", "neo", Encryption.DEFAULT, ABSENT_DB_NAME ) ); - assertTrue(shell.isConnected()); + assertTrue( shell.isConnected() ); } @Test - public void shouldConnectWithNeo4jProtocol() throws Exception { - CypherShell shell = new CypherShell( new StringLinePrinter(), new PrettyConfig( Format.PLAIN, true, 1000), false, new ShellParameterMap()); + public void shouldConnectWithNeo4jProtocol() throws Exception + { + CypherShell shell = new CypherShell( new StringLinePrinter(), new PrettyConfig( Format.PLAIN, true, 1000 ), false, new ShellParameterMap() ); // This should work even on older databases without the neo4j protocol, by falling back to bolt shell.connect( new ConnectionConfig( "neo4j", "localhost", 7687, "neo4j", "neo", Encryption.DEFAULT, ABSENT_DB_NAME ) ); - assertTrue(shell.isConnected()); + assertTrue( shell.isConnected() ); } @Test - public void shouldConnectWithBoltSSCProtocol() throws Exception { - CypherShell shell = new CypherShell( new StringLinePrinter(), new PrettyConfig( Format.PLAIN, true, 1000), false, new ShellParameterMap()); + public void shouldConnectWithBoltSSCProtocol() throws Exception + { + CypherShell shell = new CypherShell( new StringLinePrinter(), new PrettyConfig( Format.PLAIN, true, 1000 ), false, new ShellParameterMap() ); // Given 3.X series where X > 1, where SSC are the default. Hard to test in 4.0 sadly. - onlyIn3_2to3_6( shell); + onlyIn3_2to3_6( shell ); shell.connect( new ConnectionConfig( "bolt+ssc", "localhost", 7687, "neo4j", "neo", Encryption.DEFAULT, ABSENT_DB_NAME ) ); - assertTrue(shell.isConnected()); + assertTrue( shell.isConnected() ); } @Test - public void shouldConnectWithNeo4jSSCProtocol() throws Exception { - CypherShell shell = new CypherShell( new StringLinePrinter(), new PrettyConfig( Format.PLAIN, true, 1000), false, new ShellParameterMap()); + public void shouldConnectWithNeo4jSSCProtocol() throws Exception + { + CypherShell shell = new CypherShell( new StringLinePrinter(), new PrettyConfig( Format.PLAIN, true, 1000 ), false, new ShellParameterMap() ); // Given 3.X series where X > 1, where SSC are the default. Hard to test in 4.0 sadly. - onlyIn3_2to3_6( shell); + onlyIn3_2to3_6( shell ); // This should work by falling back to bolt+ssc shell.connect( new ConnectionConfig( "neo4j+ssc", "localhost", 7687, "neo4j", "neo", Encryption.DEFAULT, ABSENT_DB_NAME ) ); - assertTrue(shell.isConnected()); + assertTrue( shell.isConnected() ); } // Here should be tests for "neo4j+s" and "bolt+s", but we don't have the infrastructure for those. - private void onlyIn3_2to3_6( CypherShell shell) throws Exception { + private void onlyIn3_2to3_6( CypherShell shell ) throws Exception + { // Default connection settings shell.connect( new ConnectionConfig( "bolt", "localhost", 7687, "neo4j", "neo", Encryption.DEFAULT, ABSENT_DB_NAME ) ); assumeTrue( majorVersion( shell.getServerVersion() ) == 3 ); - assumeTrue( minorVersion( shell.getServerVersion() ) > 1 ); + assumeTrue( minorVersion( shell.getServerVersion() ) > 1 ); shell.disconnect(); } } diff --git a/cypher-shell/src/integration-test/java/org/neo4j/shell/commands/CypherShellTransactionIntegrationTest.java b/cypher-shell/src/integration-test/java/org/neo4j/shell/commands/CypherShellTransactionIntegrationTest.java index a8702806..3c0f733d 100644 --- a/cypher-shell/src/integration-test/java/org/neo4j/shell/commands/CypherShellTransactionIntegrationTest.java +++ b/cypher-shell/src/integration-test/java/org/neo4j/shell/commands/CypherShellTransactionIntegrationTest.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.commands; import org.junit.Before; @@ -92,7 +111,7 @@ public void failureInTxScenarioWithCypherFollowing() throws CommandException shell.execute( "RETURN 42" ); // then - assertThat(linePrinter.output(), containsString("42")); + assertThat( linePrinter.output(), containsString( "42" ) ); } @Test diff --git a/cypher-shell/src/integration-test/java/org/neo4j/shell/commands/CypherShellVerboseIntegrationTest.java b/cypher-shell/src/integration-test/java/org/neo4j/shell/commands/CypherShellVerboseIntegrationTest.java index 18ae4a0c..597f24df 100644 --- a/cypher-shell/src/integration-test/java/org/neo4j/shell/commands/CypherShellVerboseIntegrationTest.java +++ b/cypher-shell/src/integration-test/java/org/neo4j/shell/commands/CypherShellVerboseIntegrationTest.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.commands; import org.junit.After; @@ -26,116 +45,129 @@ import static org.neo4j.shell.util.Versions.majorVersion; import static org.neo4j.shell.util.Versions.version; -public class CypherShellVerboseIntegrationTest extends CypherShellIntegrationTest { +public class CypherShellVerboseIntegrationTest extends CypherShellIntegrationTest +{ @Rule public final ExpectedException thrown = ExpectedException.none(); private StringLinePrinter linePrinter = new StringLinePrinter(); @Before - public void setUp() throws Exception { + public void setUp() throws Exception + { linePrinter.clear(); - shell = new CypherShell(linePrinter, new PrettyConfig(Format.VERBOSE, true, 1000), false, new ShellParameterMap()); + shell = new CypherShell( linePrinter, new PrettyConfig( Format.VERBOSE, true, 1000 ), false, new ShellParameterMap() ); connect( "neo" ); } @After - public void tearDown() throws Exception { - shell.execute("MATCH (n) DETACH DELETE (n)"); + public void tearDown() throws Exception + { + shell.execute( "MATCH (n) DETACH DELETE (n)" ); } @Test - public void cypherWithNoReturnStatements() throws CommandException { + public void cypherWithNoReturnStatements() throws CommandException + { //when - shell.execute("CREATE (:TestPerson {name: \"Jane Smith\"})"); + shell.execute( "CREATE (:TestPerson {name: \"Jane Smith\"})" ); //then - assertThat(linePrinter.output(), containsString("Added 1 nodes, Set 1 properties, Added 1 labels")); + assertThat( linePrinter.output(), containsString( "Added 1 nodes, Set 1 properties, Added 1 labels" ) ); } @Test - public void cypherWithReturnStatements() throws CommandException { + public void cypherWithReturnStatements() throws CommandException + { //when - shell.execute("CREATE (jane :TestPerson {name: \"Jane Smith\"}) RETURN jane"); + shell.execute( "CREATE (jane :TestPerson {name: \"Jane Smith\"}) RETURN jane" ); //then String output = linePrinter.output(); - assertThat(output, containsString("| jane ")); - assertThat(output, containsString("| (:TestPerson {name: \"Jane Smith\"}) |" )); - assertThat(output, containsString("Added 1 nodes, Set 1 properties, Added 1 labels")); + assertThat( output, containsString( "| jane " ) ); + assertThat( output, containsString( "| (:TestPerson {name: \"Jane Smith\"}) |" ) ); + assertThat( output, containsString( "Added 1 nodes, Set 1 properties, Added 1 labels" ) ); } @Test - public void connectTwiceThrows() throws CommandException { - thrown.expect(CommandException.class); - thrown.expectMessage("Already connected"); + public void connectTwiceThrows() throws CommandException + { + thrown.expect( CommandException.class ); + thrown.expectMessage( "Already connected" ); - assertTrue("Shell should already be connected", shell.isConnected()); + assertTrue( "Shell should already be connected", shell.isConnected() ); connect( "neo" ); } @Test - public void resetOutOfTxScenario() throws CommandException { + public void resetOutOfTxScenario() throws CommandException + { //when - shell.execute("CREATE (:TestPerson {name: \"Jane Smith\"})"); + shell.execute( "CREATE (:TestPerson {name: \"Jane Smith\"})" ); shell.reset(); //then - shell.execute("CREATE (:TestPerson {name: \"Jane Smith\"})"); - shell.execute("MATCH (n:TestPerson) RETURN n ORDER BY n.name"); + shell.execute( "CREATE (:TestPerson {name: \"Jane Smith\"})" ); + shell.execute( "MATCH (n:TestPerson) RETURN n ORDER BY n.name" ); String result = linePrinter.output(); - assertThat(result, containsString( + assertThat( result, containsString( "| (:TestPerson {name: \"Jane Smith\"}) |\n" + - "| (:TestPerson {name: \"Jane Smith\"}) |")); + "| (:TestPerson {name: \"Jane Smith\"}) |" ) ); } @Test - public void paramsAndListVariables() throws EvaluationException, CommandException { - assertTrue(shell.getParameterMap().allParameterValues().isEmpty()); + public void paramsAndListVariables() throws EvaluationException, CommandException + { + assertTrue( shell.getParameterMap().allParameterValues().isEmpty() ); long randomLong = System.currentTimeMillis(); String stringInput = "\"randomString\""; - shell.getParameterMap().setParameter("string", stringInput); - Object paramValue = shell.getParameterMap().setParameter("bob", String.valueOf(randomLong)); - assertEquals(randomLong, paramValue); + shell.getParameterMap().setParameter( "string", stringInput ); + Object paramValue = shell.getParameterMap().setParameter( "bob", String.valueOf( randomLong ) ); + assertEquals( randomLong, paramValue ); - shell.execute("RETURN $bob, $string"); + shell.execute( "RETURN $bob, $string" ); String result = linePrinter.output(); - assertThat(result, containsString("| $bob")); - assertThat(result, containsString("| " + randomLong + " | " + stringInput + " |")); - assertEquals(randomLong, shell.getParameterMap().allParameterValues().get( "bob")); - assertEquals("randomString", shell.getParameterMap().allParameterValues().get( "string")); + assertThat( result, containsString( "| $bob" ) ); + assertThat( result, containsString( "| " + randomLong + " | " + stringInput + " |" ) ); + assertEquals( randomLong, shell.getParameterMap().allParameterValues().get( "bob" ) ); + assertEquals( "randomString", shell.getParameterMap().allParameterValues().get( "string" ) ); } @Test - public void paramsAndListVariablesWithSpecialCharacters() throws EvaluationException, CommandException { - assertTrue(shell.getParameterMap().allParameterValues().isEmpty()); + public void paramsAndListVariablesWithSpecialCharacters() throws EvaluationException, CommandException + { + assertTrue( shell.getParameterMap().allParameterValues().isEmpty() ); long randomLong = System.currentTimeMillis(); - Object paramValue = shell.getParameterMap().setParameter("`bob`", String.valueOf(randomLong)); - assertEquals(randomLong, paramValue); + Object paramValue = shell.getParameterMap().setParameter( "`bob`", String.valueOf( randomLong ) ); + assertEquals( randomLong, paramValue ); - shell.execute("RETURN $`bob`"); + shell.execute( "RETURN $`bob`" ); String result = linePrinter.output(); - assertThat(result, containsString("| $`bob`")); - assertThat(result, containsString("\n| " + randomLong+ " |\n")); - assertEquals(randomLong, shell.getParameterMap().allParameterValues().get("bob")); + assertThat( result, containsString( "| $`bob`" ) ); + assertThat( result, containsString( "\n| " + randomLong + " |\n" ) ); + assertEquals( randomLong, shell.getParameterMap().allParameterValues().get( "bob" ) ); } @Test - public void cypherWithOrder() throws CommandException { + public void cypherWithOrder() throws CommandException + { // given String serverVersion = shell.getServerVersion(); - assumeThat( version(serverVersion), greaterThanOrEqualTo(version("3.6"))); + assumeThat( version( serverVersion ), greaterThanOrEqualTo( version( "3.6" ) ) ); // Make sure we are creating a new NEW index - try { + try + { shell.execute( "DROP INDEX ON :Person(age)" ); - } catch ( Exception e ) { + } + catch ( Exception e ) + { // ignore if the index didn't exist } @@ -143,7 +175,7 @@ public void cypherWithOrder() throws CommandException { shell.execute( "CALL db.awaitIndexes()" ); //when - shell.execute("CYPHER RUNTIME=INTERPRETED EXPLAIN MATCH (n:Person) WHERE n.age >= 18 RETURN n.name, n.age ORDER BY n.age"); + shell.execute( "CYPHER RUNTIME=INTERPRETED EXPLAIN MATCH (n:Person) WHERE n.age >= 18 RETURN n.name, n.age ORDER BY n.age" ); //then String actual = linePrinter.output(); @@ -152,13 +184,14 @@ public void cypherWithOrder() throws CommandException { } @Test - public void cypherWithQueryDetails() throws CommandException { + public void cypherWithQueryDetails() throws CommandException + { // given String serverVersion = shell.getServerVersion(); - assumeThat( version(serverVersion), greaterThanOrEqualTo(version("4.1"))); + assumeThat( version( serverVersion ), greaterThanOrEqualTo( version( "4.1" ) ) ); //when - shell.execute("EXPLAIN MATCH (n) with n.age AS age RETURN age"); + shell.execute( "EXPLAIN MATCH (n) with n.age AS age RETURN age" ); //then String actual = linePrinter.output(); @@ -168,13 +201,14 @@ public void cypherWithQueryDetails() throws CommandException { } @Test - public void cypherWithoutQueryDetails() throws CommandException { + public void cypherWithoutQueryDetails() throws CommandException + { // given String serverVersion = shell.getServerVersion(); - assumeThat( version(serverVersion), not(greaterThanOrEqualTo(version("4.1")))); + assumeThat( version( serverVersion ), not( greaterThanOrEqualTo( version( "4.1" ) ) ) ); //when - shell.execute("EXPLAIN MATCH (n) with n.age AS age RETURN age"); + shell.execute( "EXPLAIN MATCH (n) with n.age AS age RETURN age" ); //then String actual = linePrinter.output(); @@ -183,65 +217,69 @@ public void cypherWithoutQueryDetails() throws CommandException { } @Test - public void cypherWithExplainAndRulePlanner() throws CommandException { + public void cypherWithExplainAndRulePlanner() throws CommandException + { //given (there is no rule planner in neo4j 4.0) assumeTrue( majorVersion( shell.getServerVersion() ) < 4 ); //when - shell.execute("CYPHER planner=rule EXPLAIN MATCH (e:E) WHERE e.bucket='Live' and e.id = 23253473 RETURN count(e)"); + shell.execute( "CYPHER planner=rule EXPLAIN MATCH (e:E) WHERE e.bucket='Live' and e.id = 23253473 RETURN count(e)" ); //then String actual = linePrinter.output(); - assertThat(actual, containsString("\"EXPLAIN\"")); - assertThat(actual, containsString("\"READ_ONLY\"")); - assertThat(actual, containsString("\"RULE\"")); - assertThat(actual, containsString("\"INTERPRETED\"")); + assertThat( actual, containsString( "\"EXPLAIN\"" ) ); + assertThat( actual, containsString( "\"READ_ONLY\"" ) ); + assertThat( actual, containsString( "\"RULE\"" ) ); + assertThat( actual, containsString( "\"INTERPRETED\"" ) ); } @Test - public void cypherWithProfileWithMemory() throws CommandException { + public void cypherWithProfileWithMemory() throws CommandException + { // given String serverVersion = shell.getServerVersion(); // Memory profile are only available from 4.1 - assumeThat( version(serverVersion), greaterThanOrEqualTo(version("4.1"))); + assumeThat( version( serverVersion ), greaterThanOrEqualTo( version( "4.1" ) ) ); //when - shell.execute("CYPHER RUNTIME=INTERPRETED PROFILE WITH 1 AS x RETURN DISTINCT x"); + shell.execute( "CYPHER RUNTIME=INTERPRETED PROFILE WITH 1 AS x RETURN DISTINCT x" ); //then String actual = linePrinter.output(); - assertThat(actual.replace( " ", "" ), containsString("|Plan|Statement|Version|Planner|Runtime|Time|DbHits|Rows|Memory(Bytes)|")); // First table - assertThat(actual.replace( " ", "" ), containsString("|Operator|Details|EstimatedRows|Rows|DBHits|CacheH/M|Memory(Bytes)|")); // Second table + assertThat( actual.replace( " ", "" ), containsString( "|Plan|Statement|Version|Planner|Runtime|Time|DbHits|Rows|Memory(Bytes)|" ) ); // First table + assertThat( actual.replace( " ", "" ), containsString( "|Operator|Details|EstimatedRows|Rows|DBHits|CacheH/M|Memory(Bytes)|" ) ); // Second table } @Test - public void shouldShowTheNumberOfRows() throws CommandException { + public void shouldShowTheNumberOfRows() throws CommandException + { //when - shell.execute("UNWIND [1,2,3] AS row RETURN row"); + shell.execute( "UNWIND [1,2,3] AS row RETURN row" ); //then String actual = linePrinter.output(); - assertThat(actual, containsString("3 rows available")); + assertThat( actual, containsString( "3 rows available" ) ); } @Test - public void shouldNotContainUnnecessaryNewLines() throws CommandException { + public void shouldNotContainUnnecessaryNewLines() throws CommandException + { //when - shell.execute("UNWIND [1,2,3] AS row RETURN row"); + shell.execute( "UNWIND [1,2,3] AS row RETURN row" ); //then String actual = linePrinter.output(); - assertThat(actual, - containsString( String.format( - "+-----+%n" + - "| row |%n" + - "+-----+%n" + - "| 1 |%n" + - "| 2 |%n" + - "| 3 |%n" + - "+-----+%n" + - "%n" + - "3 rows available after"))); + assertThat( actual, + containsString( String.format( + "+-----+%n" + + "| row |%n" + + "+-----+%n" + + "| 1 |%n" + + "| 2 |%n" + + "| 3 |%n" + + "+-----+%n" + + "%n" + + "3 rows available after" ) ) ); } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/ConnectionConfig.java b/cypher-shell/src/main/java/org/neo4j/shell/ConnectionConfig.java index 6db56e9f..50de7674 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/ConnectionConfig.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/ConnectionConfig.java @@ -1,10 +1,30 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell; import javax.annotation.Nonnull; import org.neo4j.shell.cli.Encryption; -public class ConnectionConfig { +public class ConnectionConfig +{ public static final String USERNAME_ENV_VAR = "NEO4J_USERNAME"; public static final String PASSWORD_ENV_VAR = "NEO4J_PASSWORD"; public static final String DATABASE_ENV_VAR = "NEO4J_DATABASE"; @@ -18,90 +38,106 @@ public class ConnectionConfig { private String newPassword; private String database; - public ConnectionConfig(@Nonnull String scheme, - @Nonnull String host, - int port, - @Nonnull String username, - @Nonnull String password, - Encryption encryption, - @Nonnull String database) { + public ConnectionConfig( @Nonnull String scheme, + @Nonnull String host, + int port, + @Nonnull String username, + @Nonnull String password, + Encryption encryption, + @Nonnull String database ) + { this.host = host; this.port = port; - this.username = fallbackToEnvVariable(username, USERNAME_ENV_VAR); - this.password = fallbackToEnvVariable(password, PASSWORD_ENV_VAR); + this.username = fallbackToEnvVariable( username, USERNAME_ENV_VAR ); + this.password = fallbackToEnvVariable( password, PASSWORD_ENV_VAR ); this.encryption = encryption; this.scheme = scheme; - this.database = fallbackToEnvVariable(database, DATABASE_ENV_VAR); + this.database = fallbackToEnvVariable( database, DATABASE_ENV_VAR ); } /** * @return preferredValue if not empty, else the contents of the fallback environment variable */ @Nonnull - private static String fallbackToEnvVariable(@Nonnull String preferredValue, @Nonnull String fallbackEnvVar) { - String result = System.getenv(fallbackEnvVar); - if (result == null || !preferredValue.isEmpty()) { + private static String fallbackToEnvVariable( @Nonnull String preferredValue, @Nonnull String fallbackEnvVar ) + { + String result = System.getenv( fallbackEnvVar ); + if ( result == null || !preferredValue.isEmpty() ) + { result = preferredValue; } return result; } @Nonnull - public String scheme() { + public String scheme() + { return scheme; } @Nonnull - public String host() { + public String host() + { return host; } - public int port() { + public int port() + { return port; } @Nonnull - public String username() { + public String username() + { return username; } @Nonnull - public String password() { + public String password() + { return password; } - public String newPassword() { + public String newPassword() + { return newPassword; } @Nonnull - public String driverUrl() { - return String.format("%s://%s:%d", scheme(), host(), port()); + public String driverUrl() + { + return String.format( "%s://%s:%d", scheme(), host(), port() ); } @Nonnull - public Encryption encryption() { + public Encryption encryption() + { return encryption; } @Nonnull - public String database() { + public String database() + { return database; } - public void setUsername(@Nonnull String username) { + public void setUsername( @Nonnull String username ) + { this.username = username; } - public void setPassword(@Nonnull String password) { + public void setPassword( @Nonnull String password ) + { this.password = password; } - public void setNewPassword( String password) { + public void setNewPassword( String password ) + { this.newPassword = password; } - public boolean passwordChangeRequired() { + public boolean passwordChangeRequired() + { return this.newPassword != null; } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/Connector.java b/cypher-shell/src/main/java/org/neo4j/shell/Connector.java index 121e5e5e..3f24f30e 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/Connector.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/Connector.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell; import javax.annotation.Nonnull; @@ -8,7 +27,8 @@ /** * An object with the ability to connect and disconnect. */ -public interface Connector { +public interface Connector +{ /** * @return true if connected, false otherwise @@ -16,22 +36,21 @@ public interface Connector { boolean isConnected(); /** - * * @throws CommandException if connection failed */ - default void connect(@Nonnull ConnectionConfig connectionConfig) throws CommandException { + default void connect( @Nonnull ConnectionConfig connectionConfig ) throws CommandException + { connect( connectionConfig, null ); } /** - * * @throws CommandException if connection failed */ - void connect( @Nonnull ConnectionConfig connectionConfig, ThrowingAction action) throws CommandException; + void connect( @Nonnull ConnectionConfig connectionConfig, ThrowingAction action ) throws CommandException; /** - * Returns the version of Neo4j which the shell is connected to. If the version is before 3.1.0-M09, or we are not - * connected yet, this returns the empty string. + * Returns the version of Neo4j which the shell is connected to. If the version is before 3.1.0-M09, or we are not connected yet, this returns the empty + * string. * * @return the version of neo4j (like '3.1.0') if connected and available, an empty string otherwise */ diff --git a/cypher-shell/src/main/java/org/neo4j/shell/CypherShell.java b/cypher-shell/src/main/java/org/neo4j/shell/CypherShell.java index 9ddb646f..767b7f9b 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/CypherShell.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/CypherShell.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell; import java.util.Optional; @@ -23,9 +42,10 @@ /** * A possibly interactive shell for evaluating cypher statements. */ -public class CypherShell implements StatementExecuter, Connector, TransactionHandler, DatabaseManager { +public class CypherShell implements StatementExecuter, Connector, TransactionHandler, DatabaseManager +{ // Final space to catch newline - private static final Pattern cmdNamePattern = Pattern.compile("^\\s*(?[^\\s]+)\\b(?.*)\\s*$"); + private static final Pattern cmdNamePattern = Pattern.compile( "^\\s*(?[^\\s]+)\\b(?.*)\\s*$" ); private final ParameterMap parameterMap; private final LinePrinter linePrinter; private final BoltStateHandler boltStateHandler; @@ -33,17 +53,19 @@ public class CypherShell implements StatementExecuter, Connector, TransactionHan private CommandHelper commandHelper; private String lastNeo4jErrorCode; - public CypherShell(@Nonnull LinePrinter linePrinter, - @Nonnull PrettyConfig prettyConfig, - boolean isInteractive, - ParameterMap parameterMap) { - this(linePrinter, new BoltStateHandler(isInteractive), new PrettyPrinter(prettyConfig), parameterMap); + public CypherShell( @Nonnull LinePrinter linePrinter, + @Nonnull PrettyConfig prettyConfig, + boolean isInteractive, + ParameterMap parameterMap ) + { + this( linePrinter, new BoltStateHandler( isInteractive ), new PrettyPrinter( prettyConfig ), parameterMap ); } - protected CypherShell(@Nonnull LinePrinter linePrinter, - @Nonnull BoltStateHandler boltStateHandler, - @Nonnull PrettyPrinter prettyPrinter, - ParameterMap parameterMap) { + protected CypherShell( @Nonnull LinePrinter linePrinter, + @Nonnull BoltStateHandler boltStateHandler, + @Nonnull PrettyPrinter prettyPrinter, + ParameterMap parameterMap ) + { this.linePrinter = linePrinter; this.boltStateHandler = boltStateHandler; this.prettyPrinter = prettyPrinter; @@ -55,81 +77,96 @@ protected CypherShell(@Nonnull LinePrinter linePrinter, * @param text to trim * @return text without trailing semicolons */ - protected static String stripTrailingSemicolons(@Nonnull String text) { + protected static String stripTrailingSemicolons( @Nonnull String text ) + { int end = text.length(); - while (end > 0 && text.substring(0, end).endsWith(";")) { + while ( end > 0 && text.substring( 0, end ).endsWith( ";" ) ) + { end -= 1; } - return text.substring(0, end); + return text.substring( 0, end ); } @Override - public void execute(@Nonnull final String cmdString) throws ExitException, CommandException { + public void execute( @Nonnull final String cmdString ) throws ExitException, CommandException + { // See if it's a shell command - final Optional cmd = getCommandExecutable(cmdString); - if (cmd.isPresent()) { - executeCmd(cmd.get()); + final Optional cmd = getCommandExecutable( cmdString ); + if ( cmd.isPresent() ) + { + executeCmd( cmd.get() ); return; } // Else it will be parsed as Cypher, but for that we need to be connected - if (!isConnected()) { - throw new CommandException("Not connected to Neo4j"); + if ( !isConnected() ) + { + throw new CommandException( "Not connected to Neo4j" ); } - executeCypher(cmdString); + executeCypher( cmdString ); } @Override - public String lastNeo4jErrorCode() { + public String lastNeo4jErrorCode() + { return lastNeo4jErrorCode; } /** - * Executes a piece of text as if it were Cypher. By default, all of the cypher is executed in single statement - * (with an implicit transaction). + * Executes a piece of text as if it were Cypher. By default, all of the cypher is executed in single statement (with an implicit transaction). * * @param cypher non-empty cypher text to executeLine */ - private void executeCypher(@Nonnull final String cypher) throws CommandException { - try { - final Optional result = boltStateHandler.runCypher(cypher, parameterMap.allParameterValues()); - result.ifPresent(boltResult -> { - prettyPrinter.format(boltResult, linePrinter); - boltStateHandler.updateActualDbName(boltResult.getSummary()); - }); + private void executeCypher( @Nonnull final String cypher ) throws CommandException + { + try + { + final Optional result = boltStateHandler.runCypher( cypher, parameterMap.allParameterValues() ); + result.ifPresent( boltResult -> + { + prettyPrinter.format( boltResult, linePrinter ); + boltStateHandler.updateActualDbName( boltResult.getSummary() ); + } ); lastNeo4jErrorCode = null; - } catch (Neo4jException e) { - lastNeo4jErrorCode = getErrorCode(e); + } + catch ( Neo4jException e ) + { + lastNeo4jErrorCode = getErrorCode( e ); throw boltStateHandler.handleException( e ); } } @Override - public boolean isConnected() { + public boolean isConnected() + { return boltStateHandler.isConnected(); } @Nonnull - protected Optional getCommandExecutable(@Nonnull final String line) { - Matcher m = cmdNamePattern.matcher(line); - if (commandHelper == null || !m.matches()) { + protected Optional getCommandExecutable( @Nonnull final String line ) + { + Matcher m = cmdNamePattern.matcher( line ); + if ( commandHelper == null || !m.matches() ) + { return Optional.empty(); } - String name = m.group("name"); - String args = m.group("args"); + String name = m.group( "name" ); + String args = m.group( "args" ); - Command cmd = commandHelper.getCommand(name); + Command cmd = commandHelper.getCommand( name ); - if (cmd == null) { + if ( cmd == null ) + { return Optional.empty(); } - return Optional.of(() -> cmd.execute(stripTrailingSemicolons(args))); + return Optional.of( () -> cmd.execute( stripTrailingSemicolons( args ) ) ); } - protected void executeCmd(@Nonnull final CommandExecutable cmdExe) throws ExitException, CommandException { + protected void executeCmd( @Nonnull final CommandExecutable cmdExe ) throws ExitException, CommandException + { cmdExe.execute(); } @@ -141,63 +178,78 @@ protected void executeCmd(@Nonnull final CommandExecutable cmdExe) throws ExitEx */ @Override public void connect( @Nonnull ConnectionConfig connectionConfig, - ThrowingAction command) throws CommandException { - boltStateHandler.connect(connectionConfig, command ); + ThrowingAction command ) throws CommandException + { + boltStateHandler.connect( connectionConfig, command ); } @Nonnull @Override - public String getServerVersion() { + public String getServerVersion() + { return boltStateHandler.getServerVersion(); } @Override - public void beginTransaction() throws CommandException { + public void beginTransaction() throws CommandException + { boltStateHandler.beginTransaction(); } @Override - public void commitTransaction() throws CommandException { - try { + public void commitTransaction() throws CommandException + { + try + { boltStateHandler.commitTransaction(); lastNeo4jErrorCode = null; - } catch (Neo4jException e) { - lastNeo4jErrorCode = getErrorCode(e); + } + catch ( Neo4jException e ) + { + lastNeo4jErrorCode = getErrorCode( e ); throw e; } } @Override - public void rollbackTransaction() throws CommandException { + public void rollbackTransaction() throws CommandException + { boltStateHandler.rollbackTransaction(); } @Override - public boolean isTransactionOpen() { + public boolean isTransactionOpen() + { return boltStateHandler.isTransactionOpen(); } - public void setCommandHelper(@Nonnull CommandHelper commandHelper) { + public void setCommandHelper( @Nonnull CommandHelper commandHelper ) + { this.commandHelper = commandHelper; } @Override - public void reset() { + public void reset() + { boltStateHandler.reset(); } - protected void addRuntimeHookToResetShell() { - Runtime.getRuntime().addShutdownHook(new Thread(this::reset)); + protected void addRuntimeHookToResetShell() + { + Runtime.getRuntime().addShutdownHook( new Thread( this::reset ) ); } @Override - public void setActiveDatabase(String databaseName) throws CommandException + public void setActiveDatabase( String databaseName ) throws CommandException { - try { - boltStateHandler.setActiveDatabase(databaseName); + try + { + boltStateHandler.setActiveDatabase( databaseName ); lastNeo4jErrorCode = null; - } catch (Neo4jException e) { - lastNeo4jErrorCode = getErrorCode(e); + } + catch ( Neo4jException e ) + { + lastNeo4jErrorCode = getErrorCode( e ); throw e; } } @@ -222,30 +274,36 @@ public ParameterMap getParameterMap() return parameterMap; } - public void changePassword(@Nonnull ConnectionConfig connectionConfig) { - boltStateHandler.changePassword(connectionConfig); + public void changePassword( @Nonnull ConnectionConfig connectionConfig ) + { + boltStateHandler.changePassword( connectionConfig ); } /** * Used for testing purposes */ - public void disconnect() { + public void disconnect() + { boltStateHandler.disconnect(); } - private String getErrorCode(Neo4jException e) { + private String getErrorCode( Neo4jException e ) + { Neo4jException statusException = e; // If we encountered a later suppressed Neo4jException we use that as the basis for the status instead Throwable[] suppressed = e.getSuppressed(); - for (Throwable s : suppressed) { - if (s instanceof Neo4jException) { + for ( Throwable s : suppressed ) + { + if ( s instanceof Neo4jException ) + { statusException = (Neo4jException) s; break; } } - if (statusException instanceof ServiceUnavailableException || statusException instanceof DiscoveryException) { + if ( statusException instanceof ServiceUnavailableException || statusException instanceof DiscoveryException ) + { // Treat this the same way as a DatabaseUnavailable error for now. return DATABASE_UNAVAILABLE_ERROR_CODE; } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/DatabaseManager.java b/cypher-shell/src/main/java/org/neo4j/shell/DatabaseManager.java index 8961c561..ec0f49b5 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/DatabaseManager.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/DatabaseManager.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell; import org.neo4j.shell.exception.CommandException; @@ -14,11 +33,10 @@ public interface DatabaseManager String DATABASE_UNAVAILABLE_ERROR_CODE = "Neo.TransientError.General.DatabaseUnavailable"; /** - * Sets the active database name as set by the user. - * If the current state is connected, try to reconnect to that database. - * If the current state is disconnected, simply update `activeDatabaseAsSetByUser`. + * Sets the active database name as set by the user. If the current state is connected, try to reconnect to that database. If the current state is + * disconnected, simply update `activeDatabaseAsSetByUser`. */ - void setActiveDatabase(String databaseName) throws CommandException; + void setActiveDatabase( String databaseName ) throws CommandException; String getActiveDatabaseAsSetByUser(); diff --git a/cypher-shell/src/main/java/org/neo4j/shell/Historian.java b/cypher-shell/src/main/java/org/neo4j/shell/Historian.java index 292359ee..b38d40e8 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/Historian.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/Historian.java @@ -1,33 +1,55 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell; -import javax.annotation.Nonnull; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import javax.annotation.Nonnull; /** * An object which keeps a record of past commands */ -public interface Historian { - /** - * - * @return a list of all past commands in the history, in order of execution (first command sorted first). - */ - @Nonnull - List getHistory(); - - Historian empty = new Historian() { +public interface Historian +{ + Historian empty = new Historian() + { @Nonnull @Override - public List getHistory() { + public List getHistory() + { return new ArrayList<>(); } @Override - public void flushHistory() { + public void flushHistory() + { } }; + /** + * @return a list of all past commands in the history, in order of execution (first command sorted first). + */ + @Nonnull + List getHistory(); + /** * Flush history to disk */ diff --git a/cypher-shell/src/main/java/org/neo4j/shell/Main.java b/cypher-shell/src/main/java/org/neo4j/shell/Main.java index 7b3533a6..98d30d2e 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/Main.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/Main.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell; import jline.console.ConsoleReader; @@ -24,71 +43,82 @@ import static org.neo4j.shell.ShellRunner.isOutputInteractive; import static org.neo4j.shell.util.Versions.isPasswordChangeRequiredException; -public class Main { - static final String NEO_CLIENT_ERROR_SECURITY_UNAUTHORIZED = "Neo.ClientError.Security.Unauthorized"; +public class Main +{ public static final int EXIT_FAILURE = 1; public static final int EXIT_SUCCESS = 0; + static final String NEO_CLIENT_ERROR_SECURITY_UNAUTHORIZED = "Neo.ClientError.Security.Unauthorized"; private final InputStream in; private final PrintStream out; private final boolean hasSpecialInteractiveOutputStream; - public static void main(String[] args) { - CliArgs cliArgs = CliArgHelper.parse(args); - - // if null, then command line parsing went wrong - // CliArgs has already printed errors. - if (cliArgs == null) { - System.exit(1); - } - - Main main = new Main(); - main.startShell(cliArgs); - } - - Main() { - this(System.in, System.out, false); + Main() + { + this( System.in, System.out, false ); } /** * For testing purposes */ - Main(final InputStream in, final PrintStream out) { - this(in, out, true); + Main( final InputStream in, final PrintStream out ) + { + this( in, out, true ); } - private Main(final InputStream in, final PrintStream out, final boolean hasSpecialInteractiveOutputStream ) { + private Main( final InputStream in, final PrintStream out, final boolean hasSpecialInteractiveOutputStream ) + { this.in = in; this.out = out; this.hasSpecialInteractiveOutputStream = hasSpecialInteractiveOutputStream; } + public static void main( String[] args ) + { + CliArgs cliArgs = CliArgHelper.parse( args ); + + // if null, then command line parsing went wrong + // CliArgs has already printed errors. + if ( cliArgs == null ) + { + System.exit( 1 ); + } + + Main main = new Main(); + main.startShell( cliArgs ); + } + /** * Delegate for testing purposes */ - private OutputStream getOutputStreamForInteractivePrompt() { + private OutputStream getOutputStreamForInteractivePrompt() + { return hasSpecialInteractiveOutputStream ? this.out : ShellRunner.getOutputStreamForInteractivePrompt(); } - void startShell(@Nonnull CliArgs cliArgs) { - if (cliArgs.getVersion()) { - out.println("Cypher-Shell " + Build.version()); + void startShell( @Nonnull CliArgs cliArgs ) + { + if ( cliArgs.getVersion() ) + { + out.println( "Cypher-Shell " + Build.version() ); } - if (cliArgs.getDriverVersion()) { - out.println("Neo4j Driver " + Build.driverVersion()); + if ( cliArgs.getDriverVersion() ) + { + out.println( "Neo4j Driver " + Build.driverVersion() ); } - if (cliArgs.getVersion() || cliArgs.getDriverVersion()) { + if ( cliArgs.getVersion() || cliArgs.getDriverVersion() ) + { return; } Logger logger = new AnsiLogger( cliArgs.getDebugMode() ); PrettyConfig prettyConfig = new PrettyConfig( cliArgs ); CypherShell shell = new CypherShell( logger, prettyConfig, ShellRunner.shouldBeInteractive( cliArgs ), - cliArgs.getParameters() ); + cliArgs.getParameters() ); int exitCode = runShell( cliArgs, shell, logger ); System.exit( exitCode ); } - int runShell(@Nonnull CliArgs cliArgs, @Nonnull CypherShell shell, Logger logger ) + int runShell( @Nonnull CliArgs cliArgs, @Nonnull CypherShell shell, Logger logger ) { ConnectionConfig connectionConfig = new ConnectionConfig( cliArgs.getScheme(), @@ -105,19 +135,19 @@ int runShell(@Nonnull CliArgs cliArgs, @Nonnull CypherShell shell, Logger logger { // Can only prompt for password if input has not been redirected connectMaybeInteractively( shell, connectionConfig, - !cliArgs.getNonInteractive() && isInputInteractive(), - !cliArgs.getNonInteractive() && isOutputInteractive(), - !cliArgs.getNonInteractive()/*Don't ask for password if using --non-interactive*/, - () -> shell.execute( cliArgs.getCypher().get() ) ); + !cliArgs.getNonInteractive() && isInputInteractive(), + !cliArgs.getNonInteractive() && isOutputInteractive(), + !cliArgs.getNonInteractive()/*Don't ask for password if using --non-interactive*/, + () -> shell.execute( cliArgs.getCypher().get() ) ); return EXIT_SUCCESS; } else { // Can only prompt for password if input has not been redirected connectMaybeInteractively( shell, connectionConfig, - !cliArgs.getNonInteractive() && isInputInteractive(), + !cliArgs.getNonInteractive() && isInputInteractive(), !cliArgs.getNonInteractive() && isOutputInteractive(), - !cliArgs.getNonInteractive()/*Don't ask for password if using --non-interactive*/); + !cliArgs.getNonInteractive()/*Don't ask for password if using --non-interactive*/ ); // Construct shellrunner after connecting, due to interrupt handling ShellRunner shellRunner = ShellRunner.getShellRunner( cliArgs, shell, logger, connectionConfig ); CommandHelper commandHelper = new CommandHelper( logger, shellRunner.getHistorian(), shell ); @@ -134,12 +164,13 @@ int runShell(@Nonnull CliArgs cliArgs, @Nonnull CypherShell shell, Logger logger } } - void connectMaybeInteractively(@Nonnull CypherShell shell, - @Nonnull ConnectionConfig connectionConfig, - boolean inputInteractive, - boolean outputInteractive, - boolean shouldPromptForPassword) - throws Exception { + void connectMaybeInteractively( @Nonnull CypherShell shell, + @Nonnull ConnectionConfig connectionConfig, + boolean inputInteractive, + boolean outputInteractive, + boolean shouldPromptForPassword ) + throws Exception + { connectMaybeInteractively( shell, connectionConfig, inputInteractive, outputInteractive, shouldPromptForPassword, null ); } @@ -147,139 +178,160 @@ void connectMaybeInteractively(@Nonnull CypherShell shell, * Connect the shell to the server, and try to handle missing passwords and such */ private void connectMaybeInteractively( @Nonnull CypherShell shell, - @Nonnull ConnectionConfig connectionConfig, - boolean inputInteractive, - boolean outputInteractive, - boolean shouldPromptForPassword, - ThrowingAction command ) - throws Exception { + @Nonnull ConnectionConfig connectionConfig, + boolean inputInteractive, + boolean outputInteractive, + boolean shouldPromptForPassword, + ThrowingAction command ) + throws Exception + { boolean didPrompt = false; // Prompt directly in interactive mode if user provided username but not password - if (inputInteractive && !connectionConfig.username().isEmpty() && connectionConfig.password().isEmpty()) { - promptForUsernameAndPassword(connectionConfig, outputInteractive); + if ( inputInteractive && !connectionConfig.username().isEmpty() && connectionConfig.password().isEmpty() ) + { + promptForUsernameAndPassword( connectionConfig, outputInteractive ); didPrompt = true; } - while (true) { - try { + while ( true ) + { + try + { // Try to connect - shell.connect(connectionConfig, command); + shell.connect( connectionConfig, command ); // If no exception occurred we are done break; - } catch (AuthenticationException e) { + } + catch ( AuthenticationException e ) + { // Fail if we already prompted, // or do not have interactive input, // or already tried with both username and password - if (didPrompt || !inputInteractive || (!connectionConfig.username().isEmpty() && !connectionConfig.password().isEmpty())) { + if ( didPrompt || !inputInteractive || (!connectionConfig.username().isEmpty() && !connectionConfig.password().isEmpty()) ) + { throw e; } // Otherwise we prompt for username and password, and try to connect again - promptForUsernameAndPassword(connectionConfig, outputInteractive); + promptForUsernameAndPassword( connectionConfig, outputInteractive ); didPrompt = true; - } catch (Neo4jException e) { - if (shouldPromptForPassword && isPasswordChangeRequiredException(e)) { - promptForPasswordChange(connectionConfig, outputInteractive); - shell.changePassword(connectionConfig); + } + catch ( Neo4jException e ) + { + if ( shouldPromptForPassword && isPasswordChangeRequiredException( e ) ) + { + promptForPasswordChange( connectionConfig, outputInteractive ); + shell.changePassword( connectionConfig ); didPrompt = true; - } else { + } + else + { throw e; } } } } - private void promptForUsernameAndPassword(ConnectionConfig connectionConfig, boolean outputInteractive) throws Exception { + private void promptForUsernameAndPassword( ConnectionConfig connectionConfig, boolean outputInteractive ) throws Exception + { OutputStream promptOutputStream = getOutputStreamForInteractivePrompt(); - ConsoleReader consoleReader = new ConsoleReader(in, promptOutputStream); + ConsoleReader consoleReader = new ConsoleReader( in, promptOutputStream ); // Disable expansion of bangs: ! - consoleReader.setExpandEvents(false); + consoleReader.setExpandEvents( false ); // Ensure Reader does not handle user input for ctrl+C behaviour - consoleReader.setHandleUserInterrupt(false); + consoleReader.setHandleUserInterrupt( false ); - try { - if (connectionConfig.username().isEmpty()) { + try + { + if ( connectionConfig.username().isEmpty() ) + { String username = outputInteractive ? - promptForNonEmptyText("username", consoleReader, null) : - promptForText("username", consoleReader, null); - connectionConfig.setUsername(username); + promptForNonEmptyText( "username", consoleReader, null ) : + promptForText( "username", consoleReader, null ); + connectionConfig.setUsername( username ); } - if (connectionConfig.password().isEmpty()) { - connectionConfig.setPassword(promptForText("password", consoleReader, '*')); + if ( connectionConfig.password().isEmpty() ) + { + connectionConfig.setPassword( promptForText( "password", consoleReader, '*' ) ); } - } finally { + } + finally + { consoleReader.close(); } } - private void promptForPasswordChange(ConnectionConfig connectionConfig, boolean outputInteractive) throws Exception { + private void promptForPasswordChange( ConnectionConfig connectionConfig, boolean outputInteractive ) throws Exception + { OutputStream promptOutputStream = getOutputStreamForInteractivePrompt(); - ConsoleReader consoleReader = new ConsoleReader(in, promptOutputStream); + ConsoleReader consoleReader = new ConsoleReader( in, promptOutputStream ); // Disable expansion of bangs: ! - consoleReader.setExpandEvents(false); + consoleReader.setExpandEvents( false ); // Ensure Reader does not handle user input for ctrl+C behaviour - consoleReader.setHandleUserInterrupt(false); + consoleReader.setHandleUserInterrupt( false ); - consoleReader.println("Password change required"); + consoleReader.println( "Password change required" ); - try { - if (connectionConfig.username().isEmpty()) { + try + { + if ( connectionConfig.username().isEmpty() ) + { String username = outputInteractive ? - promptForNonEmptyText("username", consoleReader, null) : - promptForText("username", consoleReader, null); - connectionConfig.setUsername(username); + promptForNonEmptyText( "username", consoleReader, null ) : + promptForText( "username", consoleReader, null ); + connectionConfig.setUsername( username ); } - if (connectionConfig.password().isEmpty()) { - connectionConfig.setPassword(promptForText("password", consoleReader, '*')); + if ( connectionConfig.password().isEmpty() ) + { + connectionConfig.setPassword( promptForText( "password", consoleReader, '*' ) ); } String newPassword = outputInteractive ? - promptForNonEmptyText("new password", consoleReader, '*') : - promptForText("new password", consoleReader, '*'); - connectionConfig.setNewPassword(newPassword); - } finally { + promptForNonEmptyText( "new password", consoleReader, '*' ) : + promptForText( "new password", consoleReader, '*' ); + connectionConfig.setNewPassword( newPassword ); + } + finally + { consoleReader.close(); } } /** - * @param prompt - * to display to the user - * @param mask - * single character to display instead of what the user is typing, use null if text is not secret + * @param prompt to display to the user + * @param mask single character to display instead of what the user is typing, use null if text is not secret * @return the text which was entered - * @throws Exception - * in case of errors + * @throws Exception in case of errors */ @Nonnull - private String promptForNonEmptyText(@Nonnull String prompt, @Nonnull ConsoleReader consoleReader, @Nullable Character mask) throws Exception { - String text = promptForText(prompt, consoleReader, mask); - if (!text.isEmpty()) { + private String promptForNonEmptyText( @Nonnull String prompt, @Nonnull ConsoleReader consoleReader, @Nullable Character mask ) throws Exception + { + String text = promptForText( prompt, consoleReader, mask ); + if ( !text.isEmpty() ) + { return text; } consoleReader.println( prompt + " cannot be empty" ); consoleReader.println(); - return promptForNonEmptyText(prompt, consoleReader, mask); + return promptForNonEmptyText( prompt, consoleReader, mask ); } /** - * @param prompt - * to display to the user - * @param mask - * single character to display instead of what the user is typing, use null if text is not secret - * @param consoleReader - * the reader + * @param prompt to display to the user + * @param mask single character to display instead of what the user is typing, use null if text is not secret + * @param consoleReader the reader * @return the text which was entered - * @throws Exception - * in case of errors + * @throws Exception in case of errors */ @Nonnull - private String promptForText(@Nonnull String prompt, @Nonnull ConsoleReader consoleReader, @Nullable Character mask) throws Exception { - String line = consoleReader.readLine(prompt + ": ", mask); - if (line == null) { - throw new CommandException("No text could be read, exiting..."); + private String promptForText( @Nonnull String prompt, @Nonnull ConsoleReader consoleReader, @Nullable Character mask ) throws Exception + { + String line = consoleReader.readLine( prompt + ": ", mask ); + if ( line == null ) + { + throw new CommandException( "No text could be read, exiting..." ); } return line; } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/ParameterMap.java b/cypher-shell/src/main/java/org/neo4j/shell/ParameterMap.java index 8827a3ea..83929886 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/ParameterMap.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/ParameterMap.java @@ -1,21 +1,41 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell; +import java.util.Map; +import javax.annotation.Nonnull; + import org.neo4j.cypher.internal.evaluator.EvaluationException; import org.neo4j.shell.state.ParamValue; -import javax.annotation.Nonnull; -import java.util.Map; - /** * An object which keeps named parameters and allows them them to be set/unset. */ -public interface ParameterMap { +public interface ParameterMap +{ /** - * @param name of variable to set value for + * @param name of variable to set value for * @param valueString to interpret the value from * @return the evaluated value */ - Object setParameter(@Nonnull String name, @Nonnull String valueString) throws EvaluationException; + Object setParameter( @Nonnull String name, @Nonnull String valueString ) throws EvaluationException; /** * @return map of all currently set variables and their values diff --git a/cypher-shell/src/main/java/org/neo4j/shell/ShellParameterMap.java b/cypher-shell/src/main/java/org/neo4j/shell/ShellParameterMap.java index 0877a417..cbc09083 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/ShellParameterMap.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/ShellParameterMap.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell; import java.util.HashMap; @@ -30,18 +49,18 @@ public Object setParameter( @Nonnull String name, @Nonnull String valueString ) @Nonnull @Override - public Map allParameterValues() + public Map allParameterValues() { return queryParams.entrySet() .stream() .collect( Collectors.toMap( Map.Entry::getKey, - value -> value.getValue().getValue())); + value -> value.getValue().getValue() ) ); } @Nonnull @Override - public Map getAllAsUserInput() + public Map getAllAsUserInput() { return queryParams; } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/ShellRunner.java b/cypher-shell/src/main/java/org/neo4j/shell/ShellRunner.java index 539904a3..322acf0c 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/ShellRunner.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/ShellRunner.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell; import org.apache.commons.io.output.NullOutputStream; @@ -26,20 +45,8 @@ import static org.fusesource.jansi.internal.CLibrary.isatty; import static org.neo4j.shell.system.Utils.isWindows; -public interface ShellRunner { - - /** - * Run and handle user input until end of file - * - * @return error code to exit with - */ - int runUntilEnd(); - - /** - * @return an object which can provide the history of commands executed - */ - @Nonnull - Historian getHistorian(); +public interface ShellRunner +{ /** * Get an appropriate shellrunner depending on the given arguments and if we are running in a TTY. @@ -52,19 +59,23 @@ public interface ShellRunner { * @throws IOException */ @Nonnull - static ShellRunner getShellRunner(@Nonnull CliArgs cliArgs, - @Nonnull CypherShell cypherShell, - @Nonnull Logger logger, - @Nonnull ConnectionConfig connectionConfig) throws IOException { - if (shouldBeInteractive(cliArgs)) { + static ShellRunner getShellRunner( @Nonnull CliArgs cliArgs, + @Nonnull CypherShell cypherShell, + @Nonnull Logger logger, + @Nonnull ConnectionConfig connectionConfig ) throws IOException + { + if ( shouldBeInteractive( cliArgs ) ) + { UserMessagesHandler userMessagesHandler = - new UserMessagesHandler(connectionConfig, cypherShell.getServerVersion()); - return new InteractiveShellRunner(cypherShell, cypherShell, cypherShell, logger, new ShellStatementParser(), - System.in, FileHistorian.getDefaultHistoryFile(), userMessagesHandler, connectionConfig); - } else { + new UserMessagesHandler( connectionConfig, cypherShell.getServerVersion() ); + return new InteractiveShellRunner( cypherShell, cypherShell, cypherShell, logger, new ShellStatementParser(), + System.in, FileHistorian.getDefaultHistoryFile(), userMessagesHandler, connectionConfig ); + } + else + { - return new NonInteractiveShellRunner(cliArgs.getFailBehavior(), cypherShell, logger, - new ShellStatementParser(), getInputStream(cliArgs)); + return new NonInteractiveShellRunner( cliArgs.getFailBehavior(), cypherShell, logger, + new ShellStatementParser(), getInputStream( cliArgs ) ); } } @@ -72,7 +83,8 @@ static ShellRunner getShellRunner(@Nonnull CliArgs cliArgs, * @param cliArgs * @return true if an interactive shellrunner should be used, false otherwise */ - static boolean shouldBeInteractive(@Nonnull CliArgs cliArgs) { + static boolean shouldBeInteractive( @Nonnull CliArgs cliArgs ) + { if ( cliArgs.getNonInteractive() || cliArgs.getInputFilename() != null ) { return false; @@ -82,21 +94,25 @@ static boolean shouldBeInteractive(@Nonnull CliArgs cliArgs) { } /** - * Checks if STDIN is a TTY. In case TTY checking is not possible (lack of libc), then the check falls back to - * the built in Java {@link System#console()} which checks if EITHER STDIN or STDOUT has been redirected. + * Checks if STDIN is a TTY. In case TTY checking is not possible (lack of libc), then the check falls back to the built in Java {@link System#console()} + * which checks if EITHER STDIN or STDOUT has been redirected. * - * @return true if the shell is reading from an interactive terminal, false otherwise (e.g., we are reading from a - * file). + * @return true if the shell is reading from an interactive terminal, false otherwise (e.g., we are reading from a file). */ - static boolean isInputInteractive() { - if (isWindows()) { + static boolean isInputInteractive() + { + if ( isWindows() ) + { // Input will never be a TTY on windows and it isatty seems to be able to block forever on Windows so avoid // calling it. return System.console() != null; } - try { - return 1 == isatty(STDIN_FILENO); - } catch (Throwable ignored) { + try + { + return 1 == isatty( STDIN_FILENO ); + } + catch ( Throwable ignored ) + { // system is not using libc (like Alpine Linux) // Fallback to checking stdin OR stdout return System.console() != null; @@ -104,21 +120,25 @@ static boolean isInputInteractive() { } /** - * Checks if STDOUT is a TTY. In case TTY checking is not possible (lack of libc), then the check falls back to - * the built in Java {@link System#console()} which checks if EITHER STDIN or STDOUT has been redirected. + * Checks if STDOUT is a TTY. In case TTY checking is not possible (lack of libc), then the check falls back to the built in Java {@link System#console()} + * which checks if EITHER STDIN or STDOUT has been redirected. * - * @return true if the shell is outputting to an interactive terminal, false otherwise (e.g., we are outputting - * to a file) + * @return true if the shell is outputting to an interactive terminal, false otherwise (e.g., we are outputting to a file) */ - static boolean isOutputInteractive() { - if (isWindows()) { + static boolean isOutputInteractive() + { + if ( isWindows() ) + { // Input will never be a TTY on windows and it isatty seems to be able to block forever on Windows so avoid // calling it. return System.console() != null; } - try { - return 1 == isatty(STDOUT_FILENO); - } catch (Throwable ignored) { + try + { + return 1 == isatty( STDOUT_FILENO ); + } + catch ( Throwable ignored ) + { // system is not using libc (like Alpine Linux) // Fallback to checking stdin OR stdout return System.console() != null; @@ -127,9 +147,10 @@ static boolean isOutputInteractive() { /** * If an input file has been defined use that, otherwise use STDIN + * * @throws FileNotFoundException if the provided input file doesn't exist */ - static InputStream getInputStream(CliArgs cliArgs) throws FileNotFoundException + static InputStream getInputStream( CliArgs cliArgs ) throws FileNotFoundException { if ( cliArgs.getInputFilename() == null ) { @@ -141,28 +162,53 @@ static InputStream getInputStream(CliArgs cliArgs) throws FileNotFoundException } } - static OutputStream getOutputStreamForInteractivePrompt() { - if (isWindows()) { + static OutputStream getOutputStreamForInteractivePrompt() + { + if ( isWindows() ) + { // Output will never be a TTY on windows and it isatty seems to be able to block forever on Windows so avoid // calling it. - if (System.console() != null) { - return new WriterOutputStream(System.console().writer(), Charset.defaultCharset()); + if ( System.console() != null ) + { + return new WriterOutputStream( System.console().writer(), Charset.defaultCharset() ); } - } else { - try { - if (1 == isatty(STDOUT_FILENO)) { + } + else + { + try + { + if ( 1 == isatty( STDOUT_FILENO ) ) + { return System.out; - } else { - return new FileOutputStream(new File("/dev/tty")); } - } catch (Throwable ignored) { + else + { + return new FileOutputStream( new File( "/dev/tty" ) ); + } + } + catch ( Throwable ignored ) + { // system is not using libc (like Alpine Linux) // Fallback to checking stdin OR stdout - if (System.console() != null) { - return new WriterOutputStream(System.console().writer(), Charset.defaultCharset()); + if ( System.console() != null ) + { + return new WriterOutputStream( System.console().writer(), Charset.defaultCharset() ); } } } return new NullOutputStream(); } + + /** + * Run and handle user input until end of file + * + * @return error code to exit with + */ + int runUntilEnd(); + + /** + * @return an object which can provide the history of commands executed + */ + @Nonnull + Historian getHistorian(); } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/StatementExecuter.java b/cypher-shell/src/main/java/org/neo4j/shell/StatementExecuter.java index 19825f08..e0359973 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/StatementExecuter.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/StatementExecuter.java @@ -1,22 +1,43 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell; +import javax.annotation.Nonnull; + import org.neo4j.shell.exception.CommandException; import org.neo4j.shell.exception.ExitException; -import javax.annotation.Nonnull; - /** * An interface which executes statements */ -public interface StatementExecuter { +public interface StatementExecuter +{ /** * Execute a statement + * * @param statement to execute - * @throws ExitException if a command to exit was executed + * @throws ExitException if a command to exit was executed * @throws CommandException if something went wrong */ - void execute(@Nonnull String statement) throws ExitException, CommandException; + void execute( @Nonnull String statement ) throws ExitException, CommandException; /** * Stops any running statements diff --git a/cypher-shell/src/main/java/org/neo4j/shell/TransactionHandler.java b/cypher-shell/src/main/java/org/neo4j/shell/TransactionHandler.java index 33c55853..48d34d05 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/TransactionHandler.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/TransactionHandler.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell; import org.neo4j.shell.exception.CommandException; @@ -5,22 +24,20 @@ /** * An object capable of starting, committing, and rolling back transactions. */ -public interface TransactionHandler { +public interface TransactionHandler +{ /** - * * @throws CommandException if a new transaction could not be started */ void beginTransaction() throws CommandException; /** - * * @throws CommandException if current transaction could not be committed */ void commitTransaction() throws CommandException; /** - * * @throws CommandException if current transaction could not be rolled back */ void rollbackTransaction() throws CommandException; diff --git a/cypher-shell/src/main/java/org/neo4j/shell/TriFunction.java b/cypher-shell/src/main/java/org/neo4j/shell/TriFunction.java index ee4a6290..486b7ab8 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/TriFunction.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/TriFunction.java @@ -1,6 +1,26 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell; @FunctionalInterface -public interface TriFunction { - OUT apply(IN1 in1, IN2 in2, IN3 in3); +public interface TriFunction +{ + OUT apply( IN1 in1, IN2 in2, IN3 in3 ); } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/UserMessagesHandler.java b/cypher-shell/src/main/java/org/neo4j/shell/UserMessagesHandler.java index f9f74de2..eaad792c 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/UserMessagesHandler.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/UserMessagesHandler.java @@ -1,49 +1,74 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell; +import javax.annotation.Nonnull; + import org.neo4j.shell.commands.Exit; import org.neo4j.shell.commands.Help; import org.neo4j.shell.log.AnsiFormattedText; -import javax.annotation.Nonnull; - -public class UserMessagesHandler { +public class UserMessagesHandler +{ private ConnectionConfig connectionConfig; private String serverVersion; - public UserMessagesHandler(@Nonnull ConnectionConfig connectionConfig, @Nonnull String serverVersion) { + public UserMessagesHandler( @Nonnull ConnectionConfig connectionConfig, @Nonnull String serverVersion ) + { this.connectionConfig = connectionConfig; this.serverVersion = serverVersion; } @Nonnull - public String getWelcomeMessage() { + public String getWelcomeMessage() + { String neo4j = "Neo4j"; - if (!serverVersion.isEmpty()) { + if ( !serverVersion.isEmpty() ) + { neo4j += " " + serverVersion; } - AnsiFormattedText welcomeMessage = AnsiFormattedText.from("Connected to ") - .append(neo4j) - .append(" at ") - .bold().append(connectionConfig.driverUrl()).boldOff(); + AnsiFormattedText welcomeMessage = AnsiFormattedText.from( "Connected to " ) + .append( neo4j ) + .append( " at " ) + .bold().append( connectionConfig.driverUrl() ).boldOff(); - if (!connectionConfig.username().isEmpty()) { + if ( !connectionConfig.username().isEmpty() ) + { welcomeMessage = welcomeMessage - .append(" as user ") - .bold().append(connectionConfig.username()).boldOff(); + .append( " as user " ) + .bold().append( connectionConfig.username() ).boldOff(); } return welcomeMessage - .append(".\nType ") - .bold().append(Help.COMMAND_NAME).boldOff() - .append(" for a list of available commands or ") - .bold().append(Exit.COMMAND_NAME).boldOff() - .append(" to exit the shell.") - .append("\nNote that Cypher queries must end with a ") - .bold().append("semicolon.").boldOff().formattedString(); + .append( ".\nType " ) + .bold().append( Help.COMMAND_NAME ).boldOff() + .append( " for a list of available commands or " ) + .bold().append( Exit.COMMAND_NAME ).boldOff() + .append( " to exit the shell." ) + .append( "\nNote that Cypher queries must end with a " ) + .bold().append( "semicolon." ).boldOff().formattedString(); } @Nonnull - public String getExitMessage() { - return AnsiFormattedText.s().append("\nBye!").formattedString(); + public String getExitMessage() + { + return AnsiFormattedText.s().append( "\nBye!" ).formattedString(); } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/build/Build.java b/cypher-shell/src/main/java/org/neo4j/shell/build/Build.java index 2ac06c2c..7bb32f4c 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/build/Build.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/build/Build.java @@ -1,16 +1,36 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.build; -import javax.annotation.Nonnull; import java.io.IOException; import java.io.InputStream; import java.util.Properties; +import javax.annotation.Nonnull; /** * This class provides access to build time variables */ -public class Build { +public class Build +{ - private static Properties props = null; + private static Properties props; /** * Reads the build generated properties file the first time it is called. @@ -18,17 +38,25 @@ public class Build { * @return build properties */ @Nonnull - private static Properties getProperties() { - if (props == null) { + private static Properties getProperties() + { + if ( props == null ) + { props = new Properties(); - try (InputStream stream = Build.class.getClassLoader().getResourceAsStream("build.properties")) { - if (stream == null) { - throw new IllegalStateException("Cannot read build.properties"); - } else { - props.load(stream); + try ( InputStream stream = Build.class.getClassLoader().getResourceAsStream( "build.properties" ) ) + { + if ( stream == null ) + { + throw new IllegalStateException( "Cannot read build.properties" ); } - } catch (IOException e) { - System.err.println("Could not read build properties: " + e.getMessage()); + else + { + props.load( stream ); + } + } + catch ( IOException e ) + { + System.err.println( "Could not read build properties: " + e.getMessage() ); } } @@ -39,15 +67,17 @@ private static Properties getProperties() { * @return the revision of the source code, or "dev" if no properties file could be read. */ @Nonnull - public static String version() { - return getProperties().getProperty("version", "dev"); + public static String version() + { + return getProperties().getProperty( "version", "dev" ); } /** * @return the revision of the Neo4j Driver, or "dev" if no properties file could be read. */ @Nonnull - public static String driverVersion() { - return getProperties().getProperty("driverVersion", "dev"); + public static String driverVersion() + { + return getProperties().getProperty( "driverVersion", "dev" ); } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/cli/AddParamArgumentAction.java b/cypher-shell/src/main/java/org/neo4j/shell/cli/AddParamArgumentAction.java index f49c248d..663661b9 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/cli/AddParamArgumentAction.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/cli/AddParamArgumentAction.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.cli; import net.sourceforge.argparse4j.inf.Argument; @@ -12,8 +31,7 @@ import org.neo4j.shell.util.ParameterSetter; /** - * Action that adds arguments to a ParameterMap. - * This action always consumes an argument. + * Action that adds arguments to a ParameterMap. This action always consumes an argument. */ public class AddParamArgumentAction extends ParameterSetter implements ArgumentAction { @@ -22,11 +40,11 @@ public class AddParamArgumentAction extends ParameterSetter attrs, String flag, Object value ) throws ArgumentParserException + public void run( ArgumentParser parser, Argument arg, Map attrs, String flag, Object value ) throws ArgumentParserException { try { @@ -34,7 +52,7 @@ public void run( ArgumentParser parser, Argument arg, Map attrs, } catch ( Exception e ) { - throw new ArgumentParserException(e.getMessage(), e, parser); + throw new ArgumentParserException( e.getMessage(), e, parser ); } } @@ -53,13 +71,13 @@ public boolean consumeArgument() @Override protected void onWrongUsage() { - throw new IllegalArgumentException("Incorrect usage.\nusage: --param \"name => value\""); + throw new IllegalArgumentException( "Incorrect usage.\nusage: --param \"name => value\"" ); } @Override protected void onWrongNumberOfArguments() { - throw new IllegalArgumentException("Incorrect number of arguments.\nusage: --param \"name => value\""); + throw new IllegalArgumentException( "Incorrect number of arguments.\nusage: --param \"name => value\"" ); } @Override diff --git a/cypher-shell/src/main/java/org/neo4j/shell/cli/CliArgHelper.java b/cypher-shell/src/main/java/org/neo4j/shell/cli/CliArgHelper.java index 7323dafa..1469b21c 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/cli/CliArgHelper.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/cli/CliArgHelper.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.cli; import net.sourceforge.argparse4j.ArgumentParsers; @@ -16,8 +35,6 @@ import java.io.PrintWriter; import java.net.URI; import java.net.URISyntaxException; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -32,23 +49,28 @@ /** * Command line argument parsing and related stuff */ -public class CliArgHelper { +public class CliArgHelper +{ /** * @param args to parse * @return null in case of error, commandline arguments otherwise */ @Nullable - public static CliArgs parse(@Nonnull String... args) { + public static CliArgs parse( @Nonnull String... args ) + { final CliArgs cliArgs = new CliArgs(); - final ArgumentParser parser = setupParser(cliArgs.getParameters()); + final ArgumentParser parser = setupParser( cliArgs.getParameters() ); final Namespace ns; - try { - ns = parser.parseArgs(args); - } catch (ArgumentParserException e) { - parser.handleError(e); + try + { + ns = parser.parseArgs( args ); + } + catch ( ArgumentParserException e ) + { + parser.handleError( e ); return null; } return getCliArgs( cliArgs, parser, ns ); @@ -70,82 +92,87 @@ public static CliArgs parseAndThrow( @Nonnull String... args ) throws ArgumentPa private static CliArgs getCliArgs( CliArgs cliArgs, ArgumentParser parser, Namespace ns ) { // Parse address string, returns null on error - final URI uri = parseURI( parser, ns.getString( "address")); + final URI uri = parseURI( parser, ns.getString( "address" ) ); - if (uri == null) { + if ( uri == null ) + { return null; } //--------------------- // Connection arguments - cliArgs.setScheme(uri.getScheme(), "bolt"); - cliArgs.setHost(uri.getHost(), "localhost"); + cliArgs.setScheme( uri.getScheme(), "bolt" ); + cliArgs.setHost( uri.getHost(), "localhost" ); int port = uri.getPort(); - cliArgs.setPort(port == -1 ? 7687 : port); + cliArgs.setPort( port == -1 ? 7687 : port ); // Also parse username and password from address if available parseUserInfo( uri, cliArgs ); // Only overwrite user/pass from address string if the arguments were specified - String user = ns.getString("username"); - if (!user.isEmpty()) { - cliArgs.setUsername(user, cliArgs.getUsername()); + String user = ns.getString( "username" ); + if ( !user.isEmpty() ) + { + cliArgs.setUsername( user, cliArgs.getUsername() ); } - String pass = ns.getString("password"); - if (!pass.isEmpty()) { - cliArgs.setPassword(pass, cliArgs.getPassword()); + String pass = ns.getString( "password" ); + if ( !pass.isEmpty() ) + { + cliArgs.setPassword( pass, cliArgs.getPassword() ); } - cliArgs.setEncryption(Encryption.parse(ns.get("encryption"))); - cliArgs.setDatabase(ns.getString("database")); - cliArgs.setInputFilename(ns.getString( "file" ) ); + cliArgs.setEncryption( Encryption.parse( ns.get( "encryption" ) ) ); + cliArgs.setDatabase( ns.getString( "database" ) ); + cliArgs.setInputFilename( ns.getString( "file" ) ); //---------------- // Other arguments // cypher string might not be given, represented by null - cliArgs.setCypher(ns.getString("cypher")); + cliArgs.setCypher( ns.getString( "cypher" ) ); // Fail behavior as sensible default and returns a proper type - cliArgs.setFailBehavior(ns.get("fail-behavior")); + cliArgs.setFailBehavior( ns.get( "fail-behavior" ) ); //Set Output format - cliArgs.setFormat(Format.parse(ns.get("format"))); + cliArgs.setFormat( Format.parse( ns.get( "format" ) ) ); - cliArgs.setDebugMode(ns.getBoolean("debug")); + cliArgs.setDebugMode( ns.getBoolean( "debug" ) ); - cliArgs.setNonInteractive(ns.getBoolean("force-non-interactive")); + cliArgs.setNonInteractive( ns.getBoolean( "force-non-interactive" ) ); - cliArgs.setWrap(ns.getBoolean("wrap")); + cliArgs.setWrap( ns.getBoolean( "wrap" ) ); - cliArgs.setNumSampleRows(ns.getInt("sample-rows")); + cliArgs.setNumSampleRows( ns.getInt( "sample-rows" ) ); - cliArgs.setVersion(ns.getBoolean("version")); + cliArgs.setVersion( ns.getBoolean( "version" ) ); - cliArgs.setDriverVersion(ns.getBoolean("driver-version")); + cliArgs.setDriverVersion( ns.getBoolean( "driver-version" ) ); return cliArgs; } - private static void parseUserInfo(URI uri, CliArgs cliArgs) + private static void parseUserInfo( URI uri, CliArgs cliArgs ) { String userInfo = uri.getUserInfo(); String user = null; String password = null; - if (userInfo != null) + if ( userInfo != null ) { String[] split = userInfo.split( ":" ); - if (split.length == 0) + if ( split.length == 0 ) { user = userInfo; - } else if (split.length == 2) + } + else if ( split.length == 2 ) { user = split[0]; password = split[1]; - } else { - throw new IllegalArgumentException("Cannot parse user and password from " + userInfo); } - + else + { + throw new IllegalArgumentException( "Cannot parse user and password from " + userInfo ); + } } - cliArgs.setUsername(user, ""); - cliArgs.setPassword(password, ""); + cliArgs.setUsername( user, "" ); + cliArgs.setPassword( password, "" ); } @Nullable @@ -172,7 +199,7 @@ static URI parseURI( ArgumentParser parser, String address ) } } - private static ArgumentParser setupParser(ParameterMap parameterMap) + private static ArgumentParser setupParser( ParameterMap parameterMap ) { ArgumentParser parser = ArgumentParsers.newArgumentParser( "cypher-shell" ).defaultHelp( true ).description( format( "A command line shell where you can execute Cypher against an instance of Neo4j. " + @@ -182,103 +209,111 @@ private static ArgumentParser setupParser(ParameterMap parameterMap) "example of piping a file:%n" + " cat some-cypher.txt | cypher-shell" ) ); - ArgumentGroup connGroup = parser.addArgumentGroup("connection arguments"); - connGroup.addArgument("-a", "--address") - .help("address and port to connect to") - .setDefault(String.format("%s://%s:%d", CliArgs.DEFAULT_SCHEME, CliArgs.DEFAULT_HOST, CliArgs.DEFAULT_PORT)); - connGroup.addArgument("-u", "--username") - .setDefault("") - .help("username to connect as. Can also be specified using environment variable " + ConnectionConfig.USERNAME_ENV_VAR); - connGroup.addArgument("-p", "--password") - .setDefault("") - .help("password to connect with. Can also be specified using environment variable " + ConnectionConfig.PASSWORD_ENV_VAR); - connGroup.addArgument("--encryption") - .help("whether the connection to Neo4j should be encrypted. This must be consistent with Neo4j's " + - "configuration. If choosing '" + Encryption.DEFAULT.name().toLowerCase() + - "' the encryption setting is deduced from the specified address. " + - "For example the 'neo4j+ssc' protocol would use encryption.") - .choices(new CollectionArgumentChoice<>( + ArgumentGroup connGroup = parser.addArgumentGroup( "connection arguments" ); + connGroup.addArgument( "-a", "--address" ) + .help( "address and port to connect to" ) + .setDefault( String.format( "%s://%s:%d", CliArgs.DEFAULT_SCHEME, CliArgs.DEFAULT_HOST, CliArgs.DEFAULT_PORT ) ); + connGroup.addArgument( "-u", "--username" ) + .setDefault( "" ) + .help( "username to connect as. Can also be specified using environment variable " + ConnectionConfig.USERNAME_ENV_VAR ); + connGroup.addArgument( "-p", "--password" ) + .setDefault( "" ) + .help( "password to connect with. Can also be specified using environment variable " + ConnectionConfig.PASSWORD_ENV_VAR ); + connGroup.addArgument( "--encryption" ) + .help( "whether the connection to Neo4j should be encrypted. This must be consistent with Neo4j's " + + "configuration. If choosing '" + Encryption.DEFAULT.name().toLowerCase() + + "' the encryption setting is deduced from the specified address. " + + "For example the 'neo4j+ssc' protocol would use encryption." ) + .choices( new CollectionArgumentChoice<>( Encryption.TRUE.name().toLowerCase(), Encryption.FALSE.name().toLowerCase(), - Encryption.DEFAULT.name().toLowerCase())) - .setDefault(Encryption.DEFAULT.name().toLowerCase()); - connGroup.addArgument("-d", "--database") - .help("database to connect to. Can also be specified using environment variable " + ConnectionConfig.DATABASE_ENV_VAR) - .setDefault(""); + Encryption.DEFAULT.name().toLowerCase() ) ) + .setDefault( Encryption.DEFAULT.name().toLowerCase() ); + connGroup.addArgument( "-d", "--database" ) + .help( "database to connect to. Can also be specified using environment variable " + ConnectionConfig.DATABASE_ENV_VAR ) + .setDefault( "" ); MutuallyExclusiveGroup failGroup = parser.addMutuallyExclusiveGroup(); - failGroup.addArgument("--fail-fast") - .help("exit and report failure on first error when reading from file (this is the default behavior)") - .dest("fail-behavior") - .setConst(FAIL_FAST) - .action(new StoreConstArgumentAction()); - failGroup.addArgument("--fail-at-end") - .help("exit and report failures at end of input when reading from file") - .dest("fail-behavior") - .setConst(FAIL_AT_END) - .action(new StoreConstArgumentAction()); - parser.setDefault("fail-behavior", FAIL_FAST); - - parser.addArgument("--format") - .help("desired output format, verbose displays results in tabular format and prints statistics, " + - "plain displays data with minimal formatting") - .choices(new CollectionArgumentChoice<>( - Format.AUTO.name().toLowerCase(), - Format.VERBOSE.name().toLowerCase(), - Format.PLAIN.name().toLowerCase())) - .setDefault(Format.AUTO.name().toLowerCase()); + failGroup.addArgument( "--fail-fast" ) + .help( "exit and report failure on first error when reading from file (this is the default behavior)" ) + .dest( "fail-behavior" ) + .setConst( FAIL_FAST ) + .action( new StoreConstArgumentAction() ); + failGroup.addArgument( "--fail-at-end" ) + .help( "exit and report failures at end of input when reading from file" ) + .dest( "fail-behavior" ) + .setConst( FAIL_AT_END ) + .action( new StoreConstArgumentAction() ); + parser.setDefault( "fail-behavior", FAIL_FAST ); + + parser.addArgument( "--format" ) + .help( "desired output format, verbose displays results in tabular format and prints statistics, " + + "plain displays data with minimal formatting" ) + .choices( new CollectionArgumentChoice<>( + Format.AUTO.name().toLowerCase(), + Format.VERBOSE.name().toLowerCase(), + Format.PLAIN.name().toLowerCase() ) ) + .setDefault( Format.AUTO.name().toLowerCase() ); parser.addArgument( "-P", "--param" ) .help( "Add a parameter to this session. Example: `-P \"number => 3\"`. This argument can be specified multiple times." ) .action( new AddParamArgumentAction( parameterMap ) ); - parser.addArgument("--debug") - .help("print additional debug information") - .action(new StoreTrueArgumentAction()); - - parser.addArgument("--non-interactive") - .help("force non-interactive mode, only useful if auto-detection fails (like on Windows)") - .dest("force-non-interactive") - .action(new StoreTrueArgumentAction()); - - parser.addArgument("--sample-rows") - .help("number of rows sampled to compute table widths (only for format=VERBOSE)") - .type(new PositiveIntegerType()) - .dest("sample-rows") - .setDefault(CliArgs.DEFAULT_NUM_SAMPLE_ROWS); - - parser.addArgument("--wrap") - .help("wrap table column values if column is too narrow (only for format=VERBOSE)") - .type(new BooleanArgumentType()) - .setDefault(true); - - parser.addArgument("-v", "--version") - .help("print version of cypher-shell and exit") - .action(new StoreTrueArgumentAction()); - - parser.addArgument("--driver-version") - .help("print version of the Neo4j Driver used and exit") - .dest("driver-version") - .action(new StoreTrueArgumentAction()); - - parser.addArgument("cypher") - .nargs("?") - .help("an optional string of cypher to execute and then exit"); - parser.addArgument("-f", "--file") - .help("Pass a file with cypher statements to be executed. After the statements have been executed cypher-shell will be shutdown"); + parser.addArgument( "--debug" ) + .help( "print additional debug information" ) + .action( new StoreTrueArgumentAction() ); + + parser.addArgument( "--non-interactive" ) + .help( "force non-interactive mode, only useful if auto-detection fails (like on Windows)" ) + .dest( "force-non-interactive" ) + .action( new StoreTrueArgumentAction() ); + + parser.addArgument( "--sample-rows" ) + .help( "number of rows sampled to compute table widths (only for format=VERBOSE)" ) + .type( new PositiveIntegerType() ) + .dest( "sample-rows" ) + .setDefault( CliArgs.DEFAULT_NUM_SAMPLE_ROWS ); + + parser.addArgument( "--wrap" ) + .help( "wrap table column values if column is too narrow (only for format=VERBOSE)" ) + .type( new BooleanArgumentType() ) + .setDefault( true ); + + parser.addArgument( "-v", "--version" ) + .help( "print version of cypher-shell and exit" ) + .action( new StoreTrueArgumentAction() ); + + parser.addArgument( "--driver-version" ) + .help( "print version of the Neo4j Driver used and exit" ) + .dest( "driver-version" ) + .action( new StoreTrueArgumentAction() ); + + parser.addArgument( "cypher" ) + .nargs( "?" ) + .help( "an optional string of cypher to execute and then exit" ); + parser.addArgument( "-f", "--file" ) + .help( "Pass a file with cypher statements to be executed. After the statements have been executed cypher-shell will be shutdown" ); return parser; } - private static class PositiveIntegerType implements ArgumentType { + private static class PositiveIntegerType implements ArgumentType + { @Override - public Integer convert(ArgumentParser parser, Argument arg, String value) throws ArgumentParserException { - try { - int result = Integer.parseInt(value); - if (result < 1) throw new NumberFormatException(value); + public Integer convert( ArgumentParser parser, Argument arg, String value ) throws ArgumentParserException + { + try + { + int result = Integer.parseInt( value ); + if ( result < 1 ) + { + throw new NumberFormatException( value ); + } return result; - } catch (NumberFormatException nfe) { - throw new ArgumentParserException("Invalid value: "+value, parser); + } + catch ( NumberFormatException nfe ) + { + throw new ArgumentParserException( "Invalid value: " + value, parser ); } } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/cli/CliArgs.java b/cypher-shell/src/main/java/org/neo4j/shell/cli/CliArgs.java index fc5ecacd..bfcb2952 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/cli/CliArgs.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/cli/CliArgs.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.cli; import java.util.Optional; @@ -9,7 +28,8 @@ import static org.neo4j.shell.DatabaseManager.ABSENT_DB_NAME; -public class CliArgs { +public class CliArgs +{ static final String DEFAULT_SCHEME = "neo4j"; static final String DEFAULT_HOST = "localhost"; static final int DEFAULT_PORT = 7687; @@ -27,201 +47,235 @@ public class CliArgs { private Optional cypher = Optional.empty(); private Encryption encryption = Encryption.DEFAULT; private boolean debugMode; - private boolean nonInteractive = false; - private boolean version = false; - private boolean driverVersion = false; + private boolean nonInteractive; + private boolean version; + private boolean driverVersion; private int numSampleRows = DEFAULT_NUM_SAMPLE_ROWS; private boolean wrap = true; - private String inputFilename = null; + private String inputFilename; private ParameterMap parameters = new ShellParameterMap(); /** * Set the scheme to the primary value, or if null, the fallback value. */ - public void setScheme(@Nullable String primary, @Nonnull String fallback) { + public void setScheme( @Nullable String primary, @Nonnull String fallback ) + { scheme = primary == null ? fallback : primary; } /** * Set the host to the primary value, or if null, the fallback value. */ - void setHost(@Nullable String primary, @Nonnull String fallback) { + void setHost( @Nullable String primary, @Nonnull String fallback ) + { host = primary == null ? fallback : primary; } - /** - * Set the port to the value. - */ - public void setPort(int port) { - this.port = port; - } - /** * Set the username to the primary value, or if null, the fallback value. */ - public void setUsername(@Nullable String primary, @Nonnull String fallback) { + public void setUsername( @Nullable String primary, @Nonnull String fallback ) + { username = primary == null ? fallback : primary; } /** * Set the password to the primary value, or if null, the fallback value. */ - public void setPassword(@Nullable String primary, @Nonnull String fallback) { + public void setPassword( @Nullable String primary, @Nonnull String fallback ) + { password = primary == null ? fallback : primary; } - /** - * Set the database to connect to. - */ - public void setDatabase(@Nullable String databaseName) { - this.databaseName = databaseName; + @Nonnull + public String getScheme() + { + return scheme; } - /** - * Set the desired fail behavior - */ - void setFailBehavior(@Nonnull FailBehavior failBehavior) { - this.failBehavior = failBehavior; + @Nonnull + public String getHost() + { + return host; } - /** - * Set the desired format - */ - public void setFormat(@Nonnull Format format) { - this.format = format; + public int getPort() + { + return port; } /** - * Set the specified cypher string to execute + * Set the port to the value. */ - public void setCypher(@Nullable String cypher) { - this.cypher = Optional.ofNullable(cypher); + public void setPort( int port ) + { + this.port = port; } - /** - * Set whether the connection should be encrypted - */ - public void setEncryption(Encryption encryption) { - this.encryption = encryption; + @Nonnull + public String getUsername() + { + return username; } - /** - * Force the shell to use non-interactive mode. Only useful on systems where auto-detection fails, such as Windows. - */ - public void setNonInteractive(boolean nonInteractive) { - this.nonInteractive = nonInteractive; + @Nonnull + public String getPassword() + { + return password; } - /** - * Sets a filename where to read Cypher statements from, much like piping statements from a file. - */ - public void setInputFilename(String inputFilename) + @Nonnull + public String getDatabase() { - this.inputFilename = inputFilename; + return databaseName; } /** - * Enable/disable debug mode + * Set the database to connect to. */ - void setDebugMode(boolean enabled) { - this.debugMode = enabled; - } - - @Nonnull - public String getScheme() { - return scheme; + public void setDatabase( @Nullable String databaseName ) + { + this.databaseName = databaseName; } @Nonnull - public String getHost() { - return host; + public FailBehavior getFailBehavior() + { + return failBehavior; } - public int getPort() { - return port; + /** + * Set the desired fail behavior + */ + void setFailBehavior( @Nonnull FailBehavior failBehavior ) + { + this.failBehavior = failBehavior; } @Nonnull - public String getUsername() { - return username; + public Optional getCypher() + { + return cypher; } - @Nonnull - public String getPassword() { - return password; + /** + * Set the specified cypher string to execute + */ + public void setCypher( @Nullable String cypher ) + { + this.cypher = Optional.ofNullable( cypher ); } @Nonnull - public String getDatabase() { - return databaseName; + public Format getFormat() + { + return format; } - @Nonnull - public FailBehavior getFailBehavior() { - return failBehavior; + /** + * Set the desired format + */ + public void setFormat( @Nonnull Format format ) + { + this.format = format; } - @Nonnull - public Optional getCypher() { - return cypher; + public Encryption getEncryption() + { + return encryption; } - @Nonnull - public Format getFormat() { - return format; + /** + * Set whether the connection should be encrypted + */ + public void setEncryption( Encryption encryption ) + { + this.encryption = encryption; } - public Encryption getEncryption() { - return encryption; + public boolean getDebugMode() + { + return debugMode; } - public boolean getDebugMode() { - return debugMode; + /** + * Enable/disable debug mode + */ + void setDebugMode( boolean enabled ) + { + this.debugMode = enabled; } - public boolean getNonInteractive() { + public boolean getNonInteractive() + { return nonInteractive; } + /** + * Force the shell to use non-interactive mode. Only useful on systems where auto-detection fails, such as Windows. + */ + public void setNonInteractive( boolean nonInteractive ) + { + this.nonInteractive = nonInteractive; + } + public String getInputFilename() { return inputFilename; } - public boolean getVersion() { + /** + * Sets a filename where to read Cypher statements from, much like piping statements from a file. + */ + public void setInputFilename( String inputFilename ) + { + this.inputFilename = inputFilename; + } + + public boolean getVersion() + { return version; } - public void setVersion(boolean version) { + public void setVersion( boolean version ) + { this.version = version; } - public boolean getDriverVersion() { + public boolean getDriverVersion() + { return driverVersion; } - public void setDriverVersion(boolean version) { + public void setDriverVersion( boolean version ) + { this.driverVersion = version; } - public boolean isStringShell() { + public boolean isStringShell() + { return cypher.isPresent(); } - public boolean getWrap() { + public boolean getWrap() + { return wrap; } - public void setWrap(boolean wrap) { + public void setWrap( boolean wrap ) + { this.wrap = wrap; } - public int getNumSampleRows() { + public int getNumSampleRows() + { return numSampleRows; } - public void setNumSampleRows(Integer numSampleRows) { - if (numSampleRows != null && numSampleRows > 0) { + public void setNumSampleRows( Integer numSampleRows ) + { + if ( numSampleRows != null && numSampleRows > 0 ) + { this.numSampleRows = numSampleRows; } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/cli/Encryption.java b/cypher-shell/src/main/java/org/neo4j/shell/cli/Encryption.java index 0e141f15..9eb24253 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/cli/Encryption.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/cli/Encryption.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.cli; import javax.annotation.Nonnull; @@ -8,12 +27,18 @@ public enum Encryption FALSE, DEFAULT; - public static Encryption parse( @Nonnull String format) { - if (format.equalsIgnoreCase(TRUE.name())) { + public static Encryption parse( @Nonnull String format ) + { + if ( format.equalsIgnoreCase( TRUE.name() ) ) + { return TRUE; - } else if (format.equalsIgnoreCase( FALSE.name() )) { + } + else if ( format.equalsIgnoreCase( FALSE.name() ) ) + { return FALSE; - } else { + } + else + { return DEFAULT; } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/cli/FailBehavior.java b/cypher-shell/src/main/java/org/neo4j/shell/cli/FailBehavior.java index e15a4cc9..c4b7cbb4 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/cli/FailBehavior.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/cli/FailBehavior.java @@ -1,6 +1,26 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.cli; -public enum FailBehavior { +public enum FailBehavior +{ FAIL_FAST, FAIL_AT_END } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/cli/FileHistorian.java b/cypher-shell/src/main/java/org/neo4j/shell/cli/FileHistorian.java index a27800bd..0611b17f 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/cli/FileHistorian.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/cli/FileHistorian.java @@ -1,89 +1,125 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.cli; import jline.console.ConsoleReader; import jline.console.history.FileHistory; import jline.console.history.MemoryHistory; -import org.neo4j.shell.Historian; -import org.neo4j.shell.log.Logger; -import javax.annotation.Nonnull; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import javax.annotation.Nonnull; + +import org.neo4j.shell.Historian; +import org.neo4j.shell.log.Logger; import static java.lang.System.getProperty; /** - * An historian which stores history in a file in the users home dir. The setup methods install a shutdown hook which - * will flush the history on exit. + * An historian which stores history in a file in the users home dir. The setup methods install a shutdown hook which will flush the history on exit. */ -public class FileHistorian implements Historian { +public class FileHistorian implements Historian +{ private final MemoryHistory history; - private FileHistorian(MemoryHistory history) { + private FileHistorian( MemoryHistory history ) + { this.history = history; } @Nonnull - public static Historian setupHistory(@Nonnull final ConsoleReader reader, - @Nonnull final Logger logger, - @Nonnull final File historyFile) throws IOException { - try { + public static Historian setupHistory( @Nonnull final ConsoleReader reader, + @Nonnull final Logger logger, + @Nonnull final File historyFile ) throws IOException + { + try + { File dir = historyFile.getParentFile(); - if (!dir.isDirectory() && !dir.mkdir()) { - throw new IOException("Failed to create directory for history: " + dir.getAbsolutePath()); + if ( !dir.isDirectory() && !dir.mkdir() ) + { + throw new IOException( "Failed to create directory for history: " + dir.getAbsolutePath() ); } - final FileHistory history = new FileHistory(historyFile); - reader.setHistory(history); + final FileHistory history = new FileHistory( historyFile ); + reader.setHistory( history ); // Make sure we flush history on exit - addShutdownHookToFlushHistory(logger, history); + addShutdownHookToFlushHistory( logger, history ); - return new FileHistorian(history); - } catch (IOException e) { - logger.printError("Could not load history file. Falling back to session-based history.\n" - + e.getMessage()); + return new FileHistorian( history ); + } + catch ( IOException e ) + { + logger.printError( "Could not load history file. Falling back to session-based history.\n" + + e.getMessage() ); MemoryHistory history = new MemoryHistory(); - reader.setHistory(history); - return new FileHistorian(history); + reader.setHistory( history ); + return new FileHistorian( history ); } } - private static void addShutdownHookToFlushHistory(@Nonnull final Logger logger, final FileHistory history) { - Runtime.getRuntime().addShutdownHook(new Thread() { + private static void addShutdownHookToFlushHistory( @Nonnull final Logger logger, final FileHistory history ) + { + Runtime.getRuntime().addShutdownHook( new Thread() + { @Override - public void run() { - try { + public void run() + { + try + { history.flush(); - } catch (IOException e) { - logger.printError("Failed to save history:\n" + e.getMessage()); + } + catch ( IOException e ) + { + logger.printError( "Failed to save history:\n" + e.getMessage() ); } } - }); + } ); } @Nonnull - public static File getDefaultHistoryFile() { + public static File getDefaultHistoryFile() + { // Storing in same directory as driver uses - File dir = new File(getProperty("user.home"), ".neo4j"); - return new File(dir, ".neo4j_history"); + File dir = new File( getProperty( "user.home" ), ".neo4j" ); + return new File( dir, ".neo4j_history" ); } @Nonnull @Override - public List getHistory() { - List result = new ArrayList<>(); + public List getHistory() + { + List result = new ArrayList<>(); - history.forEach(entry -> result.add(String.valueOf(entry.value()))); + history.forEach( entry -> result.add( String.valueOf( entry.value() ) ) ); return result; } @Override - public void flushHistory() throws IOException { - if (history instanceof FileHistory) { + public void flushHistory() throws IOException + { + if ( history instanceof FileHistory ) + { ((FileHistory) history).flush(); } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/cli/Format.java b/cypher-shell/src/main/java/org/neo4j/shell/cli/Format.java index ac08cf31..2666eb7e 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/cli/Format.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/cli/Format.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.cli; import javax.annotation.Nonnull; @@ -5,7 +24,8 @@ import static org.neo4j.shell.ShellRunner.isInputInteractive; import static org.neo4j.shell.ShellRunner.isOutputInteractive; -public enum Format { +public enum Format +{ // Will select depending based on STDOUT and STDIN redirection AUTO, // Intended for human consumption @@ -14,12 +34,18 @@ public enum Format { PLAIN; // TODO JSON, strictly intended for machine consumption with data formatted in JSON - public static Format parse(@Nonnull String format) { - if (format.equalsIgnoreCase(PLAIN.name())) { + public static Format parse( @Nonnull String format ) + { + if ( format.equalsIgnoreCase( PLAIN.name() ) ) + { return PLAIN; - } else if (format.equalsIgnoreCase( VERBOSE.name() )) { + } + else if ( format.equalsIgnoreCase( VERBOSE.name() ) ) + { return VERBOSE; - } else { + } + else + { return isInputInteractive() && isOutputInteractive() ? VERBOSE : PLAIN; } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/cli/InteractiveShellRunner.java b/cypher-shell/src/main/java/org/neo4j/shell/cli/InteractiveShellRunner.java index 9aea56c9..dfc2135b 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/cli/InteractiveShellRunner.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/cli/InteractiveShellRunner.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.cli; import jline.console.ConsoleReader; @@ -31,101 +50,124 @@ import static org.neo4j.shell.DatabaseManager.DATABASE_UNAVAILABLE_ERROR_CODE; /** - * A shell runner intended for interactive sessions where lines are input one by one and execution should happen - * along the way. + * A shell runner intended for interactive sessions where lines are input one by one and execution should happen along the way. */ -public class InteractiveShellRunner implements ShellRunner, SignalHandler { +public class InteractiveShellRunner implements ShellRunner, SignalHandler +{ static final String INTERRUPT_SIGNAL = "INT"; - private final static String FRESH_PROMPT = "> "; - private final static String TRANSACTION_PROMPT = "# "; - private final static String USERNAME_DB_DELIMITER = "@"; - private final static int ONELINE_PROMPT_MAX_LENGTH = 50; static final String UNRESOLVED_DEFAULT_DB_PROPMPT_TEXT = ""; static final String DATABASE_UNAVAILABLE_ERROR_PROMPT_TEXT = "[UNAVAILABLE]"; - + private static final String FRESH_PROMPT = "> "; + private static final String TRANSACTION_PROMPT = "# "; + private static final String USERNAME_DB_DELIMITER = "@"; + private static final int ONELINE_PROMPT_MAX_LENGTH = 50; // Need to know if we are currently executing when catch Ctrl-C, needs to be atomic due to // being called from different thread private final AtomicBoolean currentlyExecuting; - @Nonnull private final Logger logger; - @Nonnull private final ConsoleReader reader; - @Nonnull private final Historian historian; - @Nonnull private final StatementParser statementParser; - @Nonnull private final TransactionHandler txHandler; - @Nonnull private final DatabaseManager databaseManager; - @Nonnull private final StatementExecuter executer; - @Nonnull private final UserMessagesHandler userMessagesHandler; - @Nonnull private final ConnectionConfig connectionConfig; + @Nonnull + private final Logger logger; + @Nonnull + private final ConsoleReader reader; + @Nonnull + private final Historian historian; + @Nonnull + private final StatementParser statementParser; + @Nonnull + private final TransactionHandler txHandler; + @Nonnull + private final DatabaseManager databaseManager; + @Nonnull + private final StatementExecuter executer; + @Nonnull + private final UserMessagesHandler userMessagesHandler; + @Nonnull + private final ConnectionConfig connectionConfig; - private AnsiFormattedText continuationPrompt = null; + private AnsiFormattedText continuationPrompt; - public InteractiveShellRunner(@Nonnull StatementExecuter executer, - @Nonnull TransactionHandler txHandler, - @Nonnull DatabaseManager databaseManager, - @Nonnull Logger logger, - @Nonnull StatementParser statementParser, - @Nonnull InputStream inputStream, - @Nonnull File historyFile, - @Nonnull UserMessagesHandler userMessagesHandler, - @Nonnull ConnectionConfig connectionConfig) throws IOException { + public InteractiveShellRunner( @Nonnull StatementExecuter executer, + @Nonnull TransactionHandler txHandler, + @Nonnull DatabaseManager databaseManager, + @Nonnull Logger logger, + @Nonnull StatementParser statementParser, + @Nonnull InputStream inputStream, + @Nonnull File historyFile, + @Nonnull UserMessagesHandler userMessagesHandler, + @Nonnull ConnectionConfig connectionConfig ) throws IOException + { this.userMessagesHandler = userMessagesHandler; - this.currentlyExecuting = new AtomicBoolean(false); + this.currentlyExecuting = new AtomicBoolean( false ); this.executer = executer; this.txHandler = txHandler; this.databaseManager = databaseManager; this.logger = logger; this.statementParser = statementParser; - this.reader = setupConsoleReader(logger, inputStream); - this.historian = FileHistorian.setupHistory(reader, logger, historyFile); + this.reader = setupConsoleReader( logger, inputStream ); + this.historian = FileHistorian.setupHistory( reader, logger, historyFile ); this.connectionConfig = connectionConfig; // Catch ctrl-c - Signal.handle(new Signal(INTERRUPT_SIGNAL), this); + Signal.handle( new Signal( INTERRUPT_SIGNAL ), this ); } - private ConsoleReader setupConsoleReader(@Nonnull Logger logger, - @Nonnull InputStream inputStream) throws IOException { - ConsoleReader reader = new ConsoleReader(inputStream, logger.getOutputStream()); + private ConsoleReader setupConsoleReader( @Nonnull Logger logger, + @Nonnull InputStream inputStream ) throws IOException + { + ConsoleReader reader = new ConsoleReader( inputStream, logger.getOutputStream() ); // Disable expansion of bangs: ! - reader.setExpandEvents(false); + reader.setExpandEvents( false ); // Ensure Reader does not handle user input for ctrl+C behaviour - reader.setHandleUserInterrupt(false); + reader.setHandleUserInterrupt( false ); return reader; } @Override - public int runUntilEnd() { + public int runUntilEnd() + { int exitCode = Main.EXIT_SUCCESS; boolean running = true; - logger.printIfVerbose(userMessagesHandler.getWelcomeMessage()); + logger.printIfVerbose( userMessagesHandler.getWelcomeMessage() ); - while (running) { - try { - for (String statement : readUntilStatement()) { - currentlyExecuting.set(true); - executer.execute(statement); - currentlyExecuting.set(false); + while ( running ) + { + try + { + for ( String statement : readUntilStatement() ) + { + currentlyExecuting.set( true ); + executer.execute( statement ); + currentlyExecuting.set( false ); } - } catch (ExitException e) { + } + catch ( ExitException e ) + { exitCode = e.getCode(); running = false; - } catch (NoMoreInputException e) { + } + catch ( NoMoreInputException e ) + { // User pressed Ctrl-D and wants to exit running = false; - } catch (Throwable e) { - logger.printError(e); - } finally { - currentlyExecuting.set(false); + } + catch ( Throwable e ) + { + logger.printError( e ); + } + finally + { + currentlyExecuting.set( false ); } } - logger.printIfVerbose(userMessagesHandler.getExitMessage()); + logger.printIfVerbose( userMessagesHandler.getExitMessage() ); return exitCode; } @Nonnull @Override - public Historian getHistorian() { + public Historian getHistorian() + { return historian; } @@ -137,22 +179,27 @@ public Historian getHistorian() { * @throws NoMoreInputException */ @Nonnull - public List readUntilStatement() throws IOException, NoMoreInputException { - while (true) { - String line = reader.readLine(updateAndGetPrompt().renderedString()); - if (line == null) { + public List readUntilStatement() throws IOException, NoMoreInputException + { + while ( true ) + { + String line = reader.readLine( updateAndGetPrompt().renderedString() ); + if ( line == null ) + { // User hit CTRL-D, or file ended throw new NoMoreInputException(); } // Empty lines are ignored if nothing has been read yet - if (line.trim().isEmpty() && !statementParser.containsText()) { + if ( line.trim().isEmpty() && !statementParser.containsText() ) + { continue; } - statementParser.parseMoreText(line + "\n"); + statementParser.parseMoreText( line + "\n" ); - if (statementParser.hasStatements()) { + if ( statementParser.hasStatements() ) + { return statementParser.consumeStatements(); } } @@ -161,20 +208,23 @@ public List readUntilStatement() throws IOException, NoMoreInputExceptio /** * @return suitable prompt depending on current parsing state */ - AnsiFormattedText updateAndGetPrompt() { - if (statementParser.containsText()) { + AnsiFormattedText updateAndGetPrompt() + { + if ( statementParser.containsText() ) + { return continuationPrompt; } String databaseName = databaseManager.getActualDatabaseAsReportedByServer(); - if (databaseName == null || ABSENT_DB_NAME.equals(databaseName)) { + if ( databaseName == null || ABSENT_DB_NAME.equals( databaseName ) ) + { // We have failed to get a successful response from the connection ping query // Build the prompt from the db name as set by the user + a suffix indicating that we are in a disconnected state String dbNameSetByUser = databaseManager.getActiveDatabaseAsSetByUser(); - databaseName = ABSENT_DB_NAME.equals(dbNameSetByUser)? UNRESOLVED_DEFAULT_DB_PROPMPT_TEXT : dbNameSetByUser; + databaseName = ABSENT_DB_NAME.equals( dbNameSetByUser ) ? UNRESOLVED_DEFAULT_DB_PROPMPT_TEXT : dbNameSetByUser; } - String errorSuffix = getErrorPrompt(executer.lastNeo4jErrorCode()); + String errorSuffix = getErrorPrompt( executer.lastNeo4jErrorCode() ); int promptIndent = connectionConfig.username().length() + USERNAME_DB_DELIMITER.length() + @@ -183,21 +233,24 @@ AnsiFormattedText updateAndGetPrompt() { FRESH_PROMPT.length(); AnsiFormattedText prePrompt = AnsiFormattedText.s().bold() - .append(connectionConfig.username()) - .append("@") - .append(databaseName); + .append( connectionConfig.username() ) + .append( "@" ) + .append( databaseName ); // If we encountered an error with the connection ping query we display it in the prompt in RED - if (!errorSuffix.isEmpty()) { - prePrompt.colorRed().append(errorSuffix).colorDefault(); + if ( !errorSuffix.isEmpty() ) + { + prePrompt.colorRed().append( errorSuffix ).colorDefault(); } - if (promptIndent <= ONELINE_PROMPT_MAX_LENGTH) { - continuationPrompt = AnsiFormattedText.s().bold().append(OutputFormatter.repeat(' ', promptIndent)); + if ( promptIndent <= ONELINE_PROMPT_MAX_LENGTH ) + { + continuationPrompt = AnsiFormattedText.s().bold().append( OutputFormatter.repeat( ' ', promptIndent ) ); return prePrompt .append( txHandler.isTransactionOpen() ? TRANSACTION_PROMPT : FRESH_PROMPT ); - - } else { + } + else + { continuationPrompt = AnsiFormattedText.s().bold(); return prePrompt .appendNewLine() @@ -205,12 +258,16 @@ AnsiFormattedText updateAndGetPrompt() { } } - private String getErrorPrompt(String errorCode) { + private String getErrorPrompt( String errorCode ) + { // NOTE: errorCode can be null String errorPromptSuffix; - if (DATABASE_UNAVAILABLE_ERROR_CODE.equals(errorCode)) { + if ( DATABASE_UNAVAILABLE_ERROR_CODE.equals( errorCode ) ) + { errorPromptSuffix = DATABASE_UNAVAILABLE_ERROR_PROMPT_TEXT; - } else { + } + else + { errorPromptSuffix = ""; } return errorPromptSuffix; @@ -222,20 +279,24 @@ private String getErrorPrompt(String errorCode) { * @param signal to handle */ @Override - public void handle(final Signal signal) { + public void handle( final Signal signal ) + { // Stop any running cypher statements - if (currentlyExecuting.get()) { + if ( currentlyExecuting.get() ) + { executer.reset(); - } else { + } + else + { // Print a literal newline here to get around us being in the middle of the prompt logger.printError( AnsiFormattedText.s().colorRed() - .append("\nInterrupted (Note that Cypher queries must end with a ") - .bold().append("semicolon. ").boldOff() - .append("Type ") - .bold().append(Exit.COMMAND_NAME).append(" ").boldOff() - .append("to exit the shell.)") - .formattedString()); + .append( "\nInterrupted (Note that Cypher queries must end with a " ) + .bold().append( "semicolon. " ).boldOff() + .append( "Type " ) + .bold().append( Exit.COMMAND_NAME ).append( " " ).boldOff() + .append( "to exit the shell.)" ) + .formattedString() ); // Clear any text which has been inputted resetPrompt(); } @@ -244,26 +305,32 @@ public void handle(final Signal signal) { /** * Clears the prompt of any text which has been inputted and redraws it. */ - private void resetPrompt() { - try { + private void resetPrompt() + { + try + { // Clear whatever text has currently been inputted boolean more = true; - while (more) { + while ( more ) + { more = reader.delete(); } more = true; - while (more) { + while ( more ) + { more = reader.backspace(); } // Clear parser state statementParser.reset(); // Redraw the prompt now because the error message has changed the terminal text - reader.setPrompt(updateAndGetPrompt().renderedString()); + reader.setPrompt( updateAndGetPrompt().renderedString() ); reader.redrawLine(); reader.flush(); - } catch (IOException e) { - logger.printError(e); + } + catch ( IOException e ) + { + logger.printError( e ); } } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/cli/NonInteractiveShellRunner.java b/cypher-shell/src/main/java/org/neo4j/shell/cli/NonInteractiveShellRunner.java index 44f540cf..006d7772 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/cli/NonInteractiveShellRunner.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/cli/NonInteractiveShellRunner.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.cli; import java.io.BufferedReader; @@ -16,12 +35,12 @@ import static org.neo4j.shell.Main.EXIT_FAILURE; import static org.neo4j.shell.Main.EXIT_SUCCESS; - /** - * A shell runner which reads all of STDIN and executes commands until completion. In case of errors, the failBehavior - * determines if the shell exits immediately, or if it should keep trying the next commands. + * A shell runner which reads all of STDIN and executes commands until completion. In case of errors, the failBehavior determines if the shell exits + * immediately, or if it should keep trying the next commands. */ -public class NonInteractiveShellRunner implements ShellRunner { +public class NonInteractiveShellRunner implements ShellRunner +{ private final FailBehavior failBehavior; @Nonnull @@ -30,11 +49,12 @@ public class NonInteractiveShellRunner implements ShellRunner { private final StatementParser statementParser; private final InputStream inputStream; - public NonInteractiveShellRunner(@Nonnull FailBehavior failBehavior, - @Nonnull StatementExecuter executer, - @Nonnull Logger logger, - @Nonnull StatementParser statementParser, - @Nonnull InputStream inputStream) { + public NonInteractiveShellRunner( @Nonnull FailBehavior failBehavior, + @Nonnull StatementExecuter executer, + @Nonnull Logger logger, + @Nonnull StatementParser statementParser, + @Nonnull InputStream inputStream ) + { this.failBehavior = failBehavior; this.executer = executer; this.logger = logger; @@ -43,29 +63,40 @@ public NonInteractiveShellRunner(@Nonnull FailBehavior failBehavior, } @Override - public int runUntilEnd() { + public int runUntilEnd() + { List statements; - try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) { + try ( BufferedReader bufferedReader = new BufferedReader( new InputStreamReader( inputStream ) ) ) + { bufferedReader .lines() - .forEach(line -> statementParser.parseMoreText(line + "\n")); + .forEach( line -> statementParser.parseMoreText( line + "\n" ) ); statements = statementParser.consumeStatements(); - } catch (Throwable e) { - logger.printError(e); + } + catch ( Throwable e ) + { + logger.printError( e ); return 1; } int exitCode = EXIT_SUCCESS; - for (String statement : statements) { - try { - executer.execute(statement); - } catch (ExitException e) { + for ( String statement : statements ) + { + try + { + executer.execute( statement ); + } + catch ( ExitException e ) + { // These exceptions are always fatal return e.getCode(); - } catch (Throwable e) { + } + catch ( Throwable e ) + { exitCode = EXIT_FAILURE; - logger.printError(e); - if (FailBehavior.FAIL_AT_END != failBehavior) { + logger.printError( e ); + if ( FailBehavior.FAIL_AT_END != failBehavior ) + { return exitCode; } } @@ -75,7 +106,8 @@ public int runUntilEnd() { @Nonnull @Override - public Historian getHistorian() { + public Historian getHistorian() + { return Historian.empty; } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/commands/Begin.java b/cypher-shell/src/main/java/org/neo4j/shell/commands/Begin.java index b3a2ea40..e4e3e497 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/commands/Begin.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/commands/Begin.java @@ -1,60 +1,87 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.commands; +import java.util.Collections; +import java.util.List; +import javax.annotation.Nonnull; + import org.neo4j.shell.TransactionHandler; import org.neo4j.shell.exception.CommandException; import org.neo4j.shell.exception.ExitException; -import javax.annotation.Nonnull; -import java.util.Collections; -import java.util.List; - import static org.neo4j.shell.commands.CommandHelper.simpleArgParse; /** * This command starts a transaction. */ -public class Begin implements Command { +public class Begin implements Command +{ private static final String COMMAND_NAME = ":begin"; private final TransactionHandler transactionHandler; - public Begin(@Nonnull final TransactionHandler transactionHandler) { + public Begin( @Nonnull final TransactionHandler transactionHandler ) + { this.transactionHandler = transactionHandler; } @Nonnull @Override - public String getName() { + public String getName() + { return COMMAND_NAME; } @Nonnull @Override - public String getDescription() { + public String getDescription() + { return "Open a transaction"; } @Nonnull @Override - public String getUsage() { + public String getUsage() + { return ""; } @Nonnull @Override - public String getHelp() { - return String.format("Start a transaction which will remain open until %s or %s is called", - Commit.COMMAND_NAME, Rollback.COMMAND_NAME); + public String getHelp() + { + return String.format( "Start a transaction which will remain open until %s or %s is called", + Commit.COMMAND_NAME, Rollback.COMMAND_NAME ); } @Nonnull @Override - public List getAliases() { + public List getAliases() + { return Collections.emptyList(); } @Override - public void execute(@Nonnull final String argString) throws ExitException, CommandException { - simpleArgParse(argString, 0, COMMAND_NAME, getUsage()); + public void execute( @Nonnull final String argString ) throws ExitException, CommandException + { + simpleArgParse( argString, 0, COMMAND_NAME, getUsage() ); transactionHandler.beginTransaction(); } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/commands/Command.java b/cypher-shell/src/main/java/org/neo4j/shell/commands/Command.java index 8ea201c3..527d8e52 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/commands/Command.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/commands/Command.java @@ -1,15 +1,35 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.commands; +import java.util.List; +import javax.annotation.Nonnull; + import org.neo4j.shell.exception.CommandException; import org.neo4j.shell.exception.ExitException; -import javax.annotation.Nonnull; -import java.util.List; - /** * A shell command */ -public interface Command { +public interface Command +{ @Nonnull String getName(); @@ -27,5 +47,5 @@ public interface Command { @Nonnull List getAliases(); - void execute(@Nonnull final String args) throws ExitException, CommandException; + void execute( @Nonnull String args ) throws ExitException, CommandException; } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/commands/CommandExecutable.java b/cypher-shell/src/main/java/org/neo4j/shell/commands/CommandExecutable.java index b582a83a..1cb9f09c 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/commands/CommandExecutable.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/commands/CommandExecutable.java @@ -1,9 +1,29 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.commands; import org.neo4j.shell.exception.CommandException; import org.neo4j.shell.exception.ExitException; @FunctionalInterface -public interface CommandExecutable { +public interface CommandExecutable +{ void execute() throws CommandException, ExitException; } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/commands/CommandHelper.java b/cypher-shell/src/main/java/org/neo4j/shell/commands/CommandHelper.java index b2972eb9..6b045f8c 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/commands/CommandHelper.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/commands/CommandHelper.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.commands; import java.util.List; @@ -17,51 +36,97 @@ /** * Utility methods for dealing with commands */ -public class CommandHelper { - private final TreeMap commands = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); +public class CommandHelper +{ + private final TreeMap commands = new TreeMap<>( String.CASE_INSENSITIVE_ORDER ); - public CommandHelper(Logger logger, Historian historian, CypherShell cypherShell) { - registerAllCommands(logger, historian, cypherShell); + public CommandHelper( Logger logger, Historian historian, CypherShell cypherShell ) + { + registerAllCommands( logger, historian, cypherShell ); } - private void registerAllCommands(Logger logger, - Historian historian, - CypherShell cypherShell) { - registerCommand(new Exit(logger)); - registerCommand(new Help(logger, this)); - registerCommand(new History(logger, historian)); - registerCommand(new Use(cypherShell)); - registerCommand(new Begin(cypherShell)); - registerCommand(new Commit(cypherShell)); - registerCommand(new Rollback(cypherShell)); - registerCommand(new Param(cypherShell.getParameterMap())); - registerCommand(new Params(logger, cypherShell.getParameterMap())); - registerCommand(new Source(cypherShell, new ShellStatementParser() )); + /** + * Split an argument string on whitespace + */ + @Nonnull + public static String[] simpleArgParse( @Nonnull final String argString, int expectedCount, + @Nonnull final String commandName, @Nonnull final String usage ) + throws CommandException + { + return simpleArgParse( argString, expectedCount, expectedCount, commandName, usage ); } - private void registerCommand(@Nonnull final Command command) throws DuplicateCommandException { - if (commands.containsKey(command.getName())) { - throw new DuplicateCommandException("This command name has already been registered: " + command.getName()); + /** + * Split an argument string on whitespace + */ + @Nonnull + public static String[] simpleArgParse( @Nonnull final String argString, int minCount, int maxCount, + @Nonnull final String commandName, @Nonnull final String usage ) + throws CommandException + { + final String[] args; + if ( argString.trim().isEmpty() ) + { + args = new String[] {}; + } + else + { + args = argString.trim().split( "\\s+" ); } - commands.put(command.getName(), command); + if ( args.length < minCount || args.length > maxCount ) + { + throw new CommandException( AnsiFormattedText.from( "Incorrect number of arguments.\nusage: " ) + .bold().append( commandName ).boldOff().append( " " ).append( usage ) ); + } - for (String alias: command.getAliases()) { - if (commands.containsKey(alias)) { - throw new DuplicateCommandException("This command alias has already been registered: " + alias); - } - commands.put(alias, command); + return args; + } + + private void registerAllCommands( Logger logger, + Historian historian, + CypherShell cypherShell ) + { + registerCommand( new Exit( logger ) ); + registerCommand( new Help( logger, this ) ); + registerCommand( new History( logger, historian ) ); + registerCommand( new Use( cypherShell ) ); + registerCommand( new Begin( cypherShell ) ); + registerCommand( new Commit( cypherShell ) ); + registerCommand( new Rollback( cypherShell ) ); + registerCommand( new Param( cypherShell.getParameterMap() ) ); + registerCommand( new Params( logger, cypherShell.getParameterMap() ) ); + registerCommand( new Source( cypherShell, new ShellStatementParser() ) ); + } + + private void registerCommand( @Nonnull final Command command ) throws DuplicateCommandException + { + if ( commands.containsKey( command.getName() ) ) + { + throw new DuplicateCommandException( "This command name has already been registered: " + command.getName() ); } + commands.put( command.getName(), command ); + + for ( String alias : command.getAliases() ) + { + if ( commands.containsKey( alias ) ) + { + throw new DuplicateCommandException( "This command alias has already been registered: " + alias ); + } + commands.put( alias, command ); + } } /** * Get a command corresponding to the given name, or null if no such command has been registered. */ @Nullable - public Command getCommand(@Nonnull final String name) { - if (commands.containsKey(name)) { - return commands.get(name); + public Command getCommand( @Nonnull final String name ) + { + if ( commands.containsKey( name ) ) + { + return commands.get( name ); } return null; } @@ -70,39 +135,8 @@ public Command getCommand(@Nonnull final String name) { * Get a list of all registered commands */ @Nonnull - public List getAllCommands() { - return commands.values().stream().distinct().collect(Collectors.toList()); - } - - /** - * Split an argument string on whitespace - */ - @Nonnull - public static String[] simpleArgParse(@Nonnull final String argString, int expectedCount, - @Nonnull final String commandName, @Nonnull final String usage) - throws CommandException { - return simpleArgParse(argString, expectedCount, expectedCount, commandName, usage); - } - - /** - * Split an argument string on whitespace - */ - @Nonnull - public static String[] simpleArgParse(@Nonnull final String argString, int minCount, int maxCount, - @Nonnull final String commandName, @Nonnull final String usage) - throws CommandException { - final String[] args; - if (argString.trim().isEmpty()) { - args = new String[] {}; - } else { - args = argString.trim().split("\\s+"); - } - - if (args.length < minCount || args.length > maxCount) { - throw new CommandException(AnsiFormattedText.from("Incorrect number of arguments.\nusage: ") - .bold().append(commandName).boldOff().append(" ").append(usage)); - } - - return args; + public List getAllCommands() + { + return commands.values().stream().distinct().collect( Collectors.toList() ); } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/commands/Commit.java b/cypher-shell/src/main/java/org/neo4j/shell/commands/Commit.java index 6a035a42..ad84300d 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/commands/Commit.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/commands/Commit.java @@ -1,59 +1,86 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.commands; +import java.util.Collections; +import java.util.List; +import javax.annotation.Nonnull; + import org.neo4j.shell.TransactionHandler; import org.neo4j.shell.exception.CommandException; import org.neo4j.shell.exception.ExitException; -import javax.annotation.Nonnull; -import java.util.Collections; -import java.util.List; - import static org.neo4j.shell.commands.CommandHelper.simpleArgParse; /** * This command marks a transaction as successful and closes it. */ -public class Commit implements Command { +public class Commit implements Command +{ public static final String COMMAND_NAME = ":commit"; private final TransactionHandler transactionHandler; - public Commit(@Nonnull final TransactionHandler transactionHandler) { + public Commit( @Nonnull final TransactionHandler transactionHandler ) + { this.transactionHandler = transactionHandler; } @Nonnull @Override - public String getName() { + public String getName() + { return COMMAND_NAME; } @Nonnull @Override - public String getDescription() { + public String getDescription() + { return "Commit the currently open transaction"; } @Nonnull @Override - public String getUsage() { + public String getUsage() + { return ""; } @Nonnull @Override - public String getHelp() { + public String getHelp() + { return "Commit and close the currently open transaction"; } @Nonnull @Override - public List getAliases() { + public List getAliases() + { return Collections.emptyList(); } @Override - public void execute(@Nonnull final String argString) throws ExitException, CommandException { - simpleArgParse(argString, 0, COMMAND_NAME, getUsage()); + public void execute( @Nonnull final String argString ) throws ExitException, CommandException + { + simpleArgParse( argString, 0, COMMAND_NAME, getUsage() ); transactionHandler.commitTransaction(); } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/commands/Exit.java b/cypher-shell/src/main/java/org/neo4j/shell/commands/Exit.java index c4daa61b..9c21f7db 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/commands/Exit.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/commands/Exit.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.commands; import java.util.Arrays; @@ -15,49 +34,57 @@ /** * Command to exit the logger. Equivalent to hitting Ctrl-D. */ -public class Exit implements Command { +public class Exit implements Command +{ public static final String COMMAND_NAME = ":exit"; private final Logger logger; - public Exit(@Nonnull final Logger logger) { + public Exit( @Nonnull final Logger logger ) + { this.logger = logger; } @Nonnull @Override - public String getName() { + public String getName() + { return COMMAND_NAME; } @Nonnull @Override - public String getDescription() { + public String getDescription() + { return "Exit the logger"; } @Nonnull @Override - public String getUsage() { + public String getUsage() + { return ""; } @Nonnull @Override - public String getHelp() { - return AnsiFormattedText.from("Exit the logger. Corresponds to entering ").bold().append("CTRL-D").boldOff() - .append(".").formattedString(); + public String getHelp() + { + return AnsiFormattedText.from( "Exit the logger. Corresponds to entering " ).bold().append( "CTRL-D" ).boldOff() + .append( "." ).formattedString(); } @Nonnull @Override - public List getAliases() { - return Arrays.asList(":quit"); + public List getAliases() + { + return Arrays.asList( ":quit" ); } @Override - public void execute(@Nonnull final String argString) throws ExitException, CommandException { - simpleArgParse(argString, 0, COMMAND_NAME, getUsage()); + public void execute( @Nonnull final String argString ) throws ExitException, CommandException + { + simpleArgParse( argString, 0, COMMAND_NAME, getUsage() ); - throw new ExitException(EXIT_SUCCESS); + throw new ExitException( EXIT_SUCCESS ); } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/commands/Help.java b/cypher-shell/src/main/java/org/neo4j/shell/commands/Help.java index 92cd58bb..cf57dece 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/commands/Help.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/commands/Help.java @@ -1,121 +1,156 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.commands; -import org.neo4j.shell.exception.CommandException; -import org.neo4j.shell.log.Logger; -import org.neo4j.shell.log.AnsiFormattedText; - -import javax.annotation.Nonnull; import java.util.Arrays; import java.util.List; +import javax.annotation.Nonnull; + +import org.neo4j.shell.exception.CommandException; +import org.neo4j.shell.log.AnsiFormattedText; +import org.neo4j.shell.log.Logger; import static org.neo4j.shell.commands.CommandHelper.simpleArgParse; /** * Help command, which prints help documentation. */ -public class Help implements Command { +public class Help implements Command +{ public static final String COMMAND_NAME = ":help"; + public static String CYPHER_REFCARD_LINK = "https://neo4j.com/docs/developer-manual/current/cypher/"; private final Logger logger; private final CommandHelper commandHelper; - public static String CYPHER_REFCARD_LINK = "https://neo4j.com/docs/developer-manual/current/cypher/"; - public Help(@Nonnull final Logger shell, @Nonnull final CommandHelper commandHelper) { + public Help( @Nonnull final Logger shell, @Nonnull final CommandHelper commandHelper ) + { this.logger = shell; this.commandHelper = commandHelper; } @Nonnull @Override - public String getName() { + public String getName() + { return COMMAND_NAME; } @Nonnull @Override - public String getDescription() { + public String getDescription() + { return "Show this help message"; } @Nonnull @Override - public String getUsage() { + public String getUsage() + { return "[command]"; } @Nonnull @Override - public String getHelp() { + public String getHelp() + { return "Show the list of available commands or help for a specific command."; } @Nonnull @Override - public List getAliases() { - return Arrays.asList(":man"); + public List getAliases() + { + return Arrays.asList( ":man" ); } @Override - public void execute(@Nonnull final String argString) throws CommandException { - String[] args = simpleArgParse(argString, 0, 1, COMMAND_NAME, getUsage()); - if (args.length == 0) { + public void execute( @Nonnull final String argString ) throws CommandException + { + String[] args = simpleArgParse( argString, 0, 1, COMMAND_NAME, getUsage() ); + if ( args.length == 0 ) + { printGeneralHelp(); - } else { - printHelpFor(args[0]); + } + else + { + printHelpFor( args[0] ); } } - private void printHelpFor(@Nonnull final String name) throws CommandException { - Command cmd = commandHelper.getCommand(name); - if (cmd == null && !name.startsWith(":")) { + private void printHelpFor( @Nonnull final String name ) throws CommandException + { + Command cmd = commandHelper.getCommand( name ); + if ( cmd == null && !name.startsWith( ":" ) ) + { // Be friendly to users and don't force them to type colons for help if possible - cmd = commandHelper.getCommand(":" + name); + cmd = commandHelper.getCommand( ":" + name ); } - if (cmd == null) { - throw new CommandException(AnsiFormattedText.from("No such command: ").bold().append(name)); + if ( cmd == null ) + { + throw new CommandException( AnsiFormattedText.from( "No such command: " ).bold().append( name ) ); } - logger.printOut(AnsiFormattedText.from("\nusage: ") - .bold().append(cmd.getName()) - .boldOff() - .append(" ") - .append(cmd.getUsage()) - .append("\n\n") - .append(cmd.getHelp()) - .append("\n") - .formattedString()); + logger.printOut( AnsiFormattedText.from( "\nusage: " ) + .bold().append( cmd.getName() ) + .boldOff() + .append( " " ) + .append( cmd.getUsage() ) + .append( "\n\n" ) + .append( cmd.getHelp() ) + .append( "\n" ) + .formattedString() ); } - private void printGeneralHelp() { - logger.printOut("\nAvailable commands:"); + private void printGeneralHelp() + { + logger.printOut( "\nAvailable commands:" ); // Get longest command so we can align them nicely List allCommands = commandHelper.getAllCommands(); - int leftColWidth = longestCmdLength(allCommands); + int leftColWidth = longestCmdLength( allCommands ); - allCommands.stream().forEach(cmd -> logger.printOut( - AnsiFormattedText.from(" ") - .bold().append(String.format("%-" + leftColWidth + "s", cmd.getName())) - .boldOff().append(" " + cmd.getDescription()) - .formattedString())); + allCommands.stream().forEach( cmd -> logger.printOut( + AnsiFormattedText.from( " " ) + .bold().append( String.format( "%-" + leftColWidth + "s", cmd.getName() ) ) + .boldOff().append( " " + cmd.getDescription() ) + .formattedString() ) ); - logger.printOut("\nFor help on a specific command type:"); - logger.printOut(AnsiFormattedText.from(" ") - .append(COMMAND_NAME) - .bold().append(" command") - .boldOff().append("\n").formattedString()); + logger.printOut( "\nFor help on a specific command type:" ); + logger.printOut( AnsiFormattedText.from( " " ) + .append( COMMAND_NAME ) + .bold().append( " command" ) + .boldOff().append( "\n" ).formattedString() ); - logger.printOut("\nFor help on cypher please visit:"); - logger.printOut(AnsiFormattedText.from(" ") - .append(CYPHER_REFCARD_LINK) - .append("\n").formattedString()); + logger.printOut( "\nFor help on cypher please visit:" ); + logger.printOut( AnsiFormattedText.from( " " ) + .append( CYPHER_REFCARD_LINK ) + .append( "\n" ).formattedString() ); } - private int longestCmdLength(List allCommands) { + private int longestCmdLength( List allCommands ) + { String longestCommand = allCommands.stream() - .map(Command::getName) - .reduce("", (s1, s2) -> s1.length() > s2.length() ? s1 : s2); + .map( Command::getName ) + .reduce( "", ( s1, s2 ) -> s1.length() > s2.length() ? s1 : s2 ); return longestCommand.length(); } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/commands/History.java b/cypher-shell/src/main/java/org/neo4j/shell/commands/History.java index 8dd7cf59..39018046 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/commands/History.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/commands/History.java @@ -1,69 +1,96 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.commands; +import java.util.Collections; +import java.util.List; +import javax.annotation.Nonnull; + import org.neo4j.shell.Historian; import org.neo4j.shell.exception.CommandException; import org.neo4j.shell.exception.ExitException; import org.neo4j.shell.log.Logger; -import javax.annotation.Nonnull; -import java.util.Collections; -import java.util.List; - import static org.neo4j.shell.commands.CommandHelper.simpleArgParse; /** * Show command history */ -public class History implements Command { +public class History implements Command +{ private static final String COMMAND_NAME = ":history"; private final Logger logger; private final Historian historian; private final List aliases = Collections.emptyList(); - public History(@Nonnull final Logger logger, @Nonnull final Historian historian) { + public History( @Nonnull final Logger logger, @Nonnull final Historian historian ) + { this.logger = logger; this.historian = historian; } @Nonnull @Override - public String getName() { + public String getName() + { return COMMAND_NAME; } @Nonnull @Override - public String getDescription() { + public String getDescription() + { return "Print a list of the last commands executed"; } @Nonnull @Override - public String getUsage() { + public String getUsage() + { return ""; } @Nonnull @Override - public String getHelp() { + public String getHelp() + { return "Print a list of the last commands executed."; } @Nonnull @Override - public List getAliases() { + public List getAliases() + { return aliases; } @Override - public void execute(@Nonnull String argString) throws ExitException, CommandException { - simpleArgParse(argString, 0, COMMAND_NAME, getUsage()); + public void execute( @Nonnull String argString ) throws ExitException, CommandException + { + simpleArgParse( argString, 0, COMMAND_NAME, getUsage() ); // Calculate starting position int lineCount = 16; - logger.printOut(printHistory(historian.getHistory(), lineCount)); + logger.printOut( printHistory( historian.getHistory(), lineCount ) ); } /** @@ -71,18 +98,20 @@ public void execute(@Nonnull String argString) throws ExitException, CommandExce * * @param lineCount number of entries to print */ - private String printHistory(@Nonnull final List history, final int lineCount) { + private String printHistory( @Nonnull final List history, final int lineCount ) + { // for alignment, check the string length of history size - int colWidth = Integer.toString(history.size()).length(); + int colWidth = Integer.toString( history.size() ).length(); String fmt = " %-" + colWidth + "d %s\n"; String result = ""; int count = 0; - for (int i = history.size() - 1; i >= 0 && count < lineCount; i--, count++) { - String line = history.get(i); + for ( int i = history.size() - 1; i >= 0 && count < lineCount; i--, count++ ) + { + String line = history.get( i ); // Executing old commands with !N actually starts from 1, and not 0, hence increment index by one - result = String.format(fmt, i + 1, line) + result; + result = String.format( fmt, i + 1, line ) + result; } return result; diff --git a/cypher-shell/src/main/java/org/neo4j/shell/commands/Param.java b/cypher-shell/src/main/java/org/neo4j/shell/commands/Param.java index cdff2894..95c0988b 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/commands/Param.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/commands/Param.java @@ -1,74 +1,96 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.commands; +import java.util.Collections; +import java.util.List; +import javax.annotation.Nonnull; + import org.neo4j.cypher.internal.evaluator.EvaluationException; import org.neo4j.shell.ParameterMap; import org.neo4j.shell.exception.CommandException; import org.neo4j.shell.log.AnsiFormattedText; import org.neo4j.shell.util.ParameterSetter; -import javax.annotation.Nonnull; -import java.util.Collections; -import java.util.List; -import java.util.function.BiPredicate; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - - /** * This command sets a variable to a name, for use as query parameter. */ -public class Param extends ParameterSetter implements Command { - private final static String COMMAND_NAME = ":param"; +public class Param extends ParameterSetter implements Command +{ + private static final String COMMAND_NAME = ":param"; /** * @param parameterMap the map to set parameters in */ - public Param(@Nonnull final ParameterMap parameterMap) { - super(parameterMap); + public Param( @Nonnull final ParameterMap parameterMap ) + { + super( parameterMap ); } @Nonnull @Override - public String getName() { + public String getName() + { return COMMAND_NAME; } @Nonnull @Override - public String getDescription() { + public String getDescription() + { return "Set the value of a query parameter"; } @Nonnull @Override - public String getUsage() { - return "name => value" ; + public String getUsage() + { + return "name => value"; } @Nonnull @Override - public String getHelp() { + public String getHelp() + { return "Set the specified query parameter to the value given"; } @Nonnull @Override - public List getAliases() { + public List getAliases() + { return Collections.emptyList(); } @Override protected void onWrongUsage() throws CommandException { - throw new CommandException(AnsiFormattedText.from("Incorrect usage.\nusage: ") - .bold().append( COMMAND_NAME ).boldOff().append( " ").append( getUsage())); + throw new CommandException( AnsiFormattedText.from( "Incorrect usage.\nusage: " ) + .bold().append( COMMAND_NAME ).boldOff().append( " " ).append( getUsage() ) ); } @Override protected void onWrongNumberOfArguments() throws CommandException { - throw new CommandException(AnsiFormattedText.from("Incorrect number of arguments.\nusage: ") - .bold().append( COMMAND_NAME ).boldOff().append( " ").append( getUsage())); + throw new CommandException( AnsiFormattedText.from( "Incorrect number of arguments.\nusage: " ) + .bold().append( COMMAND_NAME ).boldOff().append( " " ).append( getUsage() ) ); } @Override diff --git a/cypher-shell/src/main/java/org/neo4j/shell/commands/Params.java b/cypher-shell/src/main/java/org/neo4j/shell/commands/Params.java index 0db3daae..21ca5526 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/commands/Params.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/commands/Params.java @@ -1,17 +1,36 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.commands; -import org.neo4j.shell.ParameterMap; -import org.neo4j.shell.exception.CommandException; -import org.neo4j.shell.exception.ExitException; -import org.neo4j.shell.log.Logger; -import org.neo4j.shell.prettyprint.CypherVariablesFormatter; - -import javax.annotation.Nonnull; import java.util.Arrays; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; +import javax.annotation.Nonnull; + +import org.neo4j.shell.ParameterMap; +import org.neo4j.shell.exception.CommandException; +import org.neo4j.shell.exception.ExitException; +import org.neo4j.shell.log.Logger; +import org.neo4j.shell.prettyprint.CypherVariablesFormatter; import static org.neo4j.shell.commands.CommandHelper.simpleArgParse; import static org.neo4j.shell.prettyprint.CypherVariablesFormatter.escape; @@ -19,80 +38,98 @@ /** * This lists all query parameters which have been set */ -public class Params implements Command { +public class Params implements Command +{ public static final String COMMAND_NAME = ":params"; + private static final Pattern backtickPattern = Pattern.compile( "^\\s*(?(`([^`])*`)+?)\\s*" ); private final Logger logger; private final ParameterMap parameterMap; - private static final Pattern backtickPattern = Pattern.compile("^\\s*(?(`([^`])*`)+?)\\s*"); - public Params(@Nonnull Logger logger, @Nonnull ParameterMap parameterMap) { + public Params( @Nonnull Logger logger, @Nonnull ParameterMap parameterMap ) + { this.logger = logger; this.parameterMap = parameterMap; } @Nonnull @Override - public String getName() { + public String getName() + { return COMMAND_NAME; } @Nonnull @Override - public String getDescription() { + public String getDescription() + { return "Print all currently set query parameters and their values"; } @Nonnull @Override - public String getUsage() { + public String getUsage() + { return "[parameter]"; } @Nonnull @Override - public String getHelp() { + public String getHelp() + { return "Print a table of all currently set query parameters or the value for the given parameter"; } @Nonnull @Override - public List getAliases() { - return Arrays.asList(":parameters"); + public List getAliases() + { + return Arrays.asList( ":parameters" ); } @Override - public void execute(@Nonnull final String argString) throws ExitException, CommandException { + public void execute( @Nonnull final String argString ) throws ExitException, CommandException + { String trim = argString.trim(); - Matcher matcher = backtickPattern.matcher(trim); - if (trim.startsWith("`") && matcher.matches()) { - listParam(trim); - } else { - String[] args = simpleArgParse(argString, 0, 1, COMMAND_NAME, getUsage()); - if (args.length > 0) { - listParam(args[0]); - } else { + Matcher matcher = backtickPattern.matcher( trim ); + if ( trim.startsWith( "`" ) && matcher.matches() ) + { + listParam( trim ); + } + else + { + String[] args = simpleArgParse( argString, 0, 1, COMMAND_NAME, getUsage() ); + if ( args.length > 0 ) + { + listParam( args[0] ); + } + else + { listAllParams(); } } } - private void listParam(@Nonnull String name) throws CommandException { - String parameterName = CypherVariablesFormatter.unescapedCypherVariable(name); - if (!this.parameterMap.getAllAsUserInput().containsKey(parameterName)) { - throw new CommandException("Unknown parameter: " + name); + private void listParam( @Nonnull String name ) throws CommandException + { + String parameterName = CypherVariablesFormatter.unescapedCypherVariable( name ); + if ( !this.parameterMap.getAllAsUserInput().containsKey( parameterName ) ) + { + throw new CommandException( "Unknown parameter: " + name ); } - listParam(name.length(), name, this.parameterMap.getAllAsUserInput().get(parameterName).getValueAsString()); + listParam( name.length(), name, this.parameterMap.getAllAsUserInput().get( parameterName ).getValueAsString() ); } - private void listParam(int leftColWidth, @Nonnull String key, @Nonnull Object value) { - logger.printOut(String.format(":param %-" + leftColWidth + "s => %s", key, value)); + private void listParam( int leftColWidth, @Nonnull String key, @Nonnull Object value ) + { + logger.printOut( String.format( ":param %-" + leftColWidth + "s => %s", key, value ) ); } - private void listAllParams() { - List keys = parameterMap.getAllAsUserInput().keySet().stream().sorted().collect(Collectors.toList()); + private void listAllParams() + { + List keys = parameterMap.getAllAsUserInput().keySet().stream().sorted().collect( Collectors.toList() ); - int leftColWidth = keys.stream().map((s) -> escape(s).length()).reduce(0, Math::max); + int leftColWidth = keys.stream().map( s -> escape( s ).length() ).reduce( 0, Math::max ); - keys.forEach(key -> listParam(leftColWidth, escape(key), parameterMap.getAllAsUserInput().get(key).getValueAsString())); + keys.forEach( key -> listParam( leftColWidth, escape( key ), parameterMap.getAllAsUserInput().get( key ).getValueAsString() ) ); } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/commands/Rollback.java b/cypher-shell/src/main/java/org/neo4j/shell/commands/Rollback.java index d2383923..a789ddac 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/commands/Rollback.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/commands/Rollback.java @@ -1,59 +1,86 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.commands; +import java.util.Collections; +import java.util.List; +import javax.annotation.Nonnull; + import org.neo4j.shell.TransactionHandler; import org.neo4j.shell.exception.CommandException; import org.neo4j.shell.exception.ExitException; -import javax.annotation.Nonnull; -import java.util.Collections; -import java.util.List; - import static org.neo4j.shell.commands.CommandHelper.simpleArgParse; /** * This command marks a transaction as failed and closes it. */ -public class Rollback implements Command { +public class Rollback implements Command +{ public static final String COMMAND_NAME = ":rollback"; private final TransactionHandler transactionHandler; - public Rollback(@Nonnull final TransactionHandler transactionHandler) { + public Rollback( @Nonnull final TransactionHandler transactionHandler ) + { this.transactionHandler = transactionHandler; } @Nonnull @Override - public String getName() { + public String getName() + { return COMMAND_NAME; } @Nonnull @Override - public String getDescription() { + public String getDescription() + { return "Rollback the currently open transaction"; } @Nonnull @Override - public String getUsage() { + public String getUsage() + { return ""; } @Nonnull @Override - public String getHelp() { + public String getHelp() + { return "Roll back and closes the currently open transaction"; } @Nonnull @Override - public List getAliases() { + public List getAliases() + { return Collections.emptyList(); } @Override - public void execute(@Nonnull final String argString) throws ExitException, CommandException { - simpleArgParse(argString, 0, COMMAND_NAME, getUsage()); + public void execute( @Nonnull final String argString ) throws ExitException, CommandException + { + simpleArgParse( argString, 0, COMMAND_NAME, getUsage() ); transactionHandler.rollbackTransaction(); } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/commands/Source.java b/cypher-shell/src/main/java/org/neo4j/shell/commands/Source.java index 76153a44..2048fe73 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/commands/Source.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/commands/Source.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.commands; import java.io.BufferedReader; @@ -20,53 +39,62 @@ /** * This command reads a cypher file frome the filesystem and executes the statements therein. */ -public class Source implements Command { +public class Source implements Command +{ private static final String COMMAND_NAME = ":source"; private final CypherShell cypherShell; private final StatementParser statementParser; - public Source( CypherShell cypherShell, StatementParser statementParser ) { + public Source( CypherShell cypherShell, StatementParser statementParser ) + { this.cypherShell = cypherShell; this.statementParser = statementParser; } @Nonnull @Override - public String getName() { + public String getName() + { return COMMAND_NAME; } @Nonnull @Override - public String getDescription() { + public String getDescription() + { return "Interactively executes cypher statements from a file"; } @Nonnull @Override - public String getUsage() { + public String getUsage() + { return "[filename]"; } @Nonnull @Override - public String getHelp() { + public String getHelp() + { return "Executes Cypher statements from a file"; } @Nonnull @Override - public List getAliases() { + public List getAliases() + { return Collections.emptyList(); } @Override - public void execute(@Nonnull final String argString) throws ExitException, CommandException { - String filename = simpleArgParse(argString, 1, 1, COMMAND_NAME, getUsage())[0]; + public void execute( @Nonnull final String argString ) throws ExitException, CommandException + { + String filename = simpleArgParse( argString, 1, 1, COMMAND_NAME, getUsage() )[0]; - try ( BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream( new File(filename) )))) { + try ( BufferedReader bufferedReader = new BufferedReader( new InputStreamReader( new FileInputStream( new File( filename ) ) ) ) ) + { bufferedReader.lines() - .forEach(line -> statementParser.parseMoreText(line + "\n")); + .forEach( line -> statementParser.parseMoreText( line + "\n" ) ); List statements = statementParser.consumeStatements(); for ( String statement : statements ) { @@ -75,7 +103,7 @@ public void execute(@Nonnull final String argString) throws ExitException, Comma } catch ( IOException e ) { - throw new CommandException( format("Cannot find file: '%s'", filename), e); + throw new CommandException( format( "Cannot find file: '%s'", filename ), e ); } } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/commands/Use.java b/cypher-shell/src/main/java/org/neo4j/shell/commands/Use.java index bb66ffb9..449909c8 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/commands/Use.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/commands/Use.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.commands; import java.util.Collections; @@ -13,49 +32,59 @@ /** * This command starts a transaction. */ -public class Use implements Command { +public class Use implements Command +{ private static final String COMMAND_NAME = ":use"; - @Nonnull private final DatabaseManager databaseManager; - @Nonnull private String databaseName; + @Nonnull + private final DatabaseManager databaseManager; + @Nonnull + private String databaseName; - public Use(@Nonnull final DatabaseManager databaseManager) { + public Use( @Nonnull final DatabaseManager databaseManager ) + { this.databaseManager = databaseManager; } @Nonnull @Override - public String getName() { + public String getName() + { return COMMAND_NAME; } @Nonnull @Override - public String getDescription() { + public String getDescription() + { return "Set the active database"; } @Nonnull @Override - public String getUsage() { + public String getUsage() + { return "database"; } @Nonnull @Override - public String getHelp() { - return String.format("Set the active database that transactions are executed on", Commit.COMMAND_NAME); + public String getHelp() + { + return String.format( "Set the active database that transactions are executed on", Commit.COMMAND_NAME ); } @Nonnull @Override - public List getAliases() { + public List getAliases() + { return Collections.emptyList(); } @Override - public void execute(@Nonnull final String argString) throws ExitException, CommandException { - String[] args = simpleArgParse(argString, 0, 1, COMMAND_NAME, getUsage()); + public void execute( @Nonnull final String argString ) throws ExitException, CommandException + { + String[] args = simpleArgParse( argString, 0, 1, COMMAND_NAME, getUsage() ); String databaseName = args.length == 0 ? DatabaseManager.ABSENT_DB_NAME : args[0]; - databaseManager.setActiveDatabase(databaseName); + databaseManager.setActiveDatabase( databaseName ); } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/exception/AnsiFormattedException.java b/cypher-shell/src/main/java/org/neo4j/shell/exception/AnsiFormattedException.java index aa912c31..b8041326 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/exception/AnsiFormattedException.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/exception/AnsiFormattedException.java @@ -1,33 +1,57 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.exception; -import org.neo4j.shell.log.AnsiFormattedText; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import org.neo4j.shell.log.AnsiFormattedText; + /** * A type of exception where the message can formatted with Ansi codes. */ -public class AnsiFormattedException extends Exception { +public class AnsiFormattedException extends Exception +{ private final AnsiFormattedText message; - public AnsiFormattedException(@Nullable String message) { - super(message); - this.message = AnsiFormattedText.from(message); + public AnsiFormattedException( @Nullable String message ) + { + super( message ); + this.message = AnsiFormattedText.from( message ); } - public AnsiFormattedException(@Nullable String message, Throwable cause) { - super(message, cause); - this.message = AnsiFormattedText.from(message); + public AnsiFormattedException( @Nullable String message, Throwable cause ) + { + super( message, cause ); + this.message = AnsiFormattedText.from( message ); } - public AnsiFormattedException(@Nonnull AnsiFormattedText message) { - super(message.plainString()); + public AnsiFormattedException( @Nonnull AnsiFormattedText message ) + { + super( message.plainString() ); this.message = message; } @Nonnull - public AnsiFormattedText getFormattedMessage() { + public AnsiFormattedText getFormattedMessage() + { return message; } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/exception/CommandException.java b/cypher-shell/src/main/java/org/neo4j/shell/exception/CommandException.java index 45073616..613c4140 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/exception/CommandException.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/exception/CommandException.java @@ -1,23 +1,46 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.exception; -import org.neo4j.shell.log.AnsiFormattedText; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import org.neo4j.shell.log.AnsiFormattedText; + /** * And exception indicating that a command invocation failed. */ -public class CommandException extends AnsiFormattedException { - public CommandException(@Nullable String msg) { - super(msg); +public class CommandException extends AnsiFormattedException +{ + public CommandException( @Nullable String msg ) + { + super( msg ); } - public CommandException(@Nullable String msg, Throwable cause) { - super(msg, cause); + public CommandException( @Nullable String msg, Throwable cause ) + { + super( msg, cause ); } - public CommandException(@Nonnull AnsiFormattedText append) { - super(append); + public CommandException( @Nonnull AnsiFormattedText append ) + { + super( append ); } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/exception/DuplicateCommandException.java b/cypher-shell/src/main/java/org/neo4j/shell/exception/DuplicateCommandException.java index 2b11c09e..557e2ce8 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/exception/DuplicateCommandException.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/exception/DuplicateCommandException.java @@ -1,7 +1,28 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.exception; -public class DuplicateCommandException extends RuntimeException { - public DuplicateCommandException(String s) { - super(s); +public class DuplicateCommandException extends RuntimeException +{ + public DuplicateCommandException( String s ) + { + super( s ); } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/exception/ExitException.java b/cypher-shell/src/main/java/org/neo4j/shell/exception/ExitException.java index 562b4ab9..6ebbc83d 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/exception/ExitException.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/exception/ExitException.java @@ -1,14 +1,36 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.exception; -public class ExitException extends Error { +public class ExitException extends Error +{ private final int code; - public ExitException(int code) { + public ExitException( int code ) + { super(); this.code = code; } - public int getCode() { + public int getCode() + { return code; } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/exception/IncompleteStatementException.java b/cypher-shell/src/main/java/org/neo4j/shell/exception/IncompleteStatementException.java index 4f2edd55..6b0ac9d8 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/exception/IncompleteStatementException.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/exception/IncompleteStatementException.java @@ -1,4 +1,24 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.exception; -public class IncompleteStatementException extends IllegalArgumentException { +public class IncompleteStatementException extends IllegalArgumentException +{ } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/exception/NoMoreInputException.java b/cypher-shell/src/main/java/org/neo4j/shell/exception/NoMoreInputException.java index 663ea688..9899ee41 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/exception/NoMoreInputException.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/exception/NoMoreInputException.java @@ -1,8 +1,27 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.exception; /** - * Signifies that the user hit CTRL-D, or we simply ran out of file. - * Should many times exit gracefully. + * Signifies that the user hit CTRL-D, or we simply ran out of file. Should many times exit gracefully. */ -public class NoMoreInputException extends Exception { +public class NoMoreInputException extends Exception +{ } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/exception/UnconsumedStatementException.java b/cypher-shell/src/main/java/org/neo4j/shell/exception/UnconsumedStatementException.java index decd531c..270c41b6 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/exception/UnconsumedStatementException.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/exception/UnconsumedStatementException.java @@ -1,4 +1,24 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.exception; -public class UnconsumedStatementException extends IllegalArgumentException { +public class UnconsumedStatementException extends IllegalArgumentException +{ } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/log/AnsiFormattedText.java b/cypher-shell/src/main/java/org/neo4j/shell/log/AnsiFormattedText.java index b7a72d3a..f8a00bfe 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/log/AnsiFormattedText.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/log/AnsiFormattedText.java @@ -1,19 +1,39 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.log; import org.fusesource.jansi.Ansi; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; /** * A piece of text which can be rendered with Ansi format codes. */ -public class AnsiFormattedText { +public class AnsiFormattedText +{ private static final String RED = "RED"; private static final String BOLD = "BOLD"; @@ -23,36 +43,38 @@ public class AnsiFormattedText { // Each piece is formatted separately private final LinkedList pieces = new LinkedList<>(); // can be defined, or undefined. null means undefined. - private String color = null; + private String color; /** - * Return a new map which is a copy of the first map, with the keys/values from the second if they do not override - * anything already defined in the first map. + * Return a new map which is a copy of the first map, with the keys/values from the second if they do not override anything already defined in the first + * map. */ - private static Map mergeMaps(Map primary, Map secondary) { + private static Map mergeMaps( Map primary, Map secondary ) + { Map result = new HashMap<>(); - result.putAll(primary); - secondary.forEach(result::putIfAbsent); + result.putAll( primary ); + secondary.forEach( result::putIfAbsent ); return result; } /** - * * @return a new empty instance */ - public static AnsiFormattedText s() { + public static AnsiFormattedText s() + { return new AnsiFormattedText(); } /** - * * @param string to start with, may be null in which case it is ignored * @return a new instance containing the unformatted text in string, or empty if it was null */ - public static AnsiFormattedText from(@Nullable String string) { + public static AnsiFormattedText from( @Nullable String string ) + { AnsiFormattedText st = new AnsiFormattedText(); - if (string != null) { - st.append(string); + if ( string != null ) + { + st.append( string ); } return st; } @@ -61,30 +83,36 @@ public static AnsiFormattedText from(@Nullable String string) { * @return the text as a string including possible formatting, ready for ANSI formatting */ @Nonnull - public String formattedString() { + public String formattedString() + { StringBuilder sb = new StringBuilder(); - for (AnsiFormattedString s : pieces) { + for ( AnsiFormattedString s : pieces ) + { List codes = new ArrayList<>(); // color - if (s.color != null && !DEFAULT_COLOR.equals(s.color)) { - codes.add(s.color); + if ( s.color != null && !DEFAULT_COLOR.equals( s.color ) ) + { + codes.add( s.color ); } // attributes - if (s.attributes.getOrDefault(BOLD, false)) { - codes.add(BOLD); + if ( s.attributes.getOrDefault( BOLD, false ) ) + { + codes.add( BOLD ); } // Only do formatting if we actually have some formatting to apply - if (!codes.isEmpty()) { - sb.append("@|") - .append(String.join(",", codes)) - .append(" "); + if ( !codes.isEmpty() ) + { + sb.append( "@|" ) + .append( String.join( ",", codes ) ) + .append( " " ); } // string - sb.append(s.string); + sb.append( s.string ); // Only reset formatting if we actually did some formatting - if (!codes.isEmpty()) { - sb.append("|@"); + if ( !codes.isEmpty() ) + { + sb.append( "|@" ); } } return sb.toString(); @@ -94,30 +122,32 @@ public String formattedString() { * @return the text as a string rendered with ANSI escape codes */ @Nonnull - public String renderedString() { - return Ansi.ansi().render(formattedString()).toString(); + public String renderedString() + { + return Ansi.ansi().render( formattedString() ).toString(); } /** * @return the text as a plain string without any formatting */ @Nonnull - public String plainString() { + public String plainString() + { StringBuilder sb = new StringBuilder(); - pieces.forEach(sb::append); + pieces.forEach( sb::append ); return sb.toString(); } /** - * Append an already formatted string. If any formatting codes are defined, then they will be ignored in favor - * of this instance's formatting. + * Append an already formatted string. If any formatting codes are defined, then they will be ignored in favor of this instance's formatting. * * @param existing text to append using this instance's formatting * @return this */ - public AnsiFormattedText append(AnsiFormattedText existing) { - existing.pieces.forEach(s -> pieces.add(new AnsiFormattedString(color != null ? color : s.color, - mergeMaps(attributes, s.attributes), s.string))); + public AnsiFormattedText append( AnsiFormattedText existing ) + { + existing.pieces.forEach( s -> pieces.add( new AnsiFormattedString( color != null ? color : s.color, + mergeMaps( attributes, s.attributes ), s.string ) ) ); return this; } @@ -127,17 +157,20 @@ public AnsiFormattedText append(AnsiFormattedText existing) { * @param s string to append using this instance's formatting * @return this */ - public AnsiFormattedText append(String s) { - pieces.add(new AnsiFormattedString(color, attributes, s)); + public AnsiFormattedText append( String s ) + { + pieces.add( new AnsiFormattedString( color, attributes, s ) ); return this; } /** * Append a new line + * * @return this */ - public AnsiFormattedText appendNewLine() { - pieces.add(new AnsiFormattedString(color, attributes, System.lineSeparator())); + public AnsiFormattedText appendNewLine() + { + pieces.add( new AnsiFormattedString( color, attributes, System.lineSeparator() ) ); return this; } @@ -146,8 +179,9 @@ public AnsiFormattedText appendNewLine() { * * @return this */ - public AnsiFormattedText bold() { - attributes.put(BOLD, true); + public AnsiFormattedText bold() + { + attributes.put( BOLD, true ); return this; } @@ -156,8 +190,9 @@ public AnsiFormattedText bold() { * * @return this */ - public AnsiFormattedText boldOff() { - attributes.put(BOLD, false); + public AnsiFormattedText boldOff() + { + attributes.put( BOLD, false ); return this; } @@ -166,7 +201,8 @@ public AnsiFormattedText boldOff() { * * @return this */ - public AnsiFormattedText colorRed() { + public AnsiFormattedText colorRed() + { color = RED; return this; } @@ -176,30 +212,33 @@ public AnsiFormattedText colorRed() { * * @return this */ - public AnsiFormattedText colorDefault() { + public AnsiFormattedText colorDefault() + { color = DEFAULT_COLOR; return this; } - /** * A formatted string */ - private static class AnsiFormattedString { + private static class AnsiFormattedString + { // can be defined, or undefined. null means undefined. final String color; // same here, no mapping means undefined final Map attributes = new HashMap<>(); final String string; - AnsiFormattedString(String color, Map attributes, String s) { + AnsiFormattedString( String color, Map attributes, String s ) + { this.color = color; - this.attributes.putAll(attributes); + this.attributes.putAll( attributes ); this.string = s; } @Override - public String toString() { + public String toString() + { return string; } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/log/AnsiLogger.java b/cypher-shell/src/main/java/org/neo4j/shell/log/AnsiLogger.java index 69cc0dca..aa9f8f27 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/log/AnsiLogger.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/log/AnsiLogger.java @@ -1,18 +1,38 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.log; import org.fusesource.jansi.Ansi; import org.fusesource.jansi.AnsiConsole; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.nio.charset.StandardCharsets; +import javax.annotation.Nonnull; + import org.neo4j.driver.exceptions.ClientException; import org.neo4j.driver.exceptions.DiscoveryException; import org.neo4j.driver.exceptions.ServiceUnavailableException; import org.neo4j.shell.cli.Format; import org.neo4j.shell.exception.AnsiFormattedException; -import javax.annotation.Nonnull; -import java.io.ByteArrayOutputStream; -import java.io.PrintStream; -import java.nio.charset.StandardCharsets; - import static org.fusesource.jansi.internal.CLibrary.STDERR_FILENO; import static org.fusesource.jansi.internal.CLibrary.STDOUT_FILENO; import static org.fusesource.jansi.internal.CLibrary.isatty; @@ -20,40 +40,51 @@ /** * A basic logger which prints Ansi formatted text to STDOUT and STDERR */ -public class AnsiLogger implements Logger { +public class AnsiLogger implements Logger +{ private final PrintStream out; private final PrintStream err; private final boolean debug; private Format format; - public AnsiLogger(final boolean debug) { - this(debug, Format.VERBOSE, System.out, System.err); + public AnsiLogger( final boolean debug ) + { + this( debug, Format.VERBOSE, System.out, System.err ); } - public AnsiLogger(final boolean debug, @Nonnull Format format, - @Nonnull PrintStream out, @Nonnull PrintStream err) { + public AnsiLogger( final boolean debug, @Nonnull Format format, + @Nonnull PrintStream out, @Nonnull PrintStream err ) + { this.debug = debug; this.format = format; this.out = out; this.err = err; - try { - if (isOutputInteractive()) { - Ansi.setEnabled(true); + try + { + if ( isOutputInteractive() ) + { + Ansi.setEnabled( true ); AnsiConsole.systemInstall(); - } else { - Ansi.setEnabled(false); } - } catch (Throwable t) { + else + { + Ansi.setEnabled( false ); + } + } + catch ( Throwable t ) + { // Not running on a distro with standard c library, disable Ansi. - Ansi.setEnabled(false); + Ansi.setEnabled( false ); } } @Nonnull - private static Throwable getRootCause(@Nonnull final Throwable th) { + private static Throwable getRootCause( @Nonnull final Throwable th ) + { Throwable cause = th; - while (cause.getCause() != null) { + while ( cause.getCause() != null ) + { cause = cause.getCause(); } return cause; @@ -64,93 +95,117 @@ private static Throwable getRootCause(@Nonnull final Throwable th) { * @throws UnsatisfiedLinkError maybe if standard c library can't be found * @throws NoClassDefFoundError maybe if standard c library can't be found */ - private static boolean isOutputInteractive() { - return 1 == isatty(STDOUT_FILENO) && 1 == isatty(STDERR_FILENO); + private static boolean isOutputInteractive() + { + return 1 == isatty( STDOUT_FILENO ) && 1 == isatty( STDERR_FILENO ); } @Nonnull @Override - public PrintStream getOutputStream() { + public PrintStream getOutputStream() + { return out; } @Nonnull @Override - public PrintStream getErrorStream() { + public PrintStream getErrorStream() + { return err; } @Nonnull @Override - public Format getFormat() { + public Format getFormat() + { return format; } @Override - public void setFormat(@Nonnull Format format) { + public void setFormat( @Nonnull Format format ) + { this.format = format; } @Override - public boolean isDebugEnabled() { + public boolean isDebugEnabled() + { return debug; } @Override - public void printError(@Nonnull Throwable throwable) { - printError(getFormattedMessage(throwable)); + public void printError( @Nonnull Throwable throwable ) + { + printError( getFormattedMessage( throwable ) ); } @Override - public void printError(@Nonnull String s) { - err.println(Ansi.ansi().render(s).toString()); + public void printError( @Nonnull String s ) + { + err.println( Ansi.ansi().render( s ).toString() ); } @Override - public void printOut(@Nonnull final String msg) { - out.println(Ansi.ansi().render(msg).toString()); + public void printOut( @Nonnull final String msg ) + { + out.println( Ansi.ansi().render( msg ).toString() ); } /** * Formatting for Bolt exceptions. */ @Nonnull - public String getFormattedMessage(@Nonnull final Throwable e) { + public String getFormattedMessage( @Nonnull final Throwable e ) + { AnsiFormattedText msg = AnsiFormattedText.s().colorRed(); - if (isDebugEnabled()) { + if ( isDebugEnabled() ) + { ByteArrayOutputStream baos = new ByteArrayOutputStream(); - PrintStream ps = new PrintStream(baos); - e.printStackTrace(ps); - msg.append(new String(baos.toByteArray(), StandardCharsets.UTF_8)); - } else { - if (e instanceof AnsiFormattedException) { - msg = msg.append(((AnsiFormattedException) e).getFormattedMessage()); - } else if (e instanceof ClientException && - e.getMessage() != null && e.getMessage().contains("Missing username")) { + PrintStream ps = new PrintStream( baos ); + e.printStackTrace( ps ); + msg.append( new String( baos.toByteArray(), StandardCharsets.UTF_8 ) ); + } + else + { + if ( e instanceof AnsiFormattedException ) + { + msg = msg.append( ((AnsiFormattedException) e).getFormattedMessage() ); + } + else if ( e instanceof ClientException && + e.getMessage() != null && e.getMessage().contains( "Missing username" ) ) + { // Username and password was not specified - msg = msg.append(e.getMessage()) - .append("\nPlease specify --username, and optionally --password, as argument(s)") - .append("\nor as environment variable(s), NEO4J_USERNAME, and NEO4J_PASSWORD respectively.") - .append("\nSee --help for more info."); - } else { + msg = msg.append( e.getMessage() ) + .append( "\nPlease specify --username, and optionally --password, as argument(s)" ) + .append( "\nor as environment variable(s), NEO4J_USERNAME, and NEO4J_PASSWORD respectively." ) + .append( "\nSee --help for more info." ); + } + else + { Throwable cause = e; // Get the suppressed root cause of ServiceUnavailableExceptions - if (e instanceof ServiceUnavailableException) { + if ( e instanceof ServiceUnavailableException ) + { Throwable[] suppressed = e.getSuppressed(); - for (Throwable s : suppressed) { - if (s instanceof DiscoveryException ) { - cause = getRootCause(s); + for ( Throwable s : suppressed ) + { + if ( s instanceof DiscoveryException ) + { + cause = getRootCause( s ); break; } } } - if (cause.getMessage() != null) { - msg = msg.append(cause.getMessage()); - } else { - msg = msg.append(cause.getClass().getSimpleName()); + if ( cause.getMessage() != null ) + { + msg = msg.append( cause.getMessage() ); + } + else + { + msg = msg.append( cause.getClass().getSimpleName() ); } } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/log/Logger.java b/cypher-shell/src/main/java/org/neo4j/shell/log/Logger.java index 5e319867..1f42a824 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/log/Logger.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/log/Logger.java @@ -1,12 +1,32 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.log; +import java.io.PrintStream; +import javax.annotation.Nonnull; + import org.neo4j.shell.cli.Format; import org.neo4j.shell.prettyprint.LinePrinter; -import javax.annotation.Nonnull; -import java.io.PrintStream; - -public interface Logger extends LinePrinter { +public interface Logger extends LinePrinter +{ /** * @return the output stream */ @@ -20,19 +40,18 @@ public interface Logger extends LinePrinter { PrintStream getErrorStream(); /** - * Print a sanitized cause of the specified error. - * If debug mode is enabled, a full stacktrace should be printed as well. + * Print a sanitized cause of the specified error. If debug mode is enabled, a full stacktrace should be printed as well. * * @param throwable to print to the error stream */ - void printError(@Nonnull Throwable throwable); + void printError( @Nonnull Throwable throwable ); /** * Print the designated text to configured error stream. * * @param text to print to the error stream */ - void printError(@Nonnull String text); + void printError( @Nonnull String text ); /** * @return the current format of the logger @@ -45,7 +64,7 @@ public interface Logger extends LinePrinter { * * @param format to set */ - void setFormat(@Nonnull Format format); + void setFormat( @Nonnull Format format ); /** * @return true if debug mode is enabled, false otherwise @@ -57,33 +76,37 @@ public interface Logger extends LinePrinter { * * @param text to print to the output stream */ - default void printIfDebug(@Nonnull String text) { - if (isDebugEnabled()) { - printOut(text); + default void printIfDebug( @Nonnull String text ) + { + if ( isDebugEnabled() ) + { + printOut( text ); } } /** - * Convenience method which only prints the given text to the output stream if the format set - * is {@link Format#VERBOSE}. + * Convenience method which only prints the given text to the output stream if the format set is {@link Format#VERBOSE}. * * @param text to print to the output stream */ - default void printIfVerbose(@Nonnull String text) { - if (Format.VERBOSE.equals(getFormat())) { - printOut(text); + default void printIfVerbose( @Nonnull String text ) + { + if ( Format.VERBOSE.equals( getFormat() ) ) + { + printOut( text ); } } /** - * Convenience method which only prints the given text to the output stream if the format set - * is {@link Format#PLAIN}. + * Convenience method which only prints the given text to the output stream if the format set is {@link Format#PLAIN}. * * @param text to print to the output stream */ - default void printIfPlain(@Nonnull String text) { - if (Format.PLAIN.equals(getFormat())) { - printOut(text); + default void printIfPlain( @Nonnull String text ) + { + if ( Format.PLAIN.equals( getFormat() ) ) + { + printOut( text ); } } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/log/NullLogger.java b/cypher-shell/src/main/java/org/neo4j/shell/log/NullLogger.java index dc2201e3..4b5bd77a 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/log/NullLogger.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/log/NullLogger.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.log; import org.neo4j.driver.Logger; diff --git a/cypher-shell/src/main/java/org/neo4j/shell/log/NullLogging.java b/cypher-shell/src/main/java/org/neo4j/shell/log/NullLogging.java index e012e81e..6c326cf5 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/log/NullLogging.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/log/NullLogging.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.log; import org.neo4j.driver.Logger; diff --git a/cypher-shell/src/main/java/org/neo4j/shell/parser/ShellStatementParser.java b/cypher-shell/src/main/java/org/neo4j/shell/parser/ShellStatementParser.java index 731c3def..c64db0e7 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/parser/ShellStatementParser.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/parser/ShellStatementParser.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.parser; import java.util.ArrayList; @@ -9,9 +28,10 @@ /** * A cypher aware parser which can detect shell commands (:prefixed) or cypher. */ -public class ShellStatementParser implements StatementParser { +public class ShellStatementParser implements StatementParser +{ - private static final Pattern SHELL_CMD_PATTERN = Pattern.compile("^\\s*:.+\\s*$"); + private static final Pattern SHELL_CMD_PATTERN = Pattern.compile( "^\\s*:.+\\s*$" ); private static final char SEMICOLON = ';'; private static final char BACKSLASH = '\\'; private static final String LINE_COMMENT_START = "//"; @@ -27,63 +47,71 @@ public class ShellStatementParser implements StatementParser { private ArrayList parsedStatements; private int commentStart = NO_COMMENT; - public ShellStatementParser() { + public ShellStatementParser() + { parsedStatements = new ArrayList<>(); statement = new StringBuilder(); awaitedRightDelimiter = Optional.empty(); } /** - * Parses text and adds to the list of parsed statements if a statement is found to be completed. - * Note that it is expected that lines include newlines. + * Parses text and adds to the list of parsed statements if a statement is found to be completed. Note that it is expected that lines include newlines. * * @param line to parse (including ending newline) */ @Override - public void parseMoreText(@Nonnull String line) { + public void parseMoreText( @Nonnull String line ) + { // See if it could possibly be a shell command, only valid if not in a current statement - if ( statementNotStarted() && SHELL_CMD_PATTERN.matcher(line).find()) { - parsedStatements.add(line); + if ( statementNotStarted() && SHELL_CMD_PATTERN.matcher( line ).find() ) + { + parsedStatements.add( line ); return; } // We will guess it is cypher then boolean skipNext = false; char prev, current = (char) 0; - for (char c : line.toCharArray()) { + for ( char c : line.toCharArray() ) + { // append current - statement.append(c); + statement.append( c ); // last char shuffling prev = current; current = c; - if (skipNext) { + if ( skipNext ) + { // This char is escaped so gets no special treatment skipNext = false; continue; } - if (handleComments(prev, current)) { + if ( handleComments( prev, current ) ) + { continue; } - if (current == BACKSLASH) { + if ( current == BACKSLASH ) + { // backslash can escape stuff outside of comments (but inside quotes too!) skipNext = true; continue; } - if (handleQuotes(prev, current)) { + if ( handleQuotes( prev, current ) ) + { continue; } // Not escaped, not in a quote, not in a comment - if (handleSemicolon(current)) { + if ( handleSemicolon( current ) ) + { continue; } // If it's the start of a quote or comment - awaitedRightDelimiter = getRightDelimiter(prev, current); + awaitedRightDelimiter = getRightDelimiter( prev, current ); } } @@ -91,10 +119,12 @@ public void parseMoreText(@Nonnull String line) { * @param current character * @return true if parsing should go immediately to the next character, false otherwise */ - private boolean handleSemicolon(char current) { - if (current == SEMICOLON) { + private boolean handleSemicolon( char current ) + { + if ( current == SEMICOLON ) + { // end current statement - parsedStatements.add(statement.toString()); + parsedStatements.add( statement.toString() ); // start a new statement statement = new StringBuilder(); return true; @@ -103,13 +133,16 @@ private boolean handleSemicolon(char current) { } /** - * @param prev character + * @param prev character * @param current character * @return true if parsing should go immediately to the next character, false otherwise */ - private boolean handleQuotes(char prev, char current) { - if (inQuote()) { - if (isRightDelimiter(prev, current)) { + private boolean handleQuotes( char prev, char current ) + { + if ( inQuote() ) + { + if ( isRightDelimiter( prev, current ) ) + { // Then end it awaitedRightDelimiter = Optional.empty(); return true; @@ -121,18 +154,22 @@ private boolean handleQuotes(char prev, char current) { } /** - * @param prev character + * @param prev character * @param current character * @return true if parsing should go immediately to the next character, false otherwise */ - private boolean handleComments(char prev, char current) { - if (inComment()) { - if ( commentStart == NO_COMMENT ) { + private boolean handleComments( char prev, char current ) + { + if ( inComment() ) + { + if ( commentStart == NO_COMMENT ) + { //find the position of //.. or /*... //i.e. currentPos - 1 - 2 commentStart = statement.length() - 3; } - if (isRightDelimiter(prev, current)) { + if ( isRightDelimiter( prev, current ) ) + { // Then end it awaitedRightDelimiter = Optional.empty(); statement.delete( commentStart, statement.length() ); @@ -148,7 +185,8 @@ private boolean handleComments(char prev, char current) { /** * @return true if inside a quote, false otherwise */ - private boolean inQuote() { + private boolean inQuote() + { return awaitedRightDelimiter.isPresent() && !inComment(); } @@ -157,84 +195,99 @@ private boolean inQuote() { * @param last character * @return true if the last two chars ends the current comment, false otherwise */ - private boolean isRightDelimiter(char first, char last) { - if (!awaitedRightDelimiter.isPresent()) { + private boolean isRightDelimiter( char first, char last ) + { + if ( !awaitedRightDelimiter.isPresent() ) + { return false; } final String expectedEnd = awaitedRightDelimiter.get(); - if (expectedEnd.length() == 1) { - return expectedEnd.equals(String.valueOf(last)); - } else { - return expectedEnd.equals(String.valueOf(first) + last); + if ( expectedEnd.length() == 1 ) + { + return expectedEnd.equals( String.valueOf( last ) ); + } + else + { + return expectedEnd.equals( String.valueOf( first ) + last ); } } /** * @return true if we are currently inside a comment, false otherwise */ - private boolean inComment() { + private boolean inComment() + { return awaitedRightDelimiter.isPresent() && - (awaitedRightDelimiter.get().equals(LINE_COMMENT_END) || - awaitedRightDelimiter.get().equals(BLOCK_COMMENT_END)); + (awaitedRightDelimiter.get().equals( LINE_COMMENT_END ) || + awaitedRightDelimiter.get().equals( BLOCK_COMMENT_END )); } /** - * If the last characters start a quote or a comment, this returns the piece of text which will end said quote - * or comment. + * If the last characters start a quote or a comment, this returns the piece of text which will end said quote or comment. * * @param first character * @param last character * @return the matching right delimiter or something empty if not the start of a quote/comment */ @Nonnull - private Optional getRightDelimiter(char first, char last) { + private Optional getRightDelimiter( char first, char last ) + { // double characters - final String lastTwoChars = String.valueOf(first) + last; - switch (lastTwoChars) { - case LINE_COMMENT_START: - return Optional.of(LINE_COMMENT_END); - case BLOCK_COMMENT_START: - return Optional.of(BLOCK_COMMENT_END); + final String lastTwoChars = String.valueOf( first ) + last; + switch ( lastTwoChars ) + { + case LINE_COMMENT_START: + return Optional.of( LINE_COMMENT_END ); + case BLOCK_COMMENT_START: + return Optional.of( BLOCK_COMMENT_END ); + default: + // Do nothing } // single characters - switch (last) { - case BACKTICK: - case DOUBLE_QUOTE: - case SINGLE_QUOTE: - return Optional.of(String.valueOf(last)); + switch ( last ) + { + case BACKTICK: + case DOUBLE_QUOTE: + case SINGLE_QUOTE: + return Optional.of( String.valueOf( last ) ); + default: + return Optional.empty(); } - - return Optional.empty(); } /** * @return false if a statement has not begun (non whitespace has been seen) else true */ - private boolean statementNotStarted() { + private boolean statementNotStarted() + { return statement.toString().trim().isEmpty(); } @Override - public boolean hasStatements() { + public boolean hasStatements() + { return !parsedStatements.isEmpty(); } @Nonnull @Override - public List consumeStatements() { + public List consumeStatements() + { ArrayList result = parsedStatements; parsedStatements = new ArrayList<>(); return result; } @Override - public boolean containsText() { + public boolean containsText() + { return !statement.toString().trim().isEmpty(); } @Override - public void reset() { + public void reset() + { statement = new StringBuilder(); parsedStatements.clear(); awaitedRightDelimiter = Optional.empty(); diff --git a/cypher-shell/src/main/java/org/neo4j/shell/parser/StatementParser.java b/cypher-shell/src/main/java/org/neo4j/shell/parser/StatementParser.java index 0ae3775c..fc215032 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/parser/StatementParser.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/parser/StatementParser.java @@ -1,19 +1,39 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.parser; -import javax.annotation.Nonnull; import java.util.List; +import javax.annotation.Nonnull; /** * An object capable of parsing a piece of text and returning a List statements contained within. */ -public interface StatementParser { +public interface StatementParser +{ /** * Parse the next line of text * * @param line to parse */ - void parseMoreText(@Nonnull String line); + void parseMoreText( @Nonnull String line ); /** * @return true if any statements have been parsed yet, false otherwise @@ -21,8 +41,8 @@ public interface StatementParser { boolean hasStatements(); /** - * Once this method has been called, the method will return the empty list (unless more text is parsed). - * If nothing has been parsed yet, then the empty list is returned. + * Once this method has been called, the method will return the empty list (unless more text is parsed). If nothing has been parsed yet, then the empty list + * is returned. * * @return statements which have been parsed so far and remove them from internal state */ diff --git a/cypher-shell/src/main/java/org/neo4j/shell/prettyprint/CypherVariablesFormatter.java b/cypher-shell/src/main/java/org/neo4j/shell/prettyprint/CypherVariablesFormatter.java index d080ca81..c80c2221 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/prettyprint/CypherVariablesFormatter.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/prettyprint/CypherVariablesFormatter.java @@ -1,30 +1,56 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.prettyprint; -import javax.annotation.Nonnull; import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.annotation.Nonnull; -public class CypherVariablesFormatter { +public class CypherVariablesFormatter +{ private static final String BACKTICK = "`"; - private static final Pattern ALPHA_NUMERIC = Pattern.compile("^[\\p{L}_][\\p{L}0-9_]*"); + private static final Pattern ALPHA_NUMERIC = Pattern.compile( "^[\\p{L}_][\\p{L}0-9_]*" ); @Nonnull - public static String escape(@Nonnull String string) { - Matcher alphaNumericMatcher = ALPHA_NUMERIC.matcher(string); - if (!alphaNumericMatcher.matches()) { - String reEscapeBackTicks = string.replaceAll(BACKTICK, BACKTICK + BACKTICK); + public static String escape( @Nonnull String string ) + { + Matcher alphaNumericMatcher = ALPHA_NUMERIC.matcher( string ); + if ( !alphaNumericMatcher.matches() ) + { + String reEscapeBackTicks = string.replaceAll( BACKTICK, BACKTICK + BACKTICK ); return BACKTICK + reEscapeBackTicks + BACKTICK; } return string; } @Nonnull - public static String unescapedCypherVariable(@Nonnull String string) { - Matcher alphaNumericMatcher = ALPHA_NUMERIC.matcher(string); - if (!alphaNumericMatcher.matches()) { - String substring = string.substring(1, string.length() - 1); - return substring.replace(BACKTICK + BACKTICK, BACKTICK); - } else { + public static String unescapedCypherVariable( @Nonnull String string ) + { + Matcher alphaNumericMatcher = ALPHA_NUMERIC.matcher( string ); + if ( !alphaNumericMatcher.matches() ) + { + String substring = string.substring( 1, string.length() - 1 ); + return substring.replace( BACKTICK + BACKTICK, BACKTICK ); + } + else + { return string; } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/prettyprint/LinePrinter.java b/cypher-shell/src/main/java/org/neo4j/shell/prettyprint/LinePrinter.java index 248176c0..84887181 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/prettyprint/LinePrinter.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/prettyprint/LinePrinter.java @@ -1,15 +1,35 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.prettyprint; /** * Prints lines. */ @FunctionalInterface -public interface LinePrinter { +public interface LinePrinter +{ /** * Print the designated line to configured output stream. * * @param line to print to the output stream */ - void printOut(String line ); + void printOut( String line ); } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/prettyprint/OutputFormatter.java b/cypher-shell/src/main/java/org/neo4j/shell/prettyprint/OutputFormatter.java index b0b642be..848d28d2 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/prettyprint/OutputFormatter.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/prettyprint/OutputFormatter.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.prettyprint; import java.util.ArrayList; @@ -25,203 +44,275 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS; import static org.neo4j.shell.prettyprint.CypherVariablesFormatter.escape; -public interface OutputFormatter { - - enum Capabilities {INFO, PLAN, RESULT, FOOTER, STATISTICS} +public interface OutputFormatter +{ String COMMA_SEPARATOR = ", "; String COLON_SEPARATOR = ": "; String COLON = ":"; String SPACE = " "; - String NEWLINE = System.getProperty("line.separator"); - - int formatAndCount(@Nonnull BoltResult result, @Nonnull LinePrinter linePrinter); - - @Nonnull default String formatValue(final Value value) { - if (value == null) return ""; - TypeRepresentation type = (TypeRepresentation) value.type(); - switch (type.constructor()) { - case LIST: - return listAsString(value.asList(this::formatValue)); - case MAP: - return mapAsString(value.asMap(this::formatValue)); - case NODE: - return nodeAsString(value.asNode()); - case RELATIONSHIP: - return relationshipAsString(value.asRelationship()); - case PATH: - return pathAsString(value.asPath()); - case POINT: - return pointAsString(value.asPoint()); - case ANY: - case BOOLEAN: - case BYTES: - case STRING: - case NUMBER: - case INTEGER: - case FLOAT: - case DATE: - case TIME: - case DATE_TIME: - case LOCAL_TIME: - case LOCAL_DATE_TIME: - case DURATION: - case NULL: - default: - return value.toString(); - } - } - - @Nonnull - default String pointAsString(Point point) { - StringBuilder stringBuilder = new StringBuilder("point({"); - stringBuilder.append("srid:").append(point.srid()).append(","); - stringBuilder.append(" x:").append(point.x()).append(","); - stringBuilder.append(" y:").append(point.y()); - double z = point.z(); - if (!Double.isNaN(z)) { - stringBuilder.append(", z:").append(z); - } - stringBuilder.append("})"); - return stringBuilder.toString(); - } + String NEWLINE = System.getProperty( "line.separator" ); + List INFO_SUMMARY = asList( "Version", "Planner", "Runtime" ); @Nonnull - default String pathAsString(@Nonnull Path path) { - List list = new ArrayList<>(path.length()); - Node lastTraversed = path.start(); - if (lastTraversed != null) { - list.add(nodeAsString(lastTraversed)); - - for (Path.Segment segment : path) { - Relationship relationship = segment.relationship(); - if (relationship.startNodeId() == lastTraversed.id()) { - list.add("-" + relationshipAsString(relationship) + "->"); - } else { - list.add("<-" + relationshipAsString(relationship) + "-"); - } - list.add(nodeAsString(segment.end())); - lastTraversed = segment.end(); - } - } - - return String.join("", list); - } - - @Nonnull default String relationshipAsString(@Nonnull Relationship relationship) { - List relationshipAsString = new ArrayList<>(); - relationshipAsString.add(COLON + escape(relationship.type())); - relationshipAsString.add(mapAsStringWithEmpty(relationship.asMap(this::formatValue))); - - return "[" + joinWithSpace(relationshipAsString) + "]"; - } - - @Nonnull default String nodeAsString(@Nonnull final Node node) { - List nodeAsString = new ArrayList<>(); - nodeAsString.add(collectNodeLabels(node)); - nodeAsString.add(mapAsStringWithEmpty(node.asMap(this::formatValue))); - - return "(" + joinWithSpace(nodeAsString) + ")"; - } - - @Nonnull static String collectNodeLabels(@Nonnull Node node) { + static String collectNodeLabels( @Nonnull Node node ) + { StringBuilder sb = new StringBuilder(); - node.labels().forEach(label -> sb.append(COLON).append(escape(label))); + node.labels().forEach( label -> sb.append( COLON ).append( escape( label ) ) ); return sb.toString(); } - @Nonnull static String listAsString(@Nonnull List list) { - return list.stream().collect(Collectors.joining(COMMA_SEPARATOR,"[","]")); + @Nonnull + static String listAsString( @Nonnull List list ) + { + return list.stream().collect( Collectors.joining( COMMA_SEPARATOR, "[", "]" ) ); } - @Nonnull static String mapAsStringWithEmpty(@Nonnull Map map) { - return map.isEmpty() ? "" : mapAsString(map); + @Nonnull + static String mapAsStringWithEmpty( @Nonnull Map map ) + { + return map.isEmpty() ? "" : mapAsString( map ); } - @Nonnull static String mapAsString(@Nonnull Map map) { + @Nonnull + static String mapAsString( @Nonnull Map map ) + { return map.entrySet().stream() - .map(e -> escape(e.getKey()) + COLON_SEPARATOR + e.getValue()) - .collect(Collectors.joining(COMMA_SEPARATOR,"{","}")); + .map( e -> escape( e.getKey() ) + COLON_SEPARATOR + e.getValue() ) + .collect( Collectors.joining( COMMA_SEPARATOR, "{", "}" ) ); } - @Nonnull static String joinWithSpace(@Nonnull List strings) { - return strings.stream().filter(OutputFormatter::isNotBlank).collect(Collectors.joining(SPACE)); + @Nonnull + static String joinWithSpace( @Nonnull List strings ) + { + return strings.stream().filter( OutputFormatter::isNotBlank ).collect( Collectors.joining( SPACE ) ); } - @Nonnull static String joinNonBlanks(@Nonnull String delim, @Nonnull List strings) { - return strings.stream().filter(OutputFormatter::isNotBlank).collect(Collectors.joining(delim)); + + @Nonnull + static String joinNonBlanks( @Nonnull String delim, @Nonnull List strings ) + { + return strings.stream().filter( OutputFormatter::isNotBlank ).collect( Collectors.joining( delim ) ); } - static boolean isNotBlank(String string) { + static boolean isNotBlank( String string ) + { return string != null && !string.trim().isEmpty(); } - @Nonnull static String repeat(char c, int times) { + @Nonnull + static String repeat( char c, int times ) + { char[] chars = new char[times]; - Arrays.fill(chars, c); - return String.valueOf(chars); + Arrays.fill( chars, c ); + return String.valueOf( chars ); } - @Nonnull static String repeat(@Nonnull String c, int times) { - StringBuilder sb = new StringBuilder(times*c.length()); - for (int i=0;i width) { - return str.substring(0, width); - } else if (actualSize < width) { - return str + repeat( c, width - actualSize); - } else { + if ( actualSize > width ) + { + return str.substring( 0, width ); + } + else if ( actualSize < width ) + { + return str + repeat( c, width - actualSize ); + } + else + { return str; } } - @Nonnull default String formatPlan(@Nonnull ResultSummary summary) { - return ""; - } - @Nonnull default String formatInfo(@Nonnull ResultSummary summary) { - return ""; - } - @Nonnull default String formatFooter(@Nonnull BoltResult result, int numberOfRows) { - return ""; - } - - Set capabilities(); - - List INFO_SUMMARY = asList("Version", "Planner", "Runtime"); - @Nonnull - static Map info(@Nonnull ResultSummary summary) { + static Map info( @Nonnull ResultSummary summary ) + { Map result = new LinkedHashMap<>(); - if (!summary.hasPlan()) return result; + if ( !summary.hasPlan() ) + { + return result; + } Plan plan = summary.plan(); - result.put("Plan", Values.value(summary.hasProfile() ? "PROFILE" : "EXPLAIN")); - result.put("Statement", Values.value(summary.queryType().name())); + result.put( "Plan", Values.value( summary.hasProfile() ? "PROFILE" : "EXPLAIN" ) ); + result.put( "Statement", Values.value( summary.queryType().name() ) ); Map arguments = plan.arguments(); - Value emptyString = Values.value(""); - Value questionMark = Values.value("?"); + Value emptyString = Values.value( "" ); + Value questionMark = Values.value( "?" ); - for (String key : INFO_SUMMARY) { - Value value = arguments.getOrDefault(key, arguments.getOrDefault(key.toLowerCase(), emptyString)); - result.put(key, value); + for ( String key : INFO_SUMMARY ) + { + Value value = arguments.getOrDefault( key, arguments.getOrDefault( key.toLowerCase(), emptyString ) ); + result.put( key, value ); + } + result.put( "Time", Values.value( summary.resultAvailableAfter( MILLISECONDS ) + summary.resultConsumedAfter( MILLISECONDS ) ) ); + if ( summary.hasProfile() ) + { + result.put( "DbHits", Values.value( collectHits( summary.profile() ) ) ); + } + if ( summary.hasProfile() ) + { + result.put( "Rows", Values.value( summary.profile().records() ) ); + } + if ( summary.hasProfile() ) + { + result.put( "Memory (Bytes)", arguments.getOrDefault( "GlobalMemory", questionMark ) ); } - result.put("Time", Values.value(summary.resultAvailableAfter(MILLISECONDS)+summary.resultConsumedAfter(MILLISECONDS))); - if ( summary.hasProfile() ) result.put( "DbHits", Values.value( collectHits( summary.profile() ) ) ); - if (summary.hasProfile()) result.put("Rows", Values.value( summary.profile().records() )); - if (summary.hasProfile()) result.put("Memory (Bytes)", arguments.getOrDefault("GlobalMemory", questionMark)); return result; } - static long collectHits(@Nonnull ProfiledPlan operator ) { + static long collectHits( @Nonnull ProfiledPlan operator ) + { long hits = operator.dbHits(); - hits = operator.children().stream().map( OutputFormatter::collectHits ).reduce(hits, Long::sum); + hits = operator.children().stream().map( OutputFormatter::collectHits ).reduce( hits, Long::sum ); return hits; } + int formatAndCount( @Nonnull BoltResult result, @Nonnull LinePrinter linePrinter ); + + @Nonnull + default String formatValue( final Value value ) + { + if ( value == null ) + { + return ""; + } + TypeRepresentation type = (TypeRepresentation) value.type(); + switch ( type.constructor() ) + { + case LIST: + return listAsString( value.asList( this::formatValue ) ); + case MAP: + return mapAsString( value.asMap( this::formatValue ) ); + case NODE: + return nodeAsString( value.asNode() ); + case RELATIONSHIP: + return relationshipAsString( value.asRelationship() ); + case PATH: + return pathAsString( value.asPath() ); + case POINT: + return pointAsString( value.asPoint() ); + case ANY: + case BOOLEAN: + case BYTES: + case STRING: + case NUMBER: + case INTEGER: + case FLOAT: + case DATE: + case TIME: + case DATE_TIME: + case LOCAL_TIME: + case LOCAL_DATE_TIME: + case DURATION: + case NULL: + default: + return value.toString(); + } + } + + @Nonnull + default String pointAsString( Point point ) + { + StringBuilder stringBuilder = new StringBuilder( "point({" ); + stringBuilder.append( "srid:" ).append( point.srid() ).append( "," ); + stringBuilder.append( " x:" ).append( point.x() ).append( "," ); + stringBuilder.append( " y:" ).append( point.y() ); + double z = point.z(); + if ( !Double.isNaN( z ) ) + { + stringBuilder.append( ", z:" ).append( z ); + } + stringBuilder.append( "})" ); + return stringBuilder.toString(); + } + + @Nonnull + default String pathAsString( @Nonnull Path path ) + { + List list = new ArrayList<>( path.length() ); + Node lastTraversed = path.start(); + if ( lastTraversed != null ) + { + list.add( nodeAsString( lastTraversed ) ); + + for ( Path.Segment segment : path ) + { + Relationship relationship = segment.relationship(); + if ( relationship.startNodeId() == lastTraversed.id() ) + { + list.add( "-" + relationshipAsString( relationship ) + "->" ); + } + else + { + list.add( "<-" + relationshipAsString( relationship ) + "-" ); + } + list.add( nodeAsString( segment.end() ) ); + lastTraversed = segment.end(); + } + } + + return String.join( "", list ); + } + + @Nonnull + default String relationshipAsString( @Nonnull Relationship relationship ) + { + List relationshipAsString = new ArrayList<>(); + relationshipAsString.add( COLON + escape( relationship.type() ) ); + relationshipAsString.add( mapAsStringWithEmpty( relationship.asMap( this::formatValue ) ) ); + + return "[" + joinWithSpace( relationshipAsString ) + "]"; + } + + @Nonnull + default String nodeAsString( @Nonnull final Node node ) + { + List nodeAsString = new ArrayList<>(); + nodeAsString.add( collectNodeLabels( node ) ); + nodeAsString.add( mapAsStringWithEmpty( node.asMap( this::formatValue ) ) ); + + return "(" + joinWithSpace( nodeAsString ) + ")"; + } + + @Nonnull + default String formatPlan( @Nonnull ResultSummary summary ) + { + return ""; + } + + @Nonnull + default String formatInfo( @Nonnull ResultSummary summary ) + { + return ""; + } + + @Nonnull + default String formatFooter( @Nonnull BoltResult result, int numberOfRows ) + { + return ""; + } + + Set capabilities(); + + enum Capabilities + { INFO, PLAN, RESULT, FOOTER, STATISTICS } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/prettyprint/PrettyConfig.java b/cypher-shell/src/main/java/org/neo4j/shell/prettyprint/PrettyConfig.java index b65f1ad8..15801d58 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/prettyprint/PrettyConfig.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/prettyprint/PrettyConfig.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.prettyprint; import org.neo4j.shell.cli.CliArgs; @@ -6,28 +25,33 @@ /** * Configuration of pretty printer. */ -public class PrettyConfig { +public class PrettyConfig +{ - public static final PrettyConfig DEFAULT = new PrettyConfig(new CliArgs()); + public static final PrettyConfig DEFAULT = new PrettyConfig( new CliArgs() ); public final Format format; public final boolean wrap; public final int numSampleRows; - public PrettyConfig(CliArgs cliArgs) { - this(selectFormat(cliArgs), cliArgs.getWrap(), cliArgs.getNumSampleRows()); - } - - private static Format selectFormat(CliArgs cliArgs) { - if (cliArgs.isStringShell() && Format.AUTO.equals(cliArgs.getFormat())) { - return Format.PLAIN; - } - return cliArgs.getFormat(); + public PrettyConfig( CliArgs cliArgs ) + { + this( selectFormat( cliArgs ), cliArgs.getWrap(), cliArgs.getNumSampleRows() ); } - public PrettyConfig(Format format, boolean wrap, int numSampleRows) { + public PrettyConfig( Format format, boolean wrap, int numSampleRows ) + { this.format = format; this.wrap = wrap; this.numSampleRows = numSampleRows; } + + private static Format selectFormat( CliArgs cliArgs ) + { + if ( cliArgs.isStringShell() && Format.AUTO.equals( cliArgs.getFormat() ) ) + { + return Format.PLAIN; + } + return cliArgs.getFormat(); + } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/prettyprint/PrettyPrinter.java b/cypher-shell/src/main/java/org/neo4j/shell/prettyprint/PrettyPrinter.java index 794e173e..6ab1e8d1 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/prettyprint/PrettyPrinter.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/prettyprint/PrettyPrinter.java @@ -1,56 +1,108 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.prettyprint; +import java.util.Set; +import javax.annotation.Nonnull; + import org.neo4j.shell.cli.Format; import org.neo4j.shell.state.BoltResult; -import javax.annotation.Nonnull; -import java.util.Set; - -import static org.neo4j.shell.prettyprint.OutputFormatter.Capabilities.*; +import static org.neo4j.shell.prettyprint.OutputFormatter.Capabilities.FOOTER; +import static org.neo4j.shell.prettyprint.OutputFormatter.Capabilities.INFO; +import static org.neo4j.shell.prettyprint.OutputFormatter.Capabilities.PLAN; +import static org.neo4j.shell.prettyprint.OutputFormatter.Capabilities.RESULT; +import static org.neo4j.shell.prettyprint.OutputFormatter.Capabilities.STATISTICS; /** * Print the result from neo4j in a intelligible fashion. */ -public class PrettyPrinter { +public class PrettyPrinter +{ private final StatisticsCollector statisticsCollector; private final OutputFormatter outputFormatter; - public PrettyPrinter(@Nonnull PrettyConfig prettyConfig) { - this.statisticsCollector = new StatisticsCollector(prettyConfig.format); - this.outputFormatter = selectFormatter(prettyConfig); + public PrettyPrinter( @Nonnull PrettyConfig prettyConfig ) + { + this.statisticsCollector = new StatisticsCollector( prettyConfig.format ); + this.outputFormatter = selectFormatter( prettyConfig ); } - public void format(@Nonnull final BoltResult result, LinePrinter linePrinter) { + public void format( @Nonnull final BoltResult result, LinePrinter linePrinter ) + { Set capabilities = outputFormatter.capabilities(); int numberOfRows = 0; - if (capabilities.contains(RESULT)) { - numberOfRows = outputFormatter.formatAndCount(result, linePrinter); + if ( capabilities.contains( RESULT ) ) + { + numberOfRows = outputFormatter.formatAndCount( result, linePrinter ); } - if (capabilities.contains(INFO)) printIfNotEmpty(outputFormatter.formatInfo(result.getSummary()), linePrinter); - if (capabilities.contains(PLAN)) printIfNotEmpty(outputFormatter.formatPlan(result.getSummary()), linePrinter); - if (capabilities.contains(FOOTER)) printIfNotEmpty(outputFormatter.formatFooter(result, numberOfRows), linePrinter); - if (capabilities.contains(STATISTICS)) printIfNotEmpty(statisticsCollector.collect(result.getSummary()), linePrinter); + if ( capabilities.contains( INFO ) ) + { + printIfNotEmpty( outputFormatter.formatInfo( result.getSummary() ), linePrinter ); + } + if ( capabilities.contains( PLAN ) ) + { + printIfNotEmpty( outputFormatter.formatPlan( result.getSummary() ), linePrinter ); + } + if ( capabilities.contains( FOOTER ) ) + { + printIfNotEmpty( outputFormatter.formatFooter( result, numberOfRows ), linePrinter ); + } + if ( capabilities.contains( STATISTICS ) ) + { + printIfNotEmpty( statisticsCollector.collect( result.getSummary() ), linePrinter ); + } } // Helper for testing - String format(@Nonnull final BoltResult result) { + String format( @Nonnull final BoltResult result ) + { StringBuilder sb = new StringBuilder(); - format(result, line -> {if (line!=null && !line.trim().isEmpty()) sb.append(line).append(OutputFormatter.NEWLINE);}); + format( result, line -> + { + if ( line != null && !line.trim().isEmpty() ) + { + sb.append( line ).append( OutputFormatter.NEWLINE ); + } + } ); return sb.toString(); } - private void printIfNotEmpty( String s, LinePrinter linePrinter ) { - if (!s.isEmpty()) { + private void printIfNotEmpty( String s, LinePrinter linePrinter ) + { + if ( !s.isEmpty() ) + { linePrinter.printOut( s ); } } - private OutputFormatter selectFormatter(PrettyConfig prettyConfig) { - if (prettyConfig.format == Format.VERBOSE) { - return new TableOutputFormatter(prettyConfig.wrap, prettyConfig.numSampleRows); - } else { + private OutputFormatter selectFormatter( PrettyConfig prettyConfig ) + { + if ( prettyConfig.format == Format.VERBOSE ) + { + return new TableOutputFormatter( prettyConfig.wrap, prettyConfig.numSampleRows ); + } + else + { return new SimpleOutputFormatter(); } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/prettyprint/SimpleOutputFormatter.java b/cypher-shell/src/main/java/org/neo4j/shell/prettyprint/SimpleOutputFormatter.java index f16791a3..9ddaef3a 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/prettyprint/SimpleOutputFormatter.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/prettyprint/SimpleOutputFormatter.java @@ -1,32 +1,57 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.prettyprint; -import org.neo4j.driver.Record; -import org.neo4j.driver.Value; -import org.neo4j.driver.summary.ResultSummary; -import org.neo4j.shell.state.BoltResult; - -import javax.annotation.Nonnull; import java.util.EnumSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import javax.annotation.Nonnull; + +import org.neo4j.driver.Record; +import org.neo4j.driver.Value; +import org.neo4j.driver.summary.ResultSummary; +import org.neo4j.shell.state.BoltResult; -import static org.neo4j.shell.prettyprint.OutputFormatter.Capabilities.*; +import static org.neo4j.shell.prettyprint.OutputFormatter.Capabilities.INFO; +import static org.neo4j.shell.prettyprint.OutputFormatter.Capabilities.RESULT; +import static org.neo4j.shell.prettyprint.OutputFormatter.Capabilities.STATISTICS; -public class SimpleOutputFormatter implements OutputFormatter { +public class SimpleOutputFormatter implements OutputFormatter +{ @Override - public int formatAndCount(@Nonnull BoltResult result, @Nonnull LinePrinter output) { + public int formatAndCount( @Nonnull BoltResult result, @Nonnull LinePrinter output ) + { Iterator records = result.iterate(); int numberOfRows = 0; - if (records.hasNext()) { + if ( records.hasNext() ) + { Record firstRow = records.next(); - output.printOut(String.join(COMMA_SEPARATOR, firstRow.keys())); - output.printOut(formatRecord(firstRow)); + output.printOut( String.join( COMMA_SEPARATOR, firstRow.keys() ) ); + output.printOut( formatRecord( firstRow ) ); numberOfRows++; - while (records.hasNext()) { - output.printOut(formatRecord(records.next())); + while ( records.hasNext() ) + { + output.printOut( formatRecord( records.next() ) ); numberOfRows++; } } @@ -34,23 +59,27 @@ public int formatAndCount(@Nonnull BoltResult result, @Nonnull LinePrinter outpu } @Nonnull - private String formatRecord(@Nonnull final Record record) { - return record.values().stream().map(this::formatValue).collect(Collectors.joining(COMMA_SEPARATOR)); + private String formatRecord( @Nonnull final Record record ) + { + return record.values().stream().map( this::formatValue ).collect( Collectors.joining( COMMA_SEPARATOR ) ); } @Nonnull @Override - public String formatInfo(@Nonnull ResultSummary summary) { - if (!summary.hasPlan()) { + public String formatInfo( @Nonnull ResultSummary summary ) + { + if ( !summary.hasPlan() ) + { return ""; } - Map info = OutputFormatter.info(summary); + Map info = OutputFormatter.info( summary ); return info.entrySet().stream() - .map( e -> String.format("%s: %s",e.getKey(),e.getValue())).collect(Collectors.joining(NEWLINE)); + .map( e -> String.format( "%s: %s", e.getKey(), e.getValue() ) ).collect( Collectors.joining( NEWLINE ) ); } @Override - public Set capabilities() { - return EnumSet.of(INFO, STATISTICS, RESULT); + public Set capabilities() + { + return EnumSet.of( INFO, STATISTICS, RESULT ); } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/prettyprint/StatisticsCollector.java b/cypher-shell/src/main/java/org/neo4j/shell/prettyprint/StatisticsCollector.java index 3f056eae..39bdcdc0 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/prettyprint/StatisticsCollector.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/prettyprint/StatisticsCollector.java @@ -1,66 +1,106 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.prettyprint; -import org.neo4j.driver.summary.ResultSummary; -import org.neo4j.driver.summary.SummaryCounters; -import org.neo4j.shell.cli.Format; - -import javax.annotation.Nonnull; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; +import javax.annotation.Nonnull; -public class StatisticsCollector { +import org.neo4j.driver.summary.ResultSummary; +import org.neo4j.driver.summary.SummaryCounters; +import org.neo4j.shell.cli.Format; + +public class StatisticsCollector +{ private Format format; - public StatisticsCollector(@Nonnull Format format) { + public StatisticsCollector( @Nonnull Format format ) + { this.format = format; } - public String collect(@Nonnull ResultSummary summary) { - if (Format.VERBOSE == format) { - return collectStatistics(summary); - } else { + public String collect( @Nonnull ResultSummary summary ) + { + if ( Format.VERBOSE == format ) + { + return collectStatistics( summary ); + } + else + { return ""; } } - private String collectStatistics(@Nonnull ResultSummary summary) { + private String collectStatistics( @Nonnull ResultSummary summary ) + { List statistics = new ArrayList<>(); SummaryCounters counters = summary.counters(); - if (counters == null) return ""; - if (counters.nodesCreated() != 0) { - statistics.add(String.format("Added %d nodes", counters.nodesCreated())); + if ( counters == null ) + { + return ""; + } + if ( counters.nodesCreated() != 0 ) + { + statistics.add( String.format( "Added %d nodes", counters.nodesCreated() ) ); } - if (counters.nodesDeleted() != 0) { - statistics.add(String.format("Deleted %d nodes", counters.nodesDeleted())); + if ( counters.nodesDeleted() != 0 ) + { + statistics.add( String.format( "Deleted %d nodes", counters.nodesDeleted() ) ); } - if (counters.relationshipsCreated() != 0) { - statistics.add(String.format("Created %d relationships", counters.relationshipsCreated())); + if ( counters.relationshipsCreated() != 0 ) + { + statistics.add( String.format( "Created %d relationships", counters.relationshipsCreated() ) ); } - if (counters.relationshipsDeleted() != 0) { - statistics.add(String.format("Deleted %d relationships", counters.relationshipsDeleted())); + if ( counters.relationshipsDeleted() != 0 ) + { + statistics.add( String.format( "Deleted %d relationships", counters.relationshipsDeleted() ) ); } - if (counters.propertiesSet() != 0) { - statistics.add(String.format("Set %d properties", counters.propertiesSet())); + if ( counters.propertiesSet() != 0 ) + { + statistics.add( String.format( "Set %d properties", counters.propertiesSet() ) ); } - if (counters.labelsAdded() != 0) { - statistics.add(String.format("Added %d labels", counters.labelsAdded())); + if ( counters.labelsAdded() != 0 ) + { + statistics.add( String.format( "Added %d labels", counters.labelsAdded() ) ); } - if (counters.labelsRemoved() != 0) { - statistics.add(String.format("Removed %d labels", counters.labelsRemoved())); + if ( counters.labelsRemoved() != 0 ) + { + statistics.add( String.format( "Removed %d labels", counters.labelsRemoved() ) ); } - if (counters.indexesAdded() != 0) { - statistics.add(String.format("Added %d indexes", counters.indexesAdded())); + if ( counters.indexesAdded() != 0 ) + { + statistics.add( String.format( "Added %d indexes", counters.indexesAdded() ) ); } - if (counters.indexesRemoved() != 0) { - statistics.add(String.format("Removed %d indexes", counters.indexesRemoved())); + if ( counters.indexesRemoved() != 0 ) + { + statistics.add( String.format( "Removed %d indexes", counters.indexesRemoved() ) ); } - if (counters.constraintsAdded() != 0) { - statistics.add(String.format("Added %d constraints", counters.constraintsAdded())); + if ( counters.constraintsAdded() != 0 ) + { + statistics.add( String.format( "Added %d constraints", counters.constraintsAdded() ) ); } - if (counters.constraintsRemoved() != 0) { - statistics.add(String.format("Removed %d constraints", counters.constraintsRemoved())); + if ( counters.constraintsRemoved() != 0 ) + { + statistics.add( String.format( "Removed %d constraints", counters.constraintsRemoved() ) ); } - return statistics.stream().collect(Collectors.joining(", ")); + return statistics.stream().collect( Collectors.joining( ", " ) ); } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/prettyprint/TableOutputFormatter.java b/cypher-shell/src/main/java/org/neo4j/shell/prettyprint/TableOutputFormatter.java index 3e0eb579..84661e4c 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/prettyprint/TableOutputFormatter.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/prettyprint/TableOutputFormatter.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.prettyprint; import java.util.ArrayList; @@ -10,95 +29,111 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; -import org.neo4j.driver.internal.InternalRecord; -import org.neo4j.driver.internal.value.NumberValueAdapter; import org.neo4j.driver.Record; import org.neo4j.driver.Value; +import org.neo4j.driver.internal.InternalRecord; +import org.neo4j.driver.internal.value.NumberValueAdapter; import org.neo4j.driver.summary.ResultSummary; import org.neo4j.shell.state.BoltResult; import static java.util.Arrays.asList; import static java.util.concurrent.TimeUnit.MILLISECONDS; -public class TableOutputFormatter implements OutputFormatter { +public class TableOutputFormatter implements OutputFormatter +{ private final boolean wrap; private final int numSampleRows; - public TableOutputFormatter(boolean wrap, int numSampleRows) { + public TableOutputFormatter( boolean wrap, int numSampleRows ) + { this.wrap = wrap; this.numSampleRows = numSampleRows; } @Override - public int formatAndCount(@Nonnull BoltResult result, @Nonnull LinePrinter output) { - String[] columns = result.getKeys().toArray(new String[0]); - if (columns.length == 0) { + public int formatAndCount( @Nonnull BoltResult result, @Nonnull LinePrinter output ) + { + String[] columns = result.getKeys().toArray( new String[0] ); + if ( columns.length == 0 ) + { return 0; } Iterator records = result.iterate(); - return formatResultAndCountRows(columns, records, output); + return formatResultAndCountRows( columns, records, output ); } - private List take(Iterator records, int count) { - List topRecords = new ArrayList<>(count); - while (records.hasNext() && topRecords.size() < count) { - topRecords.add(records.next()); + private List take( Iterator records, int count ) + { + List topRecords = new ArrayList<>( count ); + while ( records.hasNext() && topRecords.size() < count ) + { + topRecords.add( records.next() ); } return topRecords; } - private int formatResultAndCountRows(String[] columns, - Iterator records, - LinePrinter output) { + private int formatResultAndCountRows( String[] columns, + Iterator records, + LinePrinter output ) + { - List topRecords = take(records, numSampleRows); - int[] columnSizes = calculateColumnSizes(columns, topRecords, records.hasNext()); + List topRecords = take( records, numSampleRows ); + int[] columnSizes = calculateColumnSizes( columns, topRecords, records.hasNext() ); int totalWidth = 1; - for (int columnSize : columnSizes) { + for ( int columnSize : columnSizes ) + { totalWidth += columnSize + 3; } - StringBuilder builder = new StringBuilder(totalWidth); - String headerLine = formatRow(builder, columnSizes, columns, new boolean[columnSizes.length]); + StringBuilder builder = new StringBuilder( totalWidth ); + String headerLine = formatRow( builder, columnSizes, columns, new boolean[columnSizes.length] ); int lineWidth = totalWidth - 2; - String dashes = "+" + OutputFormatter.repeat('-', lineWidth) + "+"; + String dashes = "+" + OutputFormatter.repeat( '-', lineWidth ) + "+"; - output.printOut(dashes); - output.printOut(headerLine); - output.printOut(dashes); + output.printOut( dashes ); + output.printOut( headerLine ); + output.printOut( dashes ); int numberOfRows = 0; - for (Record record : topRecords) { - output.printOut(formatRecord(builder, columnSizes, record)); + for ( Record record : topRecords ) + { + output.printOut( formatRecord( builder, columnSizes, record ) ); numberOfRows++; } - while (records.hasNext()) { - output.printOut(formatRecord(builder, columnSizes, records.next())); + while ( records.hasNext() ) + { + output.printOut( formatRecord( builder, columnSizes, records.next() ) ); numberOfRows++; } - output.printOut(String.format("%s%n", dashes)); + output.printOut( String.format( "%s%n", dashes ) ); return numberOfRows; } /** * Calculate the size of the columns for table formatting - * @param columns the column names - * @param data (sample) data + * + * @param columns the column names + * @param data (sample) data * @param moreDataAfterSamples if there is more data that should be written into the table after `data` * @return the column sizes */ - private int[] calculateColumnSizes(@Nonnull String[] columns, @Nonnull List data, boolean moreDataAfterSamples) { + private int[] calculateColumnSizes( @Nonnull String[] columns, @Nonnull List data, boolean moreDataAfterSamples ) + { int[] columnSizes = new int[columns.length]; - for (int i = 0; i < columns.length; i++) { + for ( int i = 0; i < columns.length; i++ ) + { columnSizes[i] = columns[i].length(); } - for (Record record : data) { - for (int i = 0; i < columns.length; i++) { - int len = columnLengthForValue(record.get(i), moreDataAfterSamples); - if (columnSizes[i] < len) { + for ( Record record : data ) + { + for ( int i = 0; i < columns.length; i++ ) + { + int len = columnLengthForValue( record.get( i ), moreDataAfterSamples ); + if ( columnSizes[i] < len ) + { columnSizes[i] = len; } } @@ -109,27 +144,34 @@ private int[] calculateColumnSizes(@Nonnull String[] columns, @Nonnull List length) { - if (wrap) { - sb.append(txt, 0, length); - row[i] = txt.substring(length); + if ( txt != null ) + { + if ( txt.length() > length ) + { + if ( wrap ) + { + sb.append( txt, 0, length ); + row[i] = txt.substring( length ); continuation[i] = true; remainder = true; - } else { - sb.append(txt, 0, length - 1); - sb.append("…"); } - } else { + else + { + sb.append( txt, 0, length - 1 ); + sb.append( "…" ); + } + } + else + { row[i] = null; - sb.append(OutputFormatter.rightPad(txt, length)); + sb.append( OutputFormatter.rightPad( txt, length ) ); } - } else { - sb.append(OutputFormatter.repeat(' ', length)); } - if (i == row.length -1 || !continuation[i+1]) { - sb.append(" |"); - } else { - sb.append(" \\"); + else + { + sb.append( OutputFormatter.repeat( ' ', length ) ); + } + if ( i == row.length - 1 || !continuation[i + 1] ) + { + sb.append( " |" ); + } + else + { + sb.append( " \\" ); } } - if (wrap && remainder) { - sb.append(OutputFormatter.NEWLINE); - formatRow(sb, columnSizes, row, continuation); + if ( wrap && remainder ) + { + sb.append( OutputFormatter.NEWLINE ); + formatRow( sb, columnSizes, row, continuation ); } return sb.toString(); } @Override @Nonnull - public String formatFooter(@Nonnull BoltResult result, int numberOfRows) { + public String formatFooter( @Nonnull BoltResult result, int numberOfRows ) + { ResultSummary summary = result.getSummary(); - return String.format("%d row%s available after %d ms, " + - "consumed after another %d ms", numberOfRows, numberOfRows != 1 ? "s" : "", - summary.resultAvailableAfter(MILLISECONDS), - summary.resultConsumedAfter(MILLISECONDS)); + return String.format( "%d row%s available after %d ms, " + + "consumed after another %d ms", numberOfRows, numberOfRows != 1 ? "s" : "", + summary.resultAvailableAfter( MILLISECONDS ), + summary.resultConsumedAfter( MILLISECONDS ) ); } @Override @Nonnull - public String formatInfo(@Nonnull ResultSummary summary) { - Map info = OutputFormatter.info(summary); - if (info.isEmpty()) { + public String formatInfo( @Nonnull ResultSummary summary ) + { + Map info = OutputFormatter.info( summary ); + if ( info.isEmpty() ) + { return ""; } - String[] columns = info.keySet().toArray(new String[0]); + String[] columns = info.keySet().toArray( new String[0] ); StringBuilder sb = new StringBuilder(); - Record record = new InternalRecord(asList(columns), info.values().toArray(new Value[0])); - formatResultAndCountRows(columns, Collections.singletonList(record).iterator(), line -> sb.append( line).append( OutputFormatter.NEWLINE) ); + Record record = new InternalRecord( asList( columns ), info.values().toArray( new Value[0] ) ); + formatResultAndCountRows( columns, Collections.singletonList( record ).iterator(), line -> sb.append( line ).append( OutputFormatter.NEWLINE ) ); return sb.toString(); } @Override @Nonnull - public String formatPlan(@Nullable ResultSummary summary) { - if (summary == null || !summary.hasPlan()) { + public String formatPlan( @Nullable ResultSummary summary ) + { + if ( summary == null || !summary.hasPlan() ) + { return ""; } - return new TablePlanFormatter().formatPlan(summary.plan()); + return new TablePlanFormatter().formatPlan( summary.plan() ); } @Override - public Set capabilities() { - return EnumSet.allOf(Capabilities.class); + public Set capabilities() + { + return EnumSet.allOf( Capabilities.class ); } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/prettyprint/TablePlanFormatter.java b/cypher-shell/src/main/java/org/neo4j/shell/prettyprint/TablePlanFormatter.java index a1074378..ab1182f2 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/prettyprint/TablePlanFormatter.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/prettyprint/TablePlanFormatter.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.prettyprint; import java.util.ArrayList; @@ -26,10 +45,11 @@ import static org.neo4j.shell.prettyprint.OutputFormatter.NEWLINE; import static org.neo4j.shell.prettyprint.OutputFormatter.repeat; -public class TablePlanFormatter { +public class TablePlanFormatter +{ private static final String UNNAMED_PATTERN_STRING = " (UNNAMED|FRESHID|AGGREGATION|NODE|REL)(\\d+)"; - private static final Pattern UNNAMED_PATTERN = Pattern.compile(UNNAMED_PATTERN_STRING); + private static final Pattern UNNAMED_PATTERN = Pattern.compile( UNNAMED_PATTERN_STRING ); private static final String OPERATOR = "Operator"; private static final String ESTIMATED_ROWS = "Estimated Rows"; private static final String ROWS = "Rows"; @@ -42,324 +62,404 @@ public class TablePlanFormatter { private static final String OTHER = "Other"; public static final String DETAILS = "Details"; private static final String SEPARATOR = ", "; - private static final Pattern DEDUP_PATTERN = Pattern.compile("\\s*(\\S+)@\\d+"); + private static final Pattern DEDUP_PATTERN = Pattern.compile( "\\s*(\\S+)@\\d+" ); public static final int MAX_DETAILS_COLUMN_WIDTH = 100; - private static final List HEADERS = asList(OPERATOR, DETAILS, ESTIMATED_ROWS, ROWS, HITS, PAGE_CACHE, TIME, MEMORY, IDENTIFIERS, ORDER, OTHER); + private static final List HEADERS = asList( OPERATOR, DETAILS, ESTIMATED_ROWS, ROWS, HITS, PAGE_CACHE, TIME, MEMORY, IDENTIFIERS, ORDER, OTHER ); private static final Set IGNORED_ARGUMENTS = new LinkedHashSet<>( asList( "Rows", "DbHits", "EstimatedRows", "planner", "planner-impl", "planner-version", "version", "runtime", "runtime-impl", "runtime-version", "time", "source-code", "PageCacheMisses", "PageCacheHits", "PageCacheHitRatio", "Order", "Memory", "GlobalMemory", "Details" ) ); - public static final Value ZERO_VALUE = Values.value(0); + public static final Value ZERO_VALUE = Values.value( 0 ); - private int width(@Nonnull String header, @Nonnull Map columns) { - return 2 + Math.max(header.length(), columns.get(header)); + private int width( @Nonnull String header, @Nonnull Map columns ) + { + return 2 + Math.max( header.length(), columns.get( header ) ); } - private static void pad(int width, char chr, @Nonnull StringBuilder result) { - result.append(OutputFormatter.repeat(chr, width)); + private static void pad( int width, char chr, @Nonnull StringBuilder result ) + { + result.append( OutputFormatter.repeat( chr, width ) ); } - - private void divider(@Nonnull List headers, @Nullable TableRow tableRow /*= null*/, @Nonnull StringBuilder result, @Nonnull Map columns) { - for (String header : headers) { - if (tableRow != null && header.equals(OPERATOR) && tableRow.connection.isPresent()) { - result.append("|"); + private void divider( @Nonnull List headers, @Nullable TableRow tableRow /*= null*/, @Nonnull StringBuilder result, + @Nonnull Map columns ) + { + for ( String header : headers ) + { + if ( tableRow != null && header.equals( OPERATOR ) && tableRow.connection.isPresent() ) + { + result.append( "|" ); String connection = tableRow.connection.get(); - result.append(" ").append(connection); - pad(width(header, columns) - connection.length() - 1, ' ', result); - } else { - result.append("+"); - pad(width(header, columns), '-', result); + result.append( " " ).append( connection ); + pad( width( header, columns ) - connection.length() - 1, ' ', result ); + } + else + { + result.append( "+" ); + pad( width( header, columns ), '-', result ); } } - result.append("+").append(NEWLINE); + result.append( "+" ).append( NEWLINE ); } @Nonnull - String formatPlan(@Nonnull Plan plan) { + String formatPlan( @Nonnull Plan plan ) + { Map columns = new HashMap<>(); - List tableRows = accumulate(plan, new Root(), columns); + List tableRows = accumulate( plan, new Root(), columns ); // Remove Identifiers column if we have a Details column - List headers = HEADERS.stream().filter(header -> columns.containsKey(header) && !(header.equals(IDENTIFIERS) && columns.containsKey(DETAILS))).collect(Collectors.toList()); + List headers = + HEADERS.stream().filter( header -> columns.containsKey( header ) && !(header.equals( IDENTIFIERS ) && columns.containsKey( DETAILS )) ) + .collect( Collectors.toList() ); - StringBuilder result = new StringBuilder((2 + NEWLINE.length() + headers.stream().mapToInt(h -> width(h, columns)).sum()) * (tableRows.size() * 2 + 3)); + StringBuilder result = + new StringBuilder( (2 + NEWLINE.length() + headers.stream().mapToInt( h -> width( h, columns ) ).sum()) * (tableRows.size() * 2 + 3) ); List allTableRows = new ArrayList<>(); - Map headerMap = headers.stream().map(header -> Pair.of(header, new LeftJustifiedCell(header))).collect(toMap(p -> p._1, p -> p._2)); - allTableRows.add(new TableRow(OPERATOR, headerMap, Optional.empty())); + Map headerMap = + headers.stream().map( header -> Pair.of( header, new LeftJustifiedCell( header ) ) ).collect( toMap( p -> p._1, p -> p._2 ) ); + allTableRows.add( new TableRow( OPERATOR, headerMap, Optional.empty() ) ); allTableRows.addAll( tableRows ); - for (int rowIndex = 0; rowIndex < allTableRows.size(); rowIndex++) { - TableRow tableRow = allTableRows.get( rowIndex); - divider(headers, tableRow, result, columns); - for (int rowLineIndex = 0; rowLineIndex < tableRow.height; rowLineIndex++) { - for (String header : headers) { - Cell cell = tableRow.get(header); + for ( int rowIndex = 0; rowIndex < allTableRows.size(); rowIndex++ ) + { + TableRow tableRow = allTableRows.get( rowIndex ); + divider( headers, tableRow, result, columns ); + for ( int rowLineIndex = 0; rowLineIndex < tableRow.height; rowLineIndex++ ) + { + for ( String header : headers ) + { + Cell cell = tableRow.get( header ); String defaultText = ""; - if (header.equals(OPERATOR) && rowIndex + 1 < allTableRows.size()) { - defaultText = allTableRows.get(rowIndex + 1).connection.orElse("").replace('\\', ' '); + if ( header.equals( OPERATOR ) && rowIndex + 1 < allTableRows.size() ) + { + defaultText = allTableRows.get( rowIndex + 1 ).connection.orElse( "" ).replace( '\\', ' ' ); } result.append( "| " ); - int columnWidth = width(header, columns); - cell.writePaddedLine(rowLineIndex, defaultText, columnWidth, result); + int columnWidth = width( header, columns ); + cell.writePaddedLine( rowLineIndex, defaultText, columnWidth, result ); result.append( " " ); } - result.append("|").append(NEWLINE); + result.append( "|" ).append( NEWLINE ); } } - divider(headers, null, result, columns); + divider( headers, null, result, columns ); return result.toString(); } @Nonnull - private String serialize(@Nonnull String key, @Nonnull Value v) { - switch (key) { - case "ColumnsLeft": - return removeGeneratedNames(v.asString()); - case "LegacyExpression": - return removeGeneratedNames(v.asString()); - case "Expression": - return removeGeneratedNames(v.asString()); - case "UpdateActionName": - return v.asString(); - case "LegacyIndex": - return v.toString(); - case "version": - return v.toString(); - case "planner": - return v.toString(); - case "planner-impl": - return v.toString(); - case "runtime": - return v.toString(); - case "runtime-impl": - return v.toString(); - case "MergePattern": - return "MergePattern(" + v.toString() + ")"; - case "DbHits": - return v.asNumber().toString(); - case "Rows": - return v.asNumber().toString(); - case "Time": - return v.asNumber().toString(); - case "EstimatedRows": - return v.asNumber().toString(); - case "LabelName": - return v.asString(); - case "KeyNames": - return removeGeneratedNames(v.asString()); - case "KeyExpressions": - return String.join(SEPARATOR, v.asList(Value::asString)); - - case "ExpandExpression": - return removeGeneratedNames(v.asString()); - case "Index": - return v.asString(); - case "PrefixIndex": - return v.asString(); - case "InequalityIndex": - return v.asString(); - case "EntityByIdRhs": - return v.asString(); - case "PageCacheMisses": - return v.asNumber().toString(); - case "Details": - return v.asString(); - default: - return v.asObject().toString(); + private String serialize( @Nonnull String key, @Nonnull Value v ) + { + switch ( key ) + { + case "ColumnsLeft": + return removeGeneratedNames( v.asString() ); + case "LegacyExpression": + return removeGeneratedNames( v.asString() ); + case "Expression": + return removeGeneratedNames( v.asString() ); + case "UpdateActionName": + return v.asString(); + case "LegacyIndex": + return v.toString(); + case "version": + return v.toString(); + case "planner": + return v.toString(); + case "planner-impl": + return v.toString(); + case "runtime": + return v.toString(); + case "runtime-impl": + return v.toString(); + case "MergePattern": + return "MergePattern(" + v.toString() + ")"; + case "DbHits": + return v.asNumber().toString(); + case "Rows": + return v.asNumber().toString(); + case "Time": + return v.asNumber().toString(); + case "EstimatedRows": + return v.asNumber().toString(); + case "LabelName": + return v.asString(); + case "KeyNames": + return removeGeneratedNames( v.asString() ); + case "KeyExpressions": + return String.join( SEPARATOR, v.asList( Value::asString ) ); + + case "ExpandExpression": + return removeGeneratedNames( v.asString() ); + case "Index": + return v.asString(); + case "PrefixIndex": + return v.asString(); + case "InequalityIndex": + return v.asString(); + case "EntityByIdRhs": + return v.asString(); + case "PageCacheMisses": + return v.asNumber().toString(); + case "Details": + return v.asString(); + default: + return v.asObject().toString(); } } - @Nonnull private Stream> children(@Nonnull Plan plan, Level level, @Nonnull Map columns) { + @Nonnull + private Stream> children( @Nonnull Plan plan, Level level, @Nonnull Map columns ) + { List c = plan.children(); - switch (c.size()) { - case 0: - return Stream.empty(); - case 1: - return Stream.of(accumulate(c.get(0), level.child(), columns)); - case 2: - return Stream.of(accumulate(c.get(1), level.fork(), columns), accumulate(c.get(0), level.child(), columns)); - } - throw new IllegalStateException("Plan has more than 2 children " + c); + switch ( c.size() ) + { + case 0: + return Stream.empty(); + case 1: + return Stream.of( accumulate( c.get( 0 ), level.child(), columns ) ); + case 2: + return Stream.of( accumulate( c.get( 1 ), level.fork(), columns ), accumulate( c.get( 0 ), level.child(), columns ) ); + default: + throw new IllegalStateException( "Plan has more than 2 children " + c ); + } } - @Nonnull private List accumulate(@Nonnull Plan plan, @Nonnull Level level, @Nonnull Map columns) { + @Nonnull + private List accumulate( @Nonnull Plan plan, @Nonnull Level level, @Nonnull Map columns ) + { String line = level.line() + plan.operatorType(); // wa plan.name - mapping(OPERATOR, new LeftJustifiedCell(line), columns); + mapping( OPERATOR, new LeftJustifiedCell( line ), columns ); return Stream.concat( - Stream.of(new TableRow(line, details(plan, columns), level.connector())), - children(plan, level, columns).flatMap(Collection::stream)) - .collect(Collectors.toList()); + Stream.of( new TableRow( line, details( plan, columns ), level.connector() ) ), + children( plan, level, columns ).flatMap( Collection::stream ) ) + .collect( Collectors.toList() ); } @Nonnull - private Map details(@Nonnull Plan plan, @Nonnull Map columns) { + private Map details( @Nonnull Plan plan, @Nonnull Map columns ) + { Map args = plan.arguments(); - Stream>> formattedPlan = args.entrySet().stream().map(e -> { - Value value = e.getValue(); - switch (e.getKey()) { - case "EstimatedRows": - return mapping(ESTIMATED_ROWS, new RightJustifiedCell(format(value.asDouble())), columns); - case "Rows": - return mapping(ROWS, new RightJustifiedCell(value.asNumber().toString()), columns); - case "DbHits": - return mapping(HITS, new RightJustifiedCell(value.asNumber().toString()), columns); - case "PageCacheHits": - return mapping(PAGE_CACHE, new RightJustifiedCell(String.format("%s/%s", value.asNumber(), args.getOrDefault("PageCacheMisses", ZERO_VALUE).asNumber())), columns); - case "Time": - return mapping(TIME, new RightJustifiedCell(String.format("%.3f", value.asLong() / 1000000.0d)), columns); - case "Order": - return mapping(ORDER, new LeftJustifiedCell(String.format("%s", value.asString())), columns); - case "Details": - return mapping(DETAILS, new LeftJustifiedCell(splitDetails(value.asString())), columns); - case "Memory": - return mapping(MEMORY, new RightJustifiedCell(String.format("%s", value.asNumber().toString())), columns); - default: - return Optional.empty(); - } - }); + Stream>> formattedPlan = args.entrySet().stream() + .map( e -> + { + Value value = e.getValue(); + switch ( e.getKey() ) + { + case "EstimatedRows": + return mapping( ESTIMATED_ROWS, new RightJustifiedCell( + format( value.asDouble() ) ), columns ); + case "Rows": + return mapping( ROWS, new RightJustifiedCell( + value.asNumber().toString() ), columns ); + case "DbHits": + return mapping( HITS, new RightJustifiedCell( + value.asNumber().toString() ), columns ); + case "PageCacheHits": + return mapping( PAGE_CACHE, new RightJustifiedCell( + String.format( "%s/%s", value.asNumber(), + args.getOrDefault( "PageCacheMisses", + ZERO_VALUE ) + .asNumber() ) ), columns ); + case "Time": + return mapping( TIME, new RightJustifiedCell( + String.format( "%.3f", + value.asLong() / 1000000.0d ) ), + columns ); + case "Order": + return mapping( ORDER, new LeftJustifiedCell( + String.format( "%s", value.asString() ) ), columns ); + case "Details": + return mapping( DETAILS, new LeftJustifiedCell( + splitDetails( value.asString() ) ), columns ); + case "Memory": + return mapping( MEMORY, new RightJustifiedCell( + String.format( "%s", value.asNumber().toString() ) ), + columns ); + default: + return Optional.empty(); + } + } ); return Stream.concat( formattedPlan, Stream.of( - Optional.of(Pair.of(IDENTIFIERS, new LeftJustifiedCell(identifiers(plan, columns)))), - Optional.of(Pair.of(OTHER, new LeftJustifiedCell(other(plan, columns)))))) - .filter(Optional::isPresent) - .collect(toMap(o -> o.get()._1, o -> o.get()._2)); + Optional.of( Pair.of( IDENTIFIERS, new LeftJustifiedCell( identifiers( plan, columns ) ) ) ), + Optional.of( Pair.of( OTHER, new LeftJustifiedCell( other( plan, columns ) ) ) ) ) ) + .filter( Optional::isPresent ) + .collect( toMap( o -> o.get()._1, o -> o.get()._2 ) ); } @Nonnull - private Optional> mapping(@Nonnull String key, @Nonnull Cell value, @Nonnull Map columns) { - update(columns, key, value.length); - return Optional.of(Pair.of(key, value)); + private Optional> mapping( @Nonnull String key, @Nonnull Cell value, @Nonnull Map columns ) + { + update( columns, key, value.length ); + return Optional.of( Pair.of( key, value ) ); } @Nonnull - private String replaceAllIn(@Nonnull Pattern pattern, @Nonnull String s, @Nonnull Function mapper) { + private String replaceAllIn( @Nonnull Pattern pattern, @Nonnull String s, @Nonnull Function mapper ) + { StringBuffer sb = new StringBuffer(); - Matcher matcher = pattern.matcher(s); - while (matcher.find()) { - matcher.appendReplacement(sb, mapper.apply(matcher)); + Matcher matcher = pattern.matcher( s ); + while ( matcher.find() ) + { + matcher.appendReplacement( sb, mapper.apply( matcher ) ); } - matcher.appendTail(sb); + matcher.appendTail( sb ); return sb.toString(); } @Nonnull - private String removeGeneratedNames(@Nonnull String s) { - String named = replaceAllIn(UNNAMED_PATTERN, s, m -> "anon[" + m.group(2) + "]"); - return replaceAllIn(DEDUP_PATTERN, named, m -> m.group(1)); + private String removeGeneratedNames( @Nonnull String s ) + { + String named = replaceAllIn( UNNAMED_PATTERN, s, m -> "anon[" + m.group( 2 ) + "]" ); + return replaceAllIn( DEDUP_PATTERN, named, m -> m.group( 1 ) ); } - private void update(@Nonnull Map columns, @Nonnull String key, int length) { - columns.put(key, Math.max(columns.getOrDefault(key, 0), length)); + private void update( @Nonnull Map columns, @Nonnull String key, int length ) + { + columns.put( key, Math.max( columns.getOrDefault( key, 0 ), length ) ); } @Nonnull - private String identifiers(@Nonnull Plan description, @Nonnull Map columns) { - String result = description.identifiers().stream().map(this::removeGeneratedNames).collect(joining(", ")); - if (!result.isEmpty()) { - update(columns, IDENTIFIERS, result.length()); + private String identifiers( @Nonnull Plan description, @Nonnull Map columns ) + { + String result = description.identifiers().stream().map( this::removeGeneratedNames ).collect( joining( ", " ) ); + if ( !result.isEmpty() ) + { + update( columns, IDENTIFIERS, result.length() ); } return result; } @Nonnull - private String other(@Nonnull Plan description, @Nonnull Map columns) { - String result = description.arguments().entrySet().stream().map(e -> { - if (!IGNORED_ARGUMENTS.contains(e.getKey())) return serialize(e.getKey(), e.getValue()); - return ""; - }).filter(OutputFormatter::isNotBlank).collect(Collectors.joining("; ")).replaceAll(UNNAMED_PATTERN_STRING, ""); - - if (!result.isEmpty()) { - update(columns, OTHER, result.length()); + private String other( @Nonnull Plan description, @Nonnull Map columns ) + { + String result = description.arguments().entrySet().stream().map( e -> + { + if ( !IGNORED_ARGUMENTS.contains( e.getKey() ) ) + { + return serialize( e.getKey(), e.getValue() ); + } + return ""; + } ).filter( OutputFormatter::isNotBlank ).collect( Collectors.joining( "; " ) ) + .replaceAll( UNNAMED_PATTERN_STRING, "" ); + + if ( !result.isEmpty() ) + { + update( columns, OTHER, result.length() ); } return result; } @Nonnull - private String format(@Nonnull Double v) { - if (v.isNaN()) return v.toString(); - return String.valueOf(Math.round(v)); + private String format( @Nonnull Double v ) + { + if ( v.isNaN() ) + { + return v.toString(); + } + return String.valueOf( Math.round( v ) ); } - static class TableRow { + static class TableRow + { private final String tree; - private final Map cells; + private final Map cells; private final Optional connection; private final int height; - TableRow(String tree, Map cells, Optional connection) { + TableRow( String tree, Map cells, Optional connection ) + { this.tree = tree; this.cells = cells; this.connection = connection == null ? Optional.empty() : connection; - this.height = cells.values().stream().mapToInt(v -> v.lines.length).max().orElse(0); + this.height = cells.values().stream().mapToInt( v -> v.lines.length ).max().orElse( 0 ); } - Cell get(String key) { - if (key.equals(TablePlanFormatter.OPERATOR)) - return new LeftJustifiedCell(tree); + Cell get( String key ) + { + if ( key.equals( TablePlanFormatter.OPERATOR ) ) + { + return new LeftJustifiedCell( tree ); + } else - return cells.getOrDefault(key, new LeftJustifiedCell("")); + { + return cells.getOrDefault( key, new LeftJustifiedCell( "" ) ); + } } } - static abstract class Cell { + abstract static class Cell + { final int length; final String[] lines; - Cell(String[] lines) { - this.length = Stream.of(lines).mapToInt(String::length).max().orElse(0); + Cell( String[] lines ) + { + this.length = Stream.of( lines ).mapToInt( String::length ).max().orElse( 0 ); this.lines = lines; } - abstract void writePaddedLine(int lineIndex, String orElseValue, int columnWidth, StringBuilder result); + abstract void writePaddedLine( int lineIndex, String orElseValue, int columnWidth, StringBuilder result ); - protected int paddingWidth(int columnWidth, String line) { + protected int paddingWidth( int columnWidth, String line ) + { return columnWidth - line.length() - 2; } - protected String getLineOrElse(int lineIndex, String orElseValue) { - if (lineIndex < lines.length) + protected String getLineOrElse( int lineIndex, String orElseValue ) + { + if ( lineIndex < lines.length ) + { return lines[lineIndex]; + } else + { return orElseValue; + } } } static class LeftJustifiedCell extends Cell { - LeftJustifiedCell(String... lines) { - super(lines); + LeftJustifiedCell( String... lines ) + { + super( lines ); } @Override - void writePaddedLine(int lineIndex, String orElseValue, int columnWidth, StringBuilder result) { - String line = getLineOrElse(lineIndex, orElseValue); - result.append(line); - pad(paddingWidth(columnWidth, line), ' ', result); + void writePaddedLine( int lineIndex, String orElseValue, int columnWidth, StringBuilder result ) + { + String line = getLineOrElse( lineIndex, orElseValue ); + result.append( line ); + pad( paddingWidth( columnWidth, line ), ' ', result ); } } - static class RightJustifiedCell extends Cell { - RightJustifiedCell(String... lines) { - super(lines); + static class RightJustifiedCell extends Cell + { + RightJustifiedCell( String... lines ) + { + super( lines ); } @Override - void writePaddedLine(int lineIndex, String orElseValue, int columnWidth, StringBuilder result) + void writePaddedLine( int lineIndex, String orElseValue, int columnWidth, StringBuilder result ) { - String line = getLineOrElse(lineIndex, orElseValue); - pad(paddingWidth(columnWidth, line), ' ', result); - result.append(line); + String line = getLineOrElse( lineIndex, orElseValue ); + pad( paddingWidth( columnWidth, line ), ' ', result ); + result.append( line ); } } - static abstract class Level { + abstract static class Level + { abstract Level child(); abstract Level fork(); @@ -369,125 +469,154 @@ static abstract class Level { abstract Optional connector(); } - static class Root extends Level { + static class Root extends Level + { @Override - Level child() { - return new Child(1); + Level child() + { + return new Child( 1 ); } @Override - Level fork() { - return new Fork(2); + Level fork() + { + return new Fork( 2 ); } @Override - String line() { + String line() + { return "+"; } @Override - Optional connector() { + Optional connector() + { return Optional.empty(); } - } - static class Child extends Level { + static class Child extends Level + { private final int level; - Child(int level) { + Child( int level ) + { this.level = level; } @Override - Level child() { - return new Child(level); + Level child() + { + return new Child( level ); } @Override - Level fork() { - return new Fork(level + 1); + Level fork() + { + return new Fork( level + 1 ); } @Override - String line() { - return repeat("| ", (level - 1)) + "+"; + String line() + { + return repeat( "| ", level - 1 ) + "+"; } @Override - Optional connector() { - return Optional.of(repeat("| ", level)); + Optional connector() + { + return Optional.of( repeat( "| ", level ) ); } } - static class Fork extends Level { + static class Fork extends Level + { private final int level; - Fork(int level) { + Fork( int level ) + { this.level = level; } @Override - Level child() { - return new Child(level); + Level child() + { + return new Child( level ); } @Override - Level fork() { - return new Fork(level + 1); + Level fork() + { + return new Fork( level + 1 ); } @Override - String line() { - return repeat("| ", level - 1) + "+"; + String line() + { + return repeat( "| ", level - 1 ) + "+"; } @Override - Optional connector() { - return Optional.of(repeat("| ", level - 2) + "|\\"); + Optional connector() + { + return Optional.of( repeat( "| ", level - 2 ) + "|\\" ); } } - static final class Pair { + static final class Pair + { final T1 _1; final T2 _2; - private Pair(T1 _1, T2 _2) { + private Pair( T1 _1, T2 _2 ) + { this._1 = _1; this._2 = _2; } @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + public boolean equals( Object o ) + { + if ( this == o ) + { + return true; + } + if ( o == null || getClass() != o.getClass() ) + { + return false; + } Pair pair = (Pair) o; - return _1.equals(pair._1) && _2.equals(pair._2); + return _1.equals( pair._1 ) && _2.equals( pair._2 ); } @Override - public int hashCode() { + public int hashCode() + { return 31 * _1.hashCode() + _2.hashCode(); } - public static Pair of(T1 _1, T2 _2) { - return new Pair<>(_1, _2); + public static Pair of( T1 _1, T2 _2 ) + { + return new Pair<>( _1, _2 ); } } - private String[] splitDetails(String original) { + private String[] splitDetails( String original ) + { List detailsList = new ArrayList<>(); int currentPos = 0; - while(currentPos < original.length()){ - int newPos = Math.min(original.length(), currentPos + MAX_DETAILS_COLUMN_WIDTH); - detailsList.add(original.substring( currentPos, newPos)); + while ( currentPos < original.length() ) + { + int newPos = Math.min( original.length(), currentPos + MAX_DETAILS_COLUMN_WIDTH ); + detailsList.add( original.substring( currentPos, newPos ) ); currentPos = newPos; } - return detailsList.toArray(new String[0]); + return detailsList.toArray( new String[0] ); } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/state/BoltResult.java b/cypher-shell/src/main/java/org/neo4j/shell/state/BoltResult.java index 8f8aa720..adfc543f 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/state/BoltResult.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/state/BoltResult.java @@ -1,16 +1,36 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.state; -import org.neo4j.driver.Record; -import org.neo4j.driver.summary.ResultSummary; - -import javax.annotation.Nonnull; import java.util.Iterator; import java.util.List; +import javax.annotation.Nonnull; + +import org.neo4j.driver.Record; +import org.neo4j.driver.summary.ResultSummary; /** * The result of executing some Cypher over bolt. */ -public interface BoltResult { +public interface BoltResult +{ @Nonnull List getKeys(); diff --git a/cypher-shell/src/main/java/org/neo4j/shell/state/BoltStateHandler.java b/cypher-shell/src/main/java/org/neo4j/shell/state/BoltStateHandler.java index 95c76c9b..e2f52d21 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/state/BoltStateHandler.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/state/BoltStateHandler.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.state; import java.util.HashMap; @@ -45,51 +64,61 @@ /** * Handles interactions with the driver */ -public class BoltStateHandler implements TransactionHandler, Connector, DatabaseManager { - private final TriFunction driverProvider; +public class BoltStateHandler implements TransactionHandler, Connector, DatabaseManager +{ private static final String USER_AGENT = "neo4j-cypher-shell/v" + Build.version(); + private final TriFunction driverProvider; + private final boolean isInteractive; + private final Map bookmarks = new HashMap<>(); protected Driver driver; Session session; private String version; private String activeDatabaseNameAsSetByUser; private String actualDatabaseNameAsReportedByServer; - private final boolean isInteractive; - private final Map bookmarks = new HashMap<>(); - private Transaction tx = null; + private Transaction tx; - public BoltStateHandler(boolean isInteractive) { - this(GraphDatabase::driver, isInteractive); + public BoltStateHandler( boolean isInteractive ) + { + this( GraphDatabase::driver, isInteractive ); } - BoltStateHandler(TriFunction driverProvider, - boolean isInteractive) { + BoltStateHandler( TriFunction driverProvider, + boolean isInteractive ) + { this.driverProvider = driverProvider; activeDatabaseNameAsSetByUser = ABSENT_DB_NAME; this.isInteractive = isInteractive; } @Override - public void setActiveDatabase(String databaseName) throws CommandException + public void setActiveDatabase( String databaseName ) throws CommandException { - if (isTransactionOpen()) { - throw new CommandException("There is an open transaction. You need to close it before you can switch database."); + if ( isTransactionOpen() ) + { + throw new CommandException( "There is an open transaction. You need to close it before you can switch database." ); } String previousDatabaseName = activeDatabaseNameAsSetByUser; activeDatabaseNameAsSetByUser = databaseName; - try { - if (isConnected()) { - reconnect(databaseName, previousDatabaseName); + try + { + if ( isConnected() ) + { + reconnect( databaseName, previousDatabaseName ); } } - catch (ClientException e) { - if (isInteractive) { + catch ( ClientException e ) + { + if ( isInteractive ) + { // We want to try to connect to the previous database activeDatabaseNameAsSetByUser = previousDatabaseName; - try { - reconnect(previousDatabaseName, previousDatabaseName); + try + { + reconnect( previousDatabaseName, previousDatabaseName ); } - catch (Exception e2) { - e.addSuppressed(e2); + catch ( Exception e2 ) + { + e.addSuppressed( e2 ); } } throw e; @@ -109,23 +138,29 @@ public String getActualDatabaseAsReportedByServer() } @Override - public void beginTransaction() throws CommandException { - if (!isConnected()) { - throw new CommandException("Not connected to Neo4j"); + public void beginTransaction() throws CommandException + { + if ( !isConnected() ) + { + throw new CommandException( "Not connected to Neo4j" ); } - if (isTransactionOpen()) { - throw new CommandException("There is already an open transaction"); + if ( isTransactionOpen() ) + { + throw new CommandException( "There is already an open transaction" ); } tx = session.beginTransaction(); } @Override - public void commitTransaction() throws CommandException { - if (!isConnected()) { - throw new CommandException("Not connected to Neo4j"); + public void commitTransaction() throws CommandException + { + if ( !isConnected() ) + { + throw new CommandException( "Not connected to Neo4j" ); } - if (!isTransactionOpen()) { - throw new CommandException("There is no open transaction to commit"); + if ( !isTransactionOpen() ) + { + throw new CommandException( "There is no open transaction to commit" ); } tx.commit(); tx.close(); @@ -133,12 +168,15 @@ public void commitTransaction() throws CommandException { } @Override - public void rollbackTransaction() throws CommandException { - if (!isConnected()) { - throw new CommandException("Not connected to Neo4j"); + public void rollbackTransaction() throws CommandException + { + if ( !isConnected() ) + { + throw new CommandException( "Not connected to Neo4j" ); } - if (!isTransactionOpen()) { - throw new CommandException("There is no open transaction to rollback"); + if ( !isTransactionOpen() ) + { + throw new CommandException( "There is no open transaction to rollback" ); } tx.rollback(); tx.close(); @@ -146,9 +184,8 @@ public void rollbackTransaction() throws CommandException { } /** - * Handle an exception while getting or consuming the result. - * If not in TX, return the given exception. - * If in a TX, terminate the TX and return a more verbose error message. + * Handle an exception while getting or consuming the result. If not in TX, return the given exception. If in a TX, terminate the TX and return a more + * verbose error message. * * @param e the thrown exception. * @return a suitable exception to rethrow. @@ -169,28 +206,36 @@ public Neo4jException handleException( Neo4jException e ) } @Override - public boolean isTransactionOpen() { + public boolean isTransactionOpen() + { return tx != null; } @Override - public boolean isConnected() { + public boolean isConnected() + { return session != null && session.isOpen(); } @Override - public void connect( @Nonnull ConnectionConfig connectionConfig, ThrowingAction command) throws CommandException { - if (isConnected()) { - throw new CommandException("Already connected"); + public void connect( @Nonnull ConnectionConfig connectionConfig, ThrowingAction command ) throws CommandException + { + if ( isConnected() ) + { + throw new CommandException( "Already connected" ); } - final AuthToken authToken = AuthTokens.basic(connectionConfig.username(), connectionConfig.password()); - try { + final AuthToken authToken = AuthTokens.basic( connectionConfig.username(), connectionConfig.password() ); + try + { String previousDatabaseName = activeDatabaseNameAsSetByUser; - try { + try + { activeDatabaseNameAsSetByUser = connectionConfig.database(); - driver = getDriver(connectionConfig, authToken); - reconnect(activeDatabaseNameAsSetByUser, previousDatabaseName, command); - } catch (org.neo4j.driver.exceptions.ServiceUnavailableException e) { + driver = getDriver( connectionConfig, authToken ); + reconnect( activeDatabaseNameAsSetByUser, previousDatabaseName, command ); + } + catch ( org.neo4j.driver.exceptions.ServiceUnavailableException e ) + { String scheme = connectionConfig.scheme(); String fallbackScheme; switch ( scheme ) @@ -208,33 +253,40 @@ public void connect( @Nonnull ConnectionConfig connectionConfig, ThrowingAction< throw e; } connectionConfig = new ConnectionConfig( - fallbackScheme, - connectionConfig.host(), - connectionConfig.port(), - connectionConfig.username(), - connectionConfig.password(), - connectionConfig.encryption(), - connectionConfig.database()); - driver = getDriver(connectionConfig, authToken); - reconnect(activeDatabaseNameAsSetByUser, previousDatabaseName, command); + fallbackScheme, + connectionConfig.host(), + connectionConfig.port(), + connectionConfig.username(), + connectionConfig.password(), + connectionConfig.encryption(), + connectionConfig.database() ); + driver = getDriver( connectionConfig, authToken ); + reconnect( activeDatabaseNameAsSetByUser, previousDatabaseName, command ); } - } catch (Throwable t) { - try { + } + catch ( Throwable t ) + { + try + { silentDisconnect(); - } catch (Exception e) { - t.addSuppressed(e); + } + catch ( Exception e ) + { + t.addSuppressed( e ); } throw t; } } - private void reconnect(String databaseToConnectTo, String previousDatabase) throws CommandException { - reconnect(databaseToConnectTo, previousDatabase, null); + private void reconnect( String databaseToConnectTo, String previousDatabase ) throws CommandException + { + reconnect( databaseToConnectTo, previousDatabase, null ); } private void reconnect( String databaseToConnectTo, String previousDatabase, - ThrowingAction command ) throws CommandException { + ThrowingAction command ) throws CommandException + { SessionConfig.Builder builder = SessionConfig.builder(); builder.withDefaultAccessMode( AccessMode.WRITE ); if ( !ABSENT_DB_NAME.equals( databaseToConnectTo ) ) @@ -251,12 +303,12 @@ private void reconnect( String databaseToConnectTo, session = driver.session( builder.build() ); resetActualDbName(); // Set this to null first in case run throws an exception - connect(command); + connect( command ); } /** - * Closes the session, if there is any. - * Saves a bookmark for the database currently connected to. + * Closes the session, if there is any. Saves a bookmark for the database currently connected to. + * * @param databaseName the name of the database currently connected to */ private void closeSession( String databaseName ) @@ -266,11 +318,11 @@ private void closeSession( String databaseName ) // Save the last bookmark and close the session final Bookmark bookmarkForPreviousDB = session.lastBookmark(); session.close(); - bookmarks.put(databaseName, bookmarkForPreviousDB); + bookmarks.put( databaseName, bookmarkForPreviousDB ); } } - private void connect( ThrowingAction command) throws CommandException + private void connect( ThrowingAction command ) throws CommandException { ThrowingAction toCall = command == null ? getPing() : () -> { @@ -282,7 +334,7 @@ private void connect( ThrowingAction command) throws CommandEx { //If we need to update password we need to call the apply //to set the server version and such. - if (isPasswordChangeRequiredException( e )) + if ( isPasswordChangeRequiredException( e ) ) { getPing().apply(); } @@ -294,42 +346,57 @@ private void connect( ThrowingAction command) throws CommandEx toCall.apply(); } - private ThrowingAction getPing() { + private ThrowingAction getPing() + { - return () -> { + return () -> + { ResultSummary summary = null; - Result run = session.run( "CALL db.ping()"); - try { + Result run = session.run( "CALL db.ping()" ); + try + { summary = run.consume(); - } catch (ClientException e) { + } + catch ( ClientException e ) + { //In older versions there is no db.ping procedure, use legacy method. - if ( procedureNotFound( e ) ) { - run = session.run(isSystemDb() ? "CALL db.indexes()" : "RETURN 1" ); - } else { + if ( procedureNotFound( e ) ) + { + run = session.run( isSystemDb() ? "CALL db.indexes()" : "RETURN 1" ); + } + else + { throw e; } - } finally { + } + finally + { // Since run.consume() can throw the first time we have to go through this extra hoop to get the summary - if (summary == null) { + if ( summary == null ) + { summary = run.consume(); } BoltStateHandler.this.version = summary.server().version(); - updateActualDbName(summary); + updateActualDbName( summary ); } }; } @Nonnull @Override - public String getServerVersion() { - if (isConnected()) { - if (version == null) { + public String getServerVersion() + { + if ( isConnected() ) + { + if ( version == null ) + { // On versions before 3.1.0-M09 version = ""; } - if (version.startsWith("Neo4j/")) { + if ( version.startsWith( "Neo4j/" ) ) + { // Want to return '3.1.0' and not 'Neo4j/3.1.0' - version = version.substring(6); + version = version.substring( 6 ); } return version; } @@ -337,81 +404,104 @@ public String getServerVersion() { } @Nonnull - public Optional runCypher(@Nonnull String cypher, - @Nonnull Map queryParams) throws CommandException { - if (!isConnected()) { - throw new CommandException("Not connected to Neo4j"); + public Optional runCypher( @Nonnull String cypher, + @Nonnull Map queryParams ) throws CommandException + { + if ( !isConnected() ) + { + throw new CommandException( "Not connected to Neo4j" ); } - if (isTransactionOpen()) { + if ( isTransactionOpen() ) + { // If this fails, don't try any funny business - just let it die - return getBoltResult(cypher, queryParams); - } else { - try { + return getBoltResult( cypher, queryParams ); + } + else + { + try + { // Note that PERIODIC COMMIT can't execute in a transaction, so if the user has not typed BEGIN, then // the statement should NOT be executed in a transaction. - return getBoltResult(cypher, queryParams); - } catch (SessionExpiredException e) { + return getBoltResult( cypher, queryParams ); + } + catch ( SessionExpiredException e ) + { // Server is no longer accepting writes, reconnect and try again. // If it still fails, leave it up to the user - reconnect(activeDatabaseNameAsSetByUser, activeDatabaseNameAsSetByUser); - return getBoltResult(cypher, queryParams); + reconnect( activeDatabaseNameAsSetByUser, activeDatabaseNameAsSetByUser ); + return getBoltResult( cypher, queryParams ); } } } - public void updateActualDbName(@Nonnull ResultSummary resultSummary) { - actualDatabaseNameAsReportedByServer = getActualDbName(resultSummary); + public void updateActualDbName( @Nonnull ResultSummary resultSummary ) + { + actualDatabaseNameAsReportedByServer = getActualDbName( resultSummary ); } public void changePassword( @Nonnull ConnectionConfig connectionConfig ) { - if (!connectionConfig.passwordChangeRequired()) { + if ( !connectionConfig.passwordChangeRequired() ) + { return; } - if (isConnected()) { + if ( isConnected() ) + { silentDisconnect(); } - final AuthToken authToken = AuthTokens.basic(connectionConfig.username(), connectionConfig.password()); + final AuthToken authToken = AuthTokens.basic( connectionConfig.username(), connectionConfig.password() ); - try { - driver = getDriver(connectionConfig, authToken); + try + { + driver = getDriver( connectionConfig, authToken ); activeDatabaseNameAsSetByUser = SYSTEM_DB_NAME; // Supply empty command, so that we do not run ping. - reconnect( SYSTEM_DB_NAME, SYSTEM_DB_NAME, () -> {} ); + reconnect( SYSTEM_DB_NAME, SYSTEM_DB_NAME, () -> + { + } ); String command; Value parameters; - if (majorVersion(getServerVersion()) >= 4) { + if ( majorVersion( getServerVersion() ) >= 4 ) + { command = "ALTER CURRENT USER SET PASSWORD FROM $o TO $n"; - parameters = Values.parameters("o", connectionConfig.password(), "n", connectionConfig.newPassword()); - } else { + parameters = Values.parameters( "o", connectionConfig.password(), "n", connectionConfig.newPassword() ); + } + else + { command = "CALL dbms.security.changePassword($n)"; - parameters = Values.parameters("n", connectionConfig.newPassword()); + parameters = Values.parameters( "n", connectionConfig.newPassword() ); } - Result run = session.run(command, parameters); + Result run = session.run( command, parameters ); run.consume(); // If successful, use the new password when reconnecting - connectionConfig.setPassword(connectionConfig.newPassword()); - connectionConfig.setNewPassword(null); + connectionConfig.setPassword( connectionConfig.newPassword() ); + connectionConfig.setNewPassword( null ); silentDisconnect(); - } catch (Throwable t) { - try { + } + catch ( Throwable t ) + { + try + { silentDisconnect(); - } catch (Exception e) { - t.addSuppressed(e); } - if (t instanceof RuntimeException) { + catch ( Exception e ) + { + t.addSuppressed( e ); + } + if ( t instanceof RuntimeException ) + { throw (RuntimeException) t; } // The only checked exception is CommandException and we know that // we cannot get that since we supply an empty command. - throw new RuntimeException(t); + throw new RuntimeException( t ); } } @@ -419,42 +509,53 @@ public void changePassword( @Nonnull ConnectionConfig connectionConfig ) * @throws SessionExpiredException when server no longer serves writes anymore */ @Nonnull - private Optional getBoltResult(@Nonnull String cypher, @Nonnull Map queryParams) throws SessionExpiredException { + private Optional getBoltResult( @Nonnull String cypher, @Nonnull Map queryParams ) throws SessionExpiredException + { Result statementResult; - if (isTransactionOpen()){ - statementResult = tx.run(new Query(cypher, queryParams)); - } else { - statementResult = session.run(new Query(cypher, queryParams)); + if ( isTransactionOpen() ) + { + statementResult = tx.run( new Query( cypher, queryParams ) ); + } + else + { + statementResult = session.run( new Query( cypher, queryParams ) ); } - if (statementResult == null) { + if ( statementResult == null ) + { return Optional.empty(); } - return Optional.of(new StatementBoltResult(statementResult)); + return Optional.of( new StatementBoltResult( statementResult ) ); } - private String getActualDbName(@Nonnull ResultSummary resultSummary) { + private String getActualDbName( @Nonnull ResultSummary resultSummary ) + { DatabaseInfo dbInfo = resultSummary.database(); return dbInfo.name() == null ? ABSENT_DB_NAME : dbInfo.name(); } - private void resetActualDbName() { + private void resetActualDbName() + { actualDatabaseNameAsReportedByServer = null; } /** - * Disconnect from Neo4j, clearing up any session resources, but don't give any output. - * Intended only to be used if connect fails. + * Disconnect from Neo4j, clearing up any session resources, but don't give any output. Intended only to be used if connect fails. */ - void silentDisconnect() { - try { + void silentDisconnect() + { + try + { closeSession( activeDatabaseNameAsSetByUser ); - if (driver != null) { + if ( driver != null ) + { driver.close(); } - } finally { + } + finally + { session = null; driver = null; resetActualDbName(); @@ -464,12 +565,15 @@ void silentDisconnect() { /** * Reset the current session. This rolls back any open transactions. */ - public void reset() { - if (isConnected()) { + public void reset() + { + if ( isConnected() ) + { session.reset(); // Clear current state - if (isTransactionOpen()) { + if ( isTransactionOpen() ) + { // Bolt has already rolled back the transaction but it doesn't close it properly tx.rollback(); tx.close(); @@ -481,17 +585,19 @@ public void reset() { /** * Used for testing purposes */ - public void disconnect() { - reset(); - silentDisconnect(); - version = null; + public void disconnect() + { + reset(); + silentDisconnect(); + version = null; } - private Driver getDriver(@Nonnull ConnectionConfig connectionConfig, @Nullable AuthToken authToken) { + private Driver getDriver( @Nonnull ConnectionConfig connectionConfig, @Nullable AuthToken authToken ) + { Config.ConfigBuilder configBuilder = Config.builder() - .withLogging(NullLogging.NULL_LOGGING) + .withLogging( NullLogging.NULL_LOGGING ) .withUserAgent( USER_AGENT ); - switch(connectionConfig.encryption()) + switch ( connectionConfig.encryption() ) { case TRUE: configBuilder = configBuilder.withEncryption(); @@ -499,25 +605,27 @@ private Driver getDriver(@Nonnull ConnectionConfig connectionConfig, @Nullable A case FALSE: configBuilder = configBuilder.withoutEncryption(); break; + default: + // Do nothing } - return driverProvider.apply(connectionConfig.driverUrl(), authToken, configBuilder.build()); + return driverProvider.apply( connectionConfig.driverUrl(), authToken, configBuilder.build() ); } - private List executeWithRetry(List transactionStatements, BiFunction biFunction) { - return session.writeTransaction(tx -> - transactionStatements.stream() - .map(transactionStatement -> biFunction.apply(transactionStatement, tx)) - .collect(Collectors.toList())); - + private List executeWithRetry( List transactionStatements, BiFunction biFunction ) + { + return session.writeTransaction( tx -> + transactionStatements.stream() + .map( transactionStatement -> biFunction.apply( transactionStatement, tx ) ) + .collect( Collectors.toList() ) ); } private boolean isSystemDb() { - return activeDatabaseNameAsSetByUser.compareToIgnoreCase(SYSTEM_DB_NAME) == 0; + return activeDatabaseNameAsSetByUser.compareToIgnoreCase( SYSTEM_DB_NAME ) == 0; } private boolean procedureNotFound( ClientException e ) { - return e.code().compareToIgnoreCase("Neo.ClientError.Procedure.ProcedureNotFound") == 0; + return e.code().compareToIgnoreCase( "Neo.ClientError.Procedure.ProcedureNotFound" ) == 0; } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/state/ErrorWhileInTransactionException.java b/cypher-shell/src/main/java/org/neo4j/shell/state/ErrorWhileInTransactionException.java index 286228f7..007c46d4 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/state/ErrorWhileInTransactionException.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/state/ErrorWhileInTransactionException.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.state; import org.neo4j.driver.exceptions.Neo4jException; diff --git a/cypher-shell/src/main/java/org/neo4j/shell/state/ListBoltResult.java b/cypher-shell/src/main/java/org/neo4j/shell/state/ListBoltResult.java index 13f96853..ac625100 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/state/ListBoltResult.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/state/ListBoltResult.java @@ -1,27 +1,49 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.state; -import org.neo4j.driver.Record; -import org.neo4j.driver.summary.ResultSummary; - -import javax.annotation.Nonnull; import java.util.Collections; import java.util.Iterator; import java.util.List; +import javax.annotation.Nonnull; + +import org.neo4j.driver.Record; +import org.neo4j.driver.summary.ResultSummary; /** * A fully materialized Cypher result. */ -public class ListBoltResult implements BoltResult { +public class ListBoltResult implements BoltResult +{ private final List keys; private final List records; private final ResultSummary summary; - public ListBoltResult(@Nonnull List records, @Nonnull ResultSummary summary) { - this(records, summary, records.isEmpty() ? Collections.emptyList() : records.get(0).keys()); + public ListBoltResult( @Nonnull List records, @Nonnull ResultSummary summary ) + { + this( records, summary, records.isEmpty() ? Collections.emptyList() : records.get( 0 ).keys() ); } - public ListBoltResult(@Nonnull List records, @Nonnull ResultSummary summary, @Nonnull List keys) { + public ListBoltResult( @Nonnull List records, @Nonnull ResultSummary summary, @Nonnull List keys ) + { this.keys = keys; this.records = records; this.summary = summary; @@ -29,25 +51,29 @@ public ListBoltResult(@Nonnull List records, @Nonnull ResultSummary summ @Nonnull @Override - public List getKeys() { + public List getKeys() + { return keys; } @Override @Nonnull - public List getRecords() { + public List getRecords() + { return records; } @Override @Nonnull - public Iterator iterate() { + public Iterator iterate() + { return records.iterator(); } @Override @Nonnull - public ResultSummary getSummary() { + public ResultSummary getSummary() + { return summary; } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/state/ParamValue.java b/cypher-shell/src/main/java/org/neo4j/shell/state/ParamValue.java index 3708093f..645ad7c4 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/state/ParamValue.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/state/ParamValue.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.state; import java.util.Objects; @@ -5,20 +24,24 @@ /** * Handles queryparams value and user inputString */ -public class ParamValue { +public class ParamValue +{ private final String valueAsString; private final Object value; - public ParamValue(String valueAsString, Object value) { + public ParamValue( String valueAsString, Object value ) + { this.valueAsString = valueAsString; this.value = value; } - public Object getValue() { + public Object getValue() + { return value; } - public String getValueAsString() { + public String getValueAsString() + { return valueAsString; } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/state/StatementBoltResult.java b/cypher-shell/src/main/java/org/neo4j/shell/state/StatementBoltResult.java index 5507d00a..b21bfb49 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/state/StatementBoltResult.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/state/StatementBoltResult.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.state; import java.util.Iterator; @@ -11,35 +30,41 @@ /** * Wrapper around {@link Result}. Might or might not be materialized. */ -public class StatementBoltResult implements BoltResult { +public class StatementBoltResult implements BoltResult +{ private final Result result; - public StatementBoltResult(Result result) { + public StatementBoltResult( Result result ) + { this.result = result; } @Nonnull @Override - public List getKeys() { + public List getKeys() + { return result.keys(); } @Nonnull @Override - public List getRecords() { + public List getRecords() + { return result.list(); } @Nonnull @Override - public Iterator iterate() { + public Iterator iterate() + { return result; } @Nonnull @Override - public ResultSummary getSummary() { + public ResultSummary getSummary() + { return result.consume(); } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/system/Utils.java b/cypher-shell/src/main/java/org/neo4j/shell/system/Utils.java index ae34ead6..a5217eb3 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/system/Utils.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/system/Utils.java @@ -1,14 +1,35 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.system; /** * Utility functions */ -public class Utils { +public class Utils +{ /** * @return true if running on Windows, false if not or if os could not be determined. */ - public static boolean isWindows() { - String osName = System.getProperty("os.name"); - return osName != null && osName.toLowerCase().contains("windows"); + public static boolean isWindows() + { + String osName = System.getProperty( "os.name" ); + return osName != null && osName.toLowerCase().contains( "windows" ); } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/util/ParameterSetter.java b/cypher-shell/src/main/java/org/neo4j/shell/util/ParameterSetter.java index fc774b19..0ce01840 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/util/ParameterSetter.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/util/ParameterSetter.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.util; import java.util.function.BiPredicate; @@ -11,13 +30,14 @@ /** * Shared logic to parse parameters and set them in a ParameterMap */ -public abstract class ParameterSetter { +public abstract class ParameterSetter +{ // Match arguments such as "(key) (value with possible spaces)" where key and value are any strings - private static final Pattern backtickPattern = Pattern.compile( "^\\s*(?(`([^`])*`)+?):?\\s+(?.+)$"); - private static final Pattern backtickLambdaPattern = Pattern.compile("^\\s*(?(`([^`])*`)+?)\\s*=>\\s*(?.+)$"); - private static final Pattern argPattern = Pattern.compile("^\\s*(?[\\p{L}_][\\p{L}0-9_]*):?\\s+(?.+)$"); - private static final Pattern lambdaPattern = Pattern.compile("^\\s*(?[\\p{L}_][\\p{L}0-9_]*)\\s*=>\\s*(?.+)$"); - private static final Pattern lambdaMapPattern = Pattern.compile("^\\s*(?[\\p{L}_][\\p{L}0-9_]*):\\s*=>\\s*(?.+)$"); + private static final Pattern backtickPattern = Pattern.compile( "^\\s*(?(`([^`])*`)+?):?\\s+(?.+)$" ); + private static final Pattern backtickLambdaPattern = Pattern.compile( "^\\s*(?(`([^`])*`)+?)\\s*=>\\s*(?.+)$" ); + private static final Pattern argPattern = Pattern.compile( "^\\s*(?[\\p{L}_][\\p{L}0-9_]*):?\\s+(?.+)$" ); + private static final Pattern lambdaPattern = Pattern.compile( "^\\s*(?[\\p{L}_][\\p{L}0-9_]*)\\s*=>\\s*(?.+)$" ); + private static final Pattern lambdaMapPattern = Pattern.compile( "^\\s*(?[\\p{L}_][\\p{L}0-9_]*):\\s*=>\\s*(?.+)$" ); private final ParameterMap parameterMap; @@ -27,55 +47,66 @@ protected ParameterSetter( ParameterMap parameterMap ) } protected abstract void onWrongUsage() throws E; + protected abstract void onWrongNumberOfArguments() throws E; - protected abstract void onEvaluationException(EvaluationException e) throws E; - public void execute(@Nonnull final String argString) throws E { - Matcher lambdaMapMatcher = lambdaMapPattern.matcher( argString); - if (lambdaMapMatcher.matches()) { + protected abstract void onEvaluationException( EvaluationException e ) throws E; + + public void execute( @Nonnull final String argString ) throws E + { + Matcher lambdaMapMatcher = lambdaMapPattern.matcher( argString ); + if ( lambdaMapMatcher.matches() ) + { onWrongUsage(); } try { - if (!assignIfValidParameter(argString)) { + if ( !assignIfValidParameter( argString ) ) + { onWrongNumberOfArguments(); } } catch ( EvaluationException e ) { - onEvaluationException(e); + onEvaluationException( e ); } } - private boolean assignIfValidParameter(@Nonnull String argString) throws EvaluationException + private boolean assignIfValidParameter( @Nonnull String argString ) throws EvaluationException { - return setParameterIfItMatchesPattern(argString, lambdaPattern, assignIfValidParameter()) - || setParameterIfItMatchesPattern(argString, argPattern, assignIfValidParameter()) - || setParameterIfItMatchesPattern(argString, backtickLambdaPattern, backTickMatchPattern()) - || setParameterIfItMatchesPattern(argString, backtickPattern, backTickMatchPattern()); + return setParameterIfItMatchesPattern( argString, lambdaPattern, assignIfValidParameter() ) + || setParameterIfItMatchesPattern( argString, argPattern, assignIfValidParameter() ) + || setParameterIfItMatchesPattern( argString, backtickLambdaPattern, backTickMatchPattern() ) + || setParameterIfItMatchesPattern( argString, backtickPattern, backTickMatchPattern() ); } - private boolean setParameterIfItMatchesPattern(@Nonnull String argString, Pattern pattern, - BiPredicate matchingFunction) throws EvaluationException + private boolean setParameterIfItMatchesPattern( @Nonnull String argString, Pattern pattern, + BiPredicate matchingFunction ) throws EvaluationException { - Matcher matcher = pattern.matcher(argString); - if (matchingFunction.test(argString, matcher)) { - parameterMap.setParameter(matcher.group("key"), matcher.group("value")); + Matcher matcher = pattern.matcher( argString ); + if ( matchingFunction.test( argString, matcher ) ) + { + parameterMap.setParameter( matcher.group( "key" ), matcher.group( "value" ) ); return true; - } else { + } + else + { return false; } } - private BiPredicate assignIfValidParameter() { - return (argString, matcher) -> matcher.matches(); + private BiPredicate assignIfValidParameter() + { + return ( argString, matcher ) -> matcher.matches(); } - private BiPredicate backTickMatchPattern() { - return (argString, backtickLambdaMatcher) -> { - return argString.trim().startsWith("`") + private BiPredicate backTickMatchPattern() + { + return ( argString, backtickLambdaMatcher ) -> + { + return argString.trim().startsWith( "`" ) && backtickLambdaMatcher.matches() - && backtickLambdaMatcher.group("key").length() > 2; + && backtickLambdaMatcher.group( "key" ).length() > 2; }; } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/util/Version.java b/cypher-shell/src/main/java/org/neo4j/shell/util/Version.java index a84b9bc4..92d3399f 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/util/Version.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/util/Version.java @@ -1,45 +1,73 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.util; import static java.lang.String.format; -@SuppressWarnings("WeakerAccess") -public class Version implements Comparable { +@SuppressWarnings( "WeakerAccess" ) +public class Version implements Comparable +{ private final int major; private final int minor; private final int patch; - Version(int major, int minor, int patch) { + Version( int major, int minor, int patch ) + { this.major = major; this.minor = minor; this.patch = patch; } - public int major() { + public int major() + { return major; } - public int minor() { + public int minor() + { return minor; } - public int patch() { + public int patch() + { return patch; } @Override - public int compareTo(Version o) { - int comp = Integer.compare(major, o.major); - if (comp == 0) { - comp = Integer.compare(minor, o.minor); - if (comp == 0) { - comp = Integer.compare(patch, o.patch); + public int compareTo( Version o ) + { + int comp = Integer.compare( major, o.major ); + if ( comp == 0 ) + { + comp = Integer.compare( minor, o.minor ); + if ( comp == 0 ) + { + comp = Integer.compare( patch, o.patch ); } } return comp; } @Override - public String toString() { - return format("%d.%d.%d", major, minor, patch); + public String toString() + { + return format( "%d.%d.%d", major, minor, patch ); } } diff --git a/cypher-shell/src/main/java/org/neo4j/shell/util/Versions.java b/cypher-shell/src/main/java/org/neo4j/shell/util/Versions.java index 796d41d9..8d747fad 100644 --- a/cypher-shell/src/main/java/org/neo4j/shell/util/Versions.java +++ b/cypher-shell/src/main/java/org/neo4j/shell/util/Versions.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.util; import org.neo4j.driver.exceptions.Neo4jException; @@ -5,52 +24,63 @@ import static java.lang.Integer.parseInt; import static java.lang.String.format; -@SuppressWarnings({"WeakerAccess", "unused"}) -public final class Versions { +@SuppressWarnings( {"WeakerAccess", "unused"} ) +public final class Versions +{ - private Versions() { - throw new UnsupportedOperationException("Don't instantiate"); + private Versions() + { + throw new UnsupportedOperationException( "Don't instantiate" ); } - public static int majorVersion(String version) { - return version(version).major(); + public static int majorVersion( String version ) + { + return version( version ).major(); } - public static int minorVersion(String version) { - return version(version).minor(); + public static int minorVersion( String version ) + { + return version( version ).minor(); } - public static int patch(String version) { - return version(version).patch(); + public static int patch( String version ) + { + return version( version ).patch(); } - public static Version version(String version) { - if (version == null) { - throw new AssertionError("null is not a valid version string"); + public static Version version( String version ) + { + if ( version == null ) + { + throw new AssertionError( "null is not a valid version string" ); } - if (version.isEmpty()) { - return new Version(0, 0, 0); + if ( version.isEmpty() ) + { + return new Version( 0, 0, 0 ); } //remove -alpha, and -beta etc - int offset = version.indexOf("-"); - if (offset > 0) { - version = version.substring(0, offset); + int offset = version.indexOf( "-" ); + if ( offset > 0 ) + { + version = version.substring( 0, offset ); } - String[] split = version.split("\\."); - switch (split.length) { - case 1: - return new Version(parseInt(split[0]), 0, 0); - case 2: - return new Version(parseInt(split[0]), parseInt(split[1]), 0); - case 3: - return new Version(parseInt(split[0]), parseInt(split[1]), parseInt(split[2])); - default: - throw new AssertionError( - format("%s is not a proper version string, it should be of the form X.Y.Z ", version)); + String[] split = version.split( "\\." ); + switch ( split.length ) + { + case 1: + return new Version( parseInt( split[0] ), 0, 0 ); + case 2: + return new Version( parseInt( split[0] ), parseInt( split[1] ), 0 ); + case 3: + return new Version( parseInt( split[0] ), parseInt( split[1] ), parseInt( split[2] ) ); + default: + throw new AssertionError( + format( "%s is not a proper version string, it should be of the form X.Y.Z ", version ) ); } } - public static boolean isPasswordChangeRequiredException( Neo4jException e) { - return "Neo.ClientError.Security.CredentialsExpired".equalsIgnoreCase(e.code()); + public static boolean isPasswordChangeRequiredException( Neo4jException e ) + { + return "Neo.ClientError.Security.CredentialsExpired".equalsIgnoreCase( e.code() ); } } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/ConnectionConfigTest.java b/cypher-shell/src/test/java/org/neo4j/shell/ConnectionConfigTest.java index 3930c401..6ddf7ec6 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/ConnectionConfigTest.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/ConnectionConfigTest.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell; import org.junit.Rule; @@ -11,79 +30,90 @@ import static org.mockito.Mockito.mock; import static org.neo4j.shell.DatabaseManager.ABSENT_DB_NAME; -public class ConnectionConfigTest { +public class ConnectionConfigTest +{ @Rule - public final EnvironmentVariables environmentVariables - = new EnvironmentVariables(); - - private Logger logger = mock(Logger.class); - private ConnectionConfig config = new ConnectionConfig("bolt", "localhost", 1, "bob", - "pass", Encryption.DEFAULT, "db"); + public final EnvironmentVariables environmentVariables = new EnvironmentVariables(); + private Logger logger = mock( Logger.class ); + private ConnectionConfig config = new ConnectionConfig( "bolt", "localhost", 1, "bob", + "pass", Encryption.DEFAULT, "db" ); @Test - public void scheme() { - assertEquals("bolt", config.scheme()); + public void scheme() + { + assertEquals( "bolt", config.scheme() ); } @Test - public void host() { - assertEquals("localhost", config.host()); + public void host() + { + assertEquals( "localhost", config.host() ); } @Test - public void port() { - assertEquals(1, config.port()); + public void port() + { + assertEquals( 1, config.port() ); } @Test - public void username() { - assertEquals("bob", config.username()); + public void username() + { + assertEquals( "bob", config.username() ); } @Test - public void usernameDefaultsToEnvironmentVar() { - environmentVariables.set(ConnectionConfig.USERNAME_ENV_VAR, "alice"); - ConnectionConfig configWithEmptyParams = new ConnectionConfig("bolt", "localhost", 1, "", - "", Encryption.DEFAULT, ABSENT_DB_NAME); - assertEquals("alice", configWithEmptyParams.username()); + public void usernameDefaultsToEnvironmentVar() + { + environmentVariables.set( ConnectionConfig.USERNAME_ENV_VAR, "alice" ); + ConnectionConfig configWithEmptyParams = new ConnectionConfig( "bolt", "localhost", 1, "", + "", Encryption.DEFAULT, ABSENT_DB_NAME ); + assertEquals( "alice", configWithEmptyParams.username() ); } @Test - public void password() { - assertEquals("pass", config.password()); + public void password() + { + assertEquals( "pass", config.password() ); } @Test - public void passwordDefaultsToEnvironmentVar() { - environmentVariables.set(ConnectionConfig.PASSWORD_ENV_VAR, "ssap"); - ConnectionConfig configWithEmptyParams = new ConnectionConfig("bolt", "localhost", 1, "", - "", Encryption.DEFAULT, ABSENT_DB_NAME); - assertEquals("ssap", configWithEmptyParams.password()); + public void passwordDefaultsToEnvironmentVar() + { + environmentVariables.set( ConnectionConfig.PASSWORD_ENV_VAR, "ssap" ); + ConnectionConfig configWithEmptyParams = new ConnectionConfig( "bolt", "localhost", 1, "", + "", Encryption.DEFAULT, ABSENT_DB_NAME ); + assertEquals( "ssap", configWithEmptyParams.password() ); } @Test - public void database() { - assertEquals("db", config.database()); + public void database() + { + assertEquals( "db", config.database() ); } @Test - public void databaseDefaultsToEnvironmentVar() { - environmentVariables.set(ConnectionConfig.DATABASE_ENV_VAR, "funnyDB"); - ConnectionConfig configWithEmptyParams = new ConnectionConfig("bolt", "localhost", 1, "", - "", Encryption.DEFAULT, ABSENT_DB_NAME); - assertEquals("funnyDB", configWithEmptyParams.database()); + public void databaseDefaultsToEnvironmentVar() + { + environmentVariables.set( ConnectionConfig.DATABASE_ENV_VAR, "funnyDB" ); + ConnectionConfig configWithEmptyParams = new ConnectionConfig( "bolt", "localhost", 1, "", + "", Encryption.DEFAULT, ABSENT_DB_NAME ); + assertEquals( "funnyDB", configWithEmptyParams.database() ); } + @Test - public void driverUrlDefaultScheme() { - assertEquals("bolt://localhost:1", config.driverUrl()); + public void driverUrlDefaultScheme() + { + assertEquals( "bolt://localhost:1", config.driverUrl() ); } @Test - public void encryption() { - assertEquals(Encryption.DEFAULT, new ConnectionConfig("bolt", "", -1, "", "", Encryption.DEFAULT, ABSENT_DB_NAME).encryption()); - assertEquals(Encryption.TRUE, new ConnectionConfig("bolt", "", -1, "", "", Encryption.TRUE, ABSENT_DB_NAME).encryption()); - assertEquals(Encryption.FALSE, new ConnectionConfig("bolt", "", -1, "", "", Encryption.FALSE, ABSENT_DB_NAME).encryption()); + public void encryption() + { + assertEquals( Encryption.DEFAULT, new ConnectionConfig( "bolt", "", -1, "", "", Encryption.DEFAULT, ABSENT_DB_NAME ).encryption() ); + assertEquals( Encryption.TRUE, new ConnectionConfig( "bolt", "", -1, "", "", Encryption.TRUE, ABSENT_DB_NAME ).encryption() ); + assertEquals( Encryption.FALSE, new ConnectionConfig( "bolt", "", -1, "", "", Encryption.FALSE, ABSENT_DB_NAME ).encryption() ); } } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/CypherShellTest.java b/cypher-shell/src/test/java/org/neo4j/shell/CypherShellTest.java index a252d61e..b757194e 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/CypherShellTest.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/CypherShellTest.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell; import org.junit.Before; @@ -40,216 +59,238 @@ import static org.mockito.Mockito.when; import static org.neo4j.shell.DatabaseManager.ABSENT_DB_NAME; -@SuppressWarnings("OptionalGetWithoutIsPresent") -public class CypherShellTest { +@SuppressWarnings( "OptionalGetWithoutIsPresent" ) +public class CypherShellTest +{ @Rule public final ExpectedException thrown = ExpectedException.none(); - private BoltStateHandler mockedBoltStateHandler = mock(BoltStateHandler.class); - private final PrettyPrinter mockedPrettyPrinter = mock(PrettyPrinter.class); - private Logger logger = mock(Logger.class); + private final PrettyPrinter mockedPrettyPrinter = mock( PrettyPrinter.class ); + private BoltStateHandler mockedBoltStateHandler = mock( BoltStateHandler.class ); + private Logger logger = mock( Logger.class ); private OfflineTestShell offlineTestShell; @Before - public void setup() { - when(mockedBoltStateHandler.getServerVersion()).thenReturn(""); + public void setup() + { + when( mockedBoltStateHandler.getServerVersion() ).thenReturn( "" ); - doReturn(System.out).when(logger).getOutputStream(); - offlineTestShell = new OfflineTestShell(logger, mockedBoltStateHandler, mockedPrettyPrinter); + doReturn( System.out ).when( logger ).getOutputStream(); + offlineTestShell = new OfflineTestShell( logger, mockedBoltStateHandler, mockedPrettyPrinter ); - CommandHelper commandHelper = new CommandHelper(logger, Historian.empty, offlineTestShell); + CommandHelper commandHelper = new CommandHelper( logger, Historian.empty, offlineTestShell ); - offlineTestShell.setCommandHelper(commandHelper); + offlineTestShell.setCommandHelper( commandHelper ); } @Test - public void verifyDelegationOfConnectionMethods() throws CommandException { - ConnectionConfig cc = new ConnectionConfig("bolt", "", 1, "", "", Encryption.DEFAULT, ABSENT_DB_NAME); - CypherShell shell = new CypherShell(logger, mockedBoltStateHandler, mockedPrettyPrinter, new ShellParameterMap()); + public void verifyDelegationOfConnectionMethods() throws CommandException + { + ConnectionConfig cc = new ConnectionConfig( "bolt", "", 1, "", "", Encryption.DEFAULT, ABSENT_DB_NAME ); + CypherShell shell = new CypherShell( logger, mockedBoltStateHandler, mockedPrettyPrinter, new ShellParameterMap() ); - shell.connect(cc); - verify(mockedBoltStateHandler).connect(cc, null); + shell.connect( cc ); + verify( mockedBoltStateHandler ).connect( cc, null ); shell.isConnected(); - verify(mockedBoltStateHandler).isConnected(); + verify( mockedBoltStateHandler ).isConnected(); } @Test - public void verifyDelegationOfResetMethod() throws CommandException { - CypherShell shell = new CypherShell(logger, mockedBoltStateHandler, mockedPrettyPrinter, new ShellParameterMap()); + public void verifyDelegationOfResetMethod() throws CommandException + { + CypherShell shell = new CypherShell( logger, mockedBoltStateHandler, mockedPrettyPrinter, new ShellParameterMap() ); shell.reset(); - verify(mockedBoltStateHandler).reset(); + verify( mockedBoltStateHandler ).reset(); } @Test - public void verifyDelegationOfGetServerVersionMethod() throws CommandException { - CypherShell shell = new CypherShell(logger, mockedBoltStateHandler, mockedPrettyPrinter, new ShellParameterMap()); + public void verifyDelegationOfGetServerVersionMethod() throws CommandException + { + CypherShell shell = new CypherShell( logger, mockedBoltStateHandler, mockedPrettyPrinter, new ShellParameterMap() ); shell.getServerVersion(); - verify(mockedBoltStateHandler).getServerVersion(); + verify( mockedBoltStateHandler ).getServerVersion(); } @Test - public void verifyDelegationOfIsTransactionOpenMethod() throws CommandException { - CypherShell shell = new CypherShell(logger, mockedBoltStateHandler, mockedPrettyPrinter, new ShellParameterMap()); + public void verifyDelegationOfIsTransactionOpenMethod() throws CommandException + { + CypherShell shell = new CypherShell( logger, mockedBoltStateHandler, mockedPrettyPrinter, new ShellParameterMap() ); shell.isTransactionOpen(); - verify(mockedBoltStateHandler).isTransactionOpen(); + verify( mockedBoltStateHandler ).isTransactionOpen(); } @Test - public void verifyDelegationOfTransactionMethods() throws CommandException { - CypherShell shell = new CypherShell(logger, mockedBoltStateHandler, mockedPrettyPrinter, new ShellParameterMap()); + public void verifyDelegationOfTransactionMethods() throws CommandException + { + CypherShell shell = new CypherShell( logger, mockedBoltStateHandler, mockedPrettyPrinter, new ShellParameterMap() ); shell.beginTransaction(); - verify(mockedBoltStateHandler).beginTransaction(); + verify( mockedBoltStateHandler ).beginTransaction(); shell.commitTransaction(); - verify(mockedBoltStateHandler).commitTransaction(); + verify( mockedBoltStateHandler ).commitTransaction(); shell.rollbackTransaction(); - verify(mockedBoltStateHandler).rollbackTransaction(); + verify( mockedBoltStateHandler ).rollbackTransaction(); } @Test public void setWhenOfflineShouldWork() throws EvaluationException, CommandException { - CypherShell shell = new OfflineTestShell(logger, mockedBoltStateHandler, mockedPrettyPrinter); - when(mockedBoltStateHandler.isConnected()).thenReturn(false); - when(mockedBoltStateHandler.runCypher(anyString(), anyMap())).thenThrow(new CommandException("not connected")); + CypherShell shell = new OfflineTestShell( logger, mockedBoltStateHandler, mockedPrettyPrinter ); + when( mockedBoltStateHandler.isConnected() ).thenReturn( false ); + when( mockedBoltStateHandler.runCypher( anyString(), anyMap() ) ).thenThrow( new CommandException( "not connected" ) ); - Object result = shell.getParameterMap().setParameter("bob", "99"); - assertEquals(99L, result); + Object result = shell.getParameterMap().setParameter( "bob", "99" ); + assertEquals( 99L, result ); } @Test - public void executeOfflineThrows() throws CommandException { - thrown.expect(CommandException.class); - thrown.expectMessage("Not connected to Neo4j"); + public void executeOfflineThrows() throws CommandException + { + thrown.expect( CommandException.class ); + thrown.expectMessage( "Not connected to Neo4j" ); - OfflineTestShell shell = new OfflineTestShell(logger, mockedBoltStateHandler, mockedPrettyPrinter); - when(mockedBoltStateHandler.isConnected()).thenReturn(false); + OfflineTestShell shell = new OfflineTestShell( logger, mockedBoltStateHandler, mockedPrettyPrinter ); + when( mockedBoltStateHandler.isConnected() ).thenReturn( false ); - shell.execute("RETURN 999"); + shell.execute( "RETURN 999" ); } @Test - public void setParamShouldAddParamWithSpecialCharactersAndValue() throws EvaluationException, CommandException { - Value value = mock(Value.class); - Record recordMock = mock(Record.class); - BoltResult boltResult = new ListBoltResult(asList(recordMock), mock(ResultSummary.class)); + public void setParamShouldAddParamWithSpecialCharactersAndValue() throws EvaluationException, CommandException + { + Value value = mock( Value.class ); + Record recordMock = mock( Record.class ); + BoltResult boltResult = new ListBoltResult( asList( recordMock ), mock( ResultSummary.class ) ); - when(mockedBoltStateHandler.runCypher(anyString(), anyMap())).thenReturn(Optional.of(boltResult)); - when(recordMock.get("bo`b")).thenReturn(value); - when(value.asObject()).thenReturn("99"); + when( mockedBoltStateHandler.runCypher( anyString(), anyMap() ) ).thenReturn( Optional.of( boltResult ) ); + when( recordMock.get( "bo`b" ) ).thenReturn( value ); + when( value.asObject() ).thenReturn( "99" ); - assertTrue(offlineTestShell.getParameterMap().allParameterValues().isEmpty()); + assertTrue( offlineTestShell.getParameterMap().allParameterValues().isEmpty() ); - Object result = offlineTestShell.getParameterMap().setParameter("`bo``b`", "99"); - assertEquals(99L, result); - assertEquals(99L, offlineTestShell.getParameterMap().allParameterValues().get("bo`b")); + Object result = offlineTestShell.getParameterMap().setParameter( "`bo``b`", "99" ); + assertEquals( 99L, result ); + assertEquals( 99L, offlineTestShell.getParameterMap().allParameterValues().get( "bo`b" ) ); } @Test - public void setParamShouldAddParam() throws EvaluationException, CommandException { - Value value = mock(Value.class); - Record recordMock = mock(Record.class); - BoltResult boltResult = mock(ListBoltResult.class); + public void setParamShouldAddParam() throws EvaluationException, CommandException + { + Value value = mock( Value.class ); + Record recordMock = mock( Record.class ); + BoltResult boltResult = mock( ListBoltResult.class ); - when(mockedBoltStateHandler.runCypher(anyString(), anyMap())).thenReturn(Optional.of(boltResult)); - when(boltResult.getRecords()).thenReturn(asList(recordMock)); - when(recordMock.get("bob")).thenReturn(value); - when(value.asObject()).thenReturn("99"); + when( mockedBoltStateHandler.runCypher( anyString(), anyMap() ) ).thenReturn( Optional.of( boltResult ) ); + when( boltResult.getRecords() ).thenReturn( asList( recordMock ) ); + when( recordMock.get( "bob" ) ).thenReturn( value ); + when( value.asObject() ).thenReturn( "99" ); - assertTrue(offlineTestShell.getParameterMap().allParameterValues().isEmpty()); + assertTrue( offlineTestShell.getParameterMap().allParameterValues().isEmpty() ); - Object result = offlineTestShell.getParameterMap().setParameter("`bob`", "99"); - assertEquals(99L, result); - assertEquals(99L, offlineTestShell.getParameterMap().allParameterValues().get("bob")); + Object result = offlineTestShell.getParameterMap().setParameter( "`bob`", "99" ); + assertEquals( 99L, result ); + assertEquals( 99L, offlineTestShell.getParameterMap().allParameterValues().get( "bob" ) ); } @Test - public void executeShouldPrintResult() throws CommandException { - Driver mockedDriver = mock(Driver.class); - Session session = mock(Session.class); - BoltResult result = mock(ListBoltResult.class); - - BoltStateHandler boltStateHandler = mock(BoltStateHandler.class); - - when(boltStateHandler.isConnected()).thenReturn(true); - when(boltStateHandler.runCypher(anyString(), anyMap())).thenReturn(Optional.of(result)); - doAnswer((a) -> { ((LinePrinter)a.getArguments()[1]).printOut("999"); return null;}).when(mockedPrettyPrinter).format(any(BoltResult.class), anyObject()); - when(mockedDriver.session()).thenReturn(session); - - OfflineTestShell shell = new OfflineTestShell(logger, boltStateHandler, mockedPrettyPrinter); - shell.execute("RETURN 999"); - verify(logger).printOut(contains("999")); + public void executeShouldPrintResult() throws CommandException + { + Driver mockedDriver = mock( Driver.class ); + Session session = mock( Session.class ); + BoltResult result = mock( ListBoltResult.class ); + + BoltStateHandler boltStateHandler = mock( BoltStateHandler.class ); + + when( boltStateHandler.isConnected() ).thenReturn( true ); + when( boltStateHandler.runCypher( anyString(), anyMap() ) ).thenReturn( Optional.of( result ) ); + doAnswer( a -> + { + ((LinePrinter) a.getArguments()[1]).printOut( "999" ); + return null; + } ).when( mockedPrettyPrinter ).format( any( BoltResult.class ), anyObject() ); + when( mockedDriver.session() ).thenReturn( session ); + + OfflineTestShell shell = new OfflineTestShell( logger, boltStateHandler, mockedPrettyPrinter ); + shell.execute( "RETURN 999" ); + verify( logger ).printOut( contains( "999" ) ); } @Test - public void shouldStripEndingSemicolonsFromCommand() throws Exception { + public void shouldStripEndingSemicolonsFromCommand() throws Exception + { // Should not throw - offlineTestShell.getCommandExecutable(":help;;").get().execute(); - verify(logger).printOut(contains("Available commands:")); + offlineTestShell.getCommandExecutable( ":help;;" ).get().execute(); + verify( logger ).printOut( contains( "Available commands:" ) ); } @Test - public void shouldStripEndingSemicolonsFromCommandArgs() throws Exception { + public void shouldStripEndingSemicolonsFromCommandArgs() throws Exception + { // Should not throw - offlineTestShell.getCommandExecutable(":help param;;").get().execute(); - verify(logger).printOut(contains("usage: ")); + offlineTestShell.getCommandExecutable( ":help param;;" ).get().execute(); + verify( logger ).printOut( contains( "usage: " ) ); } @Test - public void testStripSemicolons() throws Exception { - assertEquals("", CypherShell.stripTrailingSemicolons("")); - assertEquals("nothing", CypherShell.stripTrailingSemicolons("nothing")); - assertEquals("", CypherShell.stripTrailingSemicolons(";;;;;")); - assertEquals("hej", CypherShell.stripTrailingSemicolons("hej;")); - assertEquals(";bob", CypherShell.stripTrailingSemicolons(";bob;;")); + public void testStripSemicolons() throws Exception + { + assertEquals( "", CypherShell.stripTrailingSemicolons( "" ) ); + assertEquals( "nothing", CypherShell.stripTrailingSemicolons( "nothing" ) ); + assertEquals( "", CypherShell.stripTrailingSemicolons( ";;;;;" ) ); + assertEquals( "hej", CypherShell.stripTrailingSemicolons( "hej;" ) ); + assertEquals( ";bob", CypherShell.stripTrailingSemicolons( ";bob;;" ) ); } @Test - public void shouldParseCommandsAndArgs() { - assertTrue(offlineTestShell.getCommandExecutable(":help").isPresent()); - assertTrue(offlineTestShell.getCommandExecutable(":help :param").isPresent()); - assertTrue(offlineTestShell.getCommandExecutable(":param \"A piece of string\"").isPresent()); - assertTrue(offlineTestShell.getCommandExecutable(":params").isPresent()); + public void shouldParseCommandsAndArgs() + { + assertTrue( offlineTestShell.getCommandExecutable( ":help" ).isPresent() ); + assertTrue( offlineTestShell.getCommandExecutable( ":help :param" ).isPresent() ); + assertTrue( offlineTestShell.getCommandExecutable( ":param \"A piece of string\"" ).isPresent() ); + assertTrue( offlineTestShell.getCommandExecutable( ":params" ).isPresent() ); } @Test - public void commandNameShouldBeParsed() { - assertTrue(offlineTestShell.getCommandExecutable(" :help ").isPresent()); - assertTrue(offlineTestShell.getCommandExecutable(" :help \n").isPresent()); - assertTrue(offlineTestShell.getCommandExecutable(" :help arg1 arg2 ").isPresent()); + public void commandNameShouldBeParsed() + { + assertTrue( offlineTestShell.getCommandExecutable( " :help " ).isPresent() ); + assertTrue( offlineTestShell.getCommandExecutable( " :help \n" ).isPresent() ); + assertTrue( offlineTestShell.getCommandExecutable( " :help arg1 arg2 " ).isPresent() ); } @Test - public void incorrectCommandsThrowException() throws CommandException { - thrown.expect(CommandException.class); - thrown.expectMessage("Incorrect number of arguments"); + public void incorrectCommandsThrowException() throws CommandException + { + thrown.expect( CommandException.class ); + thrown.expectMessage( "Incorrect number of arguments" ); - Optional exe = offlineTestShell.getCommandExecutable(" :help arg1 arg2 "); + Optional exe = offlineTestShell.getCommandExecutable( " :help arg1 arg2 " ); - offlineTestShell.executeCmd(exe.get()); + offlineTestShell.executeCmd( exe.get() ); } @Test - public void shouldReturnNothingOnStrangeCommand() { - Optional exe = offlineTestShell.getCommandExecutable(" :aklxjde arg1 arg2 "); + public void shouldReturnNothingOnStrangeCommand() + { + Optional exe = offlineTestShell.getCommandExecutable( " :aklxjde arg1 arg2 " ); - assertFalse(exe.isPresent()); + assertFalse( exe.isPresent() ); } - @Test - public void setParameterDoesNotTriggerByBoltError() throws EvaluationException, CommandException { + public void setParameterDoesNotTriggerByBoltError() throws EvaluationException, CommandException + { // given - when(mockedBoltStateHandler.runCypher(anyString(), anyMap())).thenReturn(Optional.empty()); - CypherShell shell = new CypherShell(logger, mockedBoltStateHandler, mockedPrettyPrinter, new ShellParameterMap()); + when( mockedBoltStateHandler.runCypher( anyString(), anyMap() ) ).thenReturn( Optional.empty() ); + CypherShell shell = new CypherShell( logger, mockedBoltStateHandler, mockedPrettyPrinter, new ShellParameterMap() ); // when - Object result = shell.getParameterMap().setParameter("bob", "99"); - assertEquals(99L, result); + Object result = shell.getParameterMap().setParameter( "bob", "99" ); + assertEquals( 99L, result ); } } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/HistorianTest.java b/cypher-shell/src/test/java/org/neo4j/shell/HistorianTest.java index 485d9182..4a5bf69a 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/HistorianTest.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/HistorianTest.java @@ -1,14 +1,33 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell; import org.junit.Test; import static org.junit.Assert.assertTrue; - -public class HistorianTest { +public class HistorianTest +{ @Test - public void getHistory() throws Exception { - assertTrue(Historian.empty.getHistory().isEmpty()); + public void getHistory() throws Exception + { + assertTrue( Historian.empty.getHistory().isEmpty() ); } - } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/MainTest.java b/cypher-shell/src/test/java/org/neo4j/shell/MainTest.java index a9af8010..a7316ad2 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/MainTest.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/MainTest.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell; import org.junit.Before; @@ -28,7 +47,8 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -public class MainTest { +public class MainTest +{ @Rule public final ExpectedException thrown = ExpectedException.none(); @@ -40,419 +60,460 @@ public class MainTest { private Neo4jException passwordChangeRequiredException; @Before - public void setup() { - out = mock(PrintStream.class); - shell = mock(CypherShell.class); - connectionConfig = mock(ConnectionConfig.class); + public void setup() + { + out = mock( PrintStream.class ); + shell = mock( CypherShell.class ); + connectionConfig = mock( ConnectionConfig.class ); - doReturn("").when(connectionConfig).username(); - doReturn("").when(connectionConfig).password(); + doReturn( "" ).when( connectionConfig ).username(); + doReturn( "" ).when( connectionConfig ).password(); // Don't mock because of gradle bug: https://github.com/gradle/gradle/issues/1618 - authException = new AuthenticationException(Main.NEO_CLIENT_ERROR_SECURITY_UNAUTHORIZED, "BOOM"); - passwordChangeRequiredException = new SecurityException("Neo.ClientError.Security.CredentialsExpired", "BLAM"); + authException = new AuthenticationException( Main.NEO_CLIENT_ERROR_SECURITY_UNAUTHORIZED, "BOOM" ); + passwordChangeRequiredException = new SecurityException( "Neo.ClientError.Security.CredentialsExpired", "BLAM" ); } @Test - public void nonEndedStringFails() throws Exception { + public void nonEndedStringFails() throws Exception + { String inputString = "no newline"; - InputStream inputStream = new ByteArrayInputStream(inputString.getBytes()); + InputStream inputStream = new ByteArrayInputStream( inputString.getBytes() ); - doThrow(authException).when(shell).connect(connectionConfig, null); + doThrow( authException ).when( shell ).connect( connectionConfig, null ); - thrown.expectMessage("No text could be read, exiting"); + thrown.expectMessage( "No text could be read, exiting" ); - Main main = new Main(inputStream, out); - main.connectMaybeInteractively(shell, connectionConfig, true, true, true); - verify(shell, times(1)).connect(connectionConfig, null); + Main main = new Main( inputStream, out ); + main.connectMaybeInteractively( shell, connectionConfig, true, true, true ); + verify( shell, times( 1 ) ).connect( connectionConfig, null ); } @Test - public void unrelatedErrorDoesNotPrompt() throws Exception { - doThrow(new RuntimeException("bla")).when(shell).connect(connectionConfig, null); + public void unrelatedErrorDoesNotPrompt() throws Exception + { + doThrow( new RuntimeException( "bla" ) ).when( shell ).connect( connectionConfig, null ); - thrown.expect(RuntimeException.class); - thrown.expectMessage("bla"); + thrown.expect( RuntimeException.class ); + thrown.expectMessage( "bla" ); - Main main = new Main(mock(InputStream.class), out); - main.connectMaybeInteractively(shell, connectionConfig, true, true, true); - verify(shell, times(1)).connect(connectionConfig, null); + Main main = new Main( mock( InputStream.class ), out ); + main.connectMaybeInteractively( shell, connectionConfig, true, true, true ); + verify( shell, times( 1 ) ).connect( connectionConfig, null ); } @Test - public void promptsForUsernameAndPasswordIfNoneGivenIfInteractive() throws Exception { - doThrow(authException).doNothing().when(shell).connect(connectionConfig, null); + public void promptsForUsernameAndPasswordIfNoneGivenIfInteractive() throws Exception + { + doThrow( authException ).doNothing().when( shell ).connect( connectionConfig, null ); String inputString = "bob\nsecret\n"; - InputStream inputStream = new ByteArrayInputStream(inputString.getBytes()); + InputStream inputStream = new ByteArrayInputStream( inputString.getBytes() ); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - PrintStream ps = new PrintStream(baos); + PrintStream ps = new PrintStream( baos ); - Main main = new Main(inputStream, ps); - main.connectMaybeInteractively(shell, connectionConfig, true, true, true); + Main main = new Main( inputStream, ps ); + main.connectMaybeInteractively( shell, connectionConfig, true, true, true ); - String out = new String(baos.toByteArray(), StandardCharsets.UTF_8); + String out = new String( baos.toByteArray(), StandardCharsets.UTF_8 ); - assertEquals(String.format( "username: bob%npassword: ******%n" ), out); - verify(connectionConfig).setUsername("bob"); - verify(connectionConfig).setPassword("secret"); - verify(shell, times(2)).connect(connectionConfig, null); + assertEquals( String.format( "username: bob%npassword: ******%n" ), out ); + verify( connectionConfig ).setUsername( "bob" ); + verify( connectionConfig ).setPassword( "secret" ); + verify( shell, times( 2 ) ).connect( connectionConfig, null ); } @Test - public void promptsSilentlyForUsernameAndPasswordIfNoneGivenIfOutputRedirected() throws Exception { - if (Utils.isWindows()) { + public void promptsSilentlyForUsernameAndPasswordIfNoneGivenIfOutputRedirected() throws Exception + { + if ( Utils.isWindows() ) + { // Disable this test on Windows due to problem with redirection return; } - doThrow(authException).doNothing().when(shell).connect(connectionConfig, null); - doReturn("").doReturn("secret").when(connectionConfig).password(); + doThrow( authException ).doNothing().when( shell ).connect( connectionConfig, null ); + doReturn( "" ).doReturn( "secret" ).when( connectionConfig ).password(); String inputString = "bob\nsecret\n"; - InputStream inputStream = new ByteArrayInputStream(inputString.getBytes()); + InputStream inputStream = new ByteArrayInputStream( inputString.getBytes() ); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - PrintStream ps = new PrintStream(baos); + PrintStream ps = new PrintStream( baos ); // Redirect stdin and stdout InputStream stdIn = System.in; PrintStream stdOut = System.out; - System.setIn(inputStream); - System.setOut(ps); + System.setIn( inputStream ); + System.setOut( ps ); - try { + try + { Main main = new Main(); - main.connectMaybeInteractively(shell, connectionConfig, true, false, true); + main.connectMaybeInteractively( shell, connectionConfig, true, false, true ); - String out = new String(baos.toByteArray(), StandardCharsets.UTF_8); + String out = new String( baos.toByteArray(), StandardCharsets.UTF_8 ); - assertEquals("", out); - verify(connectionConfig).setUsername("bob"); - verify(connectionConfig).setPassword("secret"); - verify(shell, times(2)).connect(connectionConfig, null); - } finally { - System.setIn(stdIn); - System.setOut(stdOut); + assertEquals( "", out ); + verify( connectionConfig ).setUsername( "bob" ); + verify( connectionConfig ).setPassword( "secret" ); + verify( shell, times( 2 ) ).connect( connectionConfig, null ); + } + finally + { + System.setIn( stdIn ); + System.setOut( stdOut ); } } @Test - public void doesNotPromptIfInputRedirected() throws Exception { - doThrow(authException).doNothing().when(shell).connect(connectionConfig, null); + public void doesNotPromptIfInputRedirected() throws Exception + { + doThrow( authException ).doNothing().when( shell ).connect( connectionConfig, null ); String inputString = "bob\nsecret\n"; - InputStream inputStream = new ByteArrayInputStream(inputString.getBytes()); + InputStream inputStream = new ByteArrayInputStream( inputString.getBytes() ); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - PrintStream ps = new PrintStream(baos); + PrintStream ps = new PrintStream( baos ); - Main main = new Main(inputStream, ps); + Main main = new Main( inputStream, ps ); - try { - main.connectMaybeInteractively(shell, connectionConfig, false, true, true); - fail("Expected auth exception"); - } catch (AuthenticationException e) { - verify(shell, times(1)).connect(connectionConfig, null); + try + { + main.connectMaybeInteractively( shell, connectionConfig, false, true, true ); + fail( "Expected auth exception" ); + } + catch ( AuthenticationException e ) + { + verify( shell, times( 1 ) ).connect( connectionConfig, null ); } } @Test - public void promptsForUserIfPassExistsIfInteractive() throws Exception { - doThrow(authException).doNothing().when(shell).connect(connectionConfig, null); - doReturn("secret").when(connectionConfig).password(); + public void promptsForUserIfPassExistsIfInteractive() throws Exception + { + doThrow( authException ).doNothing().when( shell ).connect( connectionConfig, null ); + doReturn( "secret" ).when( connectionConfig ).password(); String inputString = "bob\n"; - InputStream inputStream = new ByteArrayInputStream(inputString.getBytes()); + InputStream inputStream = new ByteArrayInputStream( inputString.getBytes() ); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - PrintStream ps = new PrintStream(baos); + PrintStream ps = new PrintStream( baos ); - Main main = new Main(inputStream, ps); - main.connectMaybeInteractively(shell, connectionConfig, true, true, true); + Main main = new Main( inputStream, ps ); + main.connectMaybeInteractively( shell, connectionConfig, true, true, true ); - String out = new String(baos.toByteArray(), StandardCharsets.UTF_8); + String out = new String( baos.toByteArray(), StandardCharsets.UTF_8 ); - assertEquals(out, String.format( "username: bob%n" )); - verify(connectionConfig).setUsername("bob"); - verify(shell, times(2)).connect(connectionConfig, null); + assertEquals( out, String.format( "username: bob%n" ) ); + verify( connectionConfig ).setUsername( "bob" ); + verify( shell, times( 2 ) ).connect( connectionConfig, null ); } @Test - public void promptsSilentlyForUserIfPassExistsIfOutputRedirected() throws Exception { - if (Utils.isWindows()) { + public void promptsSilentlyForUserIfPassExistsIfOutputRedirected() throws Exception + { + if ( Utils.isWindows() ) + { // Disable this test on Windows due to problem with redirection return; } - doThrow(authException).doNothing().when(shell).connect(connectionConfig, null); - doReturn("secret").when(connectionConfig).password(); + doThrow( authException ).doNothing().when( shell ).connect( connectionConfig, null ); + doReturn( "secret" ).when( connectionConfig ).password(); String inputString = "bob\n"; - InputStream inputStream = new ByteArrayInputStream(inputString.getBytes()); + InputStream inputStream = new ByteArrayInputStream( inputString.getBytes() ); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - PrintStream ps = new PrintStream(baos); + PrintStream ps = new PrintStream( baos ); // Redirect stdin and stdout InputStream stdIn = System.in; PrintStream stdOut = System.out; - System.setIn(inputStream); - System.setOut(ps); + System.setIn( inputStream ); + System.setOut( ps ); - try { + try + { Main main = new Main(); - main.connectMaybeInteractively(shell, connectionConfig, true, false, true); + main.connectMaybeInteractively( shell, connectionConfig, true, false, true ); - String out = new String(baos.toByteArray(), StandardCharsets.UTF_8); + String out = new String( baos.toByteArray(), StandardCharsets.UTF_8 ); - assertEquals(out, ""); - verify(connectionConfig).setUsername("bob"); - verify(shell, times(2)).connect(connectionConfig, null); - } finally { - System.setIn(stdIn); - System.setOut(stdOut); + assertEquals( out, "" ); + verify( connectionConfig ).setUsername( "bob" ); + verify( shell, times( 2 ) ).connect( connectionConfig, null ); + } + finally + { + System.setIn( stdIn ); + System.setOut( stdOut ); } } @Test - public void promptsForPassBeforeConnectIfUserExistsIfInteractive() throws Exception { - doReturn("bob").when(connectionConfig).username(); + public void promptsForPassBeforeConnectIfUserExistsIfInteractive() throws Exception + { + doReturn( "bob" ).when( connectionConfig ).username(); String inputString = "secret\n"; - InputStream inputStream = new ByteArrayInputStream(inputString.getBytes()); + InputStream inputStream = new ByteArrayInputStream( inputString.getBytes() ); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - PrintStream ps = new PrintStream(baos); + PrintStream ps = new PrintStream( baos ); - Main main = new Main(inputStream, ps); - main.connectMaybeInteractively(shell, connectionConfig, true, true, true); + Main main = new Main( inputStream, ps ); + main.connectMaybeInteractively( shell, connectionConfig, true, true, true ); - String out = new String(baos.toByteArray(), StandardCharsets.UTF_8); + String out = new String( baos.toByteArray(), StandardCharsets.UTF_8 ); - assertEquals(out, String.format("password: ******%n")); - verify(connectionConfig).setPassword("secret"); - verify(shell, times(1)).connect(connectionConfig, null); + assertEquals( out, String.format( "password: ******%n" ) ); + verify( connectionConfig ).setPassword( "secret" ); + verify( shell, times( 1 ) ).connect( connectionConfig, null ); } @Test - public void promptsSilentlyForPassIfUserExistsIfOutputRedirected() throws Exception { - if (Utils.isWindows()) { + public void promptsSilentlyForPassIfUserExistsIfOutputRedirected() throws Exception + { + if ( Utils.isWindows() ) + { // Disable this test on Windows due to problem with redirection return; } - doReturn("bob").when(connectionConfig).username(); - doReturn("").doReturn("").doReturn("secret").when(connectionConfig).password(); + doReturn( "bob" ).when( connectionConfig ).username(); + doReturn( "" ).doReturn( "" ).doReturn( "secret" ).when( connectionConfig ).password(); String inputString = "secret\n"; - InputStream inputStream = new ByteArrayInputStream(inputString.getBytes()); + InputStream inputStream = new ByteArrayInputStream( inputString.getBytes() ); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - PrintStream ps = new PrintStream(baos); + PrintStream ps = new PrintStream( baos ); // Redirect stdin and stdout InputStream stdIn = System.in; PrintStream stdOut = System.out; - System.setIn(inputStream); - System.setOut(ps); + System.setIn( inputStream ); + System.setOut( ps ); - try { + try + { Main main = new Main(); - main.connectMaybeInteractively(shell, connectionConfig, true, false, true); + main.connectMaybeInteractively( shell, connectionConfig, true, false, true ); - String out = new String(baos.toByteArray(), StandardCharsets.UTF_8); + String out = new String( baos.toByteArray(), StandardCharsets.UTF_8 ); - assertEquals(out, ""); - verify(connectionConfig).setPassword("secret"); - verify(shell, times(1)).connect(connectionConfig, null); - } finally { - System.setIn(stdIn); - System.setOut(stdOut); + assertEquals( out, "" ); + verify( connectionConfig ).setPassword( "secret" ); + verify( shell, times( 1 ) ).connect( connectionConfig, null ); + } + finally + { + System.setIn( stdIn ); + System.setOut( stdOut ); } } @Test - public void promptsForNewPasswordIfPasswordChangeRequired() throws Exception { + public void promptsForNewPasswordIfPasswordChangeRequired() throws Exception + { // Use a real ConnectionConfig instead of the mock in this test - ConnectionConfig connectionConfig = new ConnectionConfig("", "", 0, "", "", Encryption.DEFAULT, ""); - doThrow(authException).doThrow(passwordChangeRequiredException).doNothing().when(shell).connect(connectionConfig, null); + ConnectionConfig connectionConfig = new ConnectionConfig( "", "", 0, "", "", Encryption.DEFAULT, "" ); + doThrow( authException ).doThrow( passwordChangeRequiredException ).doNothing().when( shell ).connect( connectionConfig, null ); String inputString = "bob\nsecret\nnewsecret\n"; - InputStream inputStream = new ByteArrayInputStream(inputString.getBytes()); + InputStream inputStream = new ByteArrayInputStream( inputString.getBytes() ); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - PrintStream ps = new PrintStream(baos); + PrintStream ps = new PrintStream( baos ); - Main main = new Main(inputStream, ps); - main.connectMaybeInteractively(shell, connectionConfig, true, true, true); + Main main = new Main( inputStream, ps ); + main.connectMaybeInteractively( shell, connectionConfig, true, true, true ); - String out = new String(baos.toByteArray(), StandardCharsets.UTF_8); + String out = new String( baos.toByteArray(), StandardCharsets.UTF_8 ); - assertEquals(String.format( "username: bob%npassword: ******%nPassword change required%nnew password: *********%n" ), out); - assertEquals("bob", connectionConfig.username()); - assertEquals("secret", connectionConfig.password()); - assertEquals("newsecret", connectionConfig.newPassword()); - verify(shell, times(3)).connect(connectionConfig, null); - verify(shell).changePassword(connectionConfig); + assertEquals( String.format( "username: bob%npassword: ******%nPassword change required%nnew password: *********%n" ), out ); + assertEquals( "bob", connectionConfig.username() ); + assertEquals( "secret", connectionConfig.password() ); + assertEquals( "newsecret", connectionConfig.newPassword() ); + verify( shell, times( 3 ) ).connect( connectionConfig, null ); + verify( shell ).changePassword( connectionConfig ); } @Test - public void promptsForNewPasswordIfPasswordChangeRequiredCannotBeEmpty() throws Exception { + public void promptsForNewPasswordIfPasswordChangeRequiredCannotBeEmpty() throws Exception + { // Use a real ConnectionConfig instead of the mock in this test - ConnectionConfig connectionConfig = new ConnectionConfig("", "", 0, "", "", Encryption.DEFAULT, ""); - doThrow(authException).doThrow(passwordChangeRequiredException).doNothing().when(shell).connect(connectionConfig, null); + ConnectionConfig connectionConfig = new ConnectionConfig( "", "", 0, "", "", Encryption.DEFAULT, "" ); + doThrow( authException ).doThrow( passwordChangeRequiredException ).doNothing().when( shell ).connect( connectionConfig, null ); String inputString = "bob\nsecret\n\nnewsecret\n"; - InputStream inputStream = new ByteArrayInputStream(inputString.getBytes()); + InputStream inputStream = new ByteArrayInputStream( inputString.getBytes() ); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - PrintStream ps = new PrintStream(baos); + PrintStream ps = new PrintStream( baos ); - Main main = new Main(inputStream, ps); - main.connectMaybeInteractively(shell, connectionConfig, true, true, true); + Main main = new Main( inputStream, ps ); + main.connectMaybeInteractively( shell, connectionConfig, true, true, true ); - String out = new String(baos.toByteArray(), StandardCharsets.UTF_8); + String out = new String( baos.toByteArray(), StandardCharsets.UTF_8 ); - assertEquals(String.format("username: bob%npassword: ******%nPassword change required%nnew password: %nnew password cannot be empty%n%nnew password: *********%n" ), out); - assertEquals("bob", connectionConfig.username()); - assertEquals("secret", connectionConfig.password()); - assertEquals("newsecret", connectionConfig.newPassword()); - verify(shell, times(3)).connect(connectionConfig, null); - verify(shell).changePassword(connectionConfig); + assertEquals( String.format( + "username: bob%npassword: ******%nPassword change required%nnew password: %nnew password cannot be empty%n%nnew password: *********%n" ), out ); + assertEquals( "bob", connectionConfig.username() ); + assertEquals( "secret", connectionConfig.password() ); + assertEquals( "newsecret", connectionConfig.newPassword() ); + verify( shell, times( 3 ) ).connect( connectionConfig, null ); + verify( shell ).changePassword( connectionConfig ); } @Test - public void promptsHandlesBang() throws Exception { - doThrow(authException).doNothing().when(shell).connect(connectionConfig, null); + public void promptsHandlesBang() throws Exception + { + doThrow( authException ).doNothing().when( shell ).connect( connectionConfig, null ); String inputString = "bo!b\nsec!ret\n"; - InputStream inputStream = new ByteArrayInputStream(inputString.getBytes()); + InputStream inputStream = new ByteArrayInputStream( inputString.getBytes() ); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - PrintStream ps = new PrintStream(baos); + PrintStream ps = new PrintStream( baos ); - Main main = new Main(inputStream, ps); - main.connectMaybeInteractively(shell, connectionConfig, true, true, true); + Main main = new Main( inputStream, ps ); + main.connectMaybeInteractively( shell, connectionConfig, true, true, true ); - String out = new String(baos.toByteArray(), StandardCharsets.UTF_8); + String out = new String( baos.toByteArray(), StandardCharsets.UTF_8 ); - assertEquals(String.format("username: bo!b%npassword: *******%n"), out); - verify(connectionConfig).setUsername("bo!b"); - verify(connectionConfig).setPassword("sec!ret"); - verify(shell, times(2)).connect(connectionConfig, null); + assertEquals( String.format( "username: bo!b%npassword: *******%n" ), out ); + verify( connectionConfig ).setUsername( "bo!b" ); + verify( connectionConfig ).setPassword( "sec!ret" ); + verify( shell, times( 2 ) ).connect( connectionConfig, null ); } @Test - public void triesOnlyOnceIfUserPassExists() throws Exception { - doThrow(authException).doThrow(new RuntimeException("second try")).when(shell).connect(connectionConfig, null); - doReturn("bob").when(connectionConfig).username(); - doReturn("secret").when(connectionConfig).password(); + public void triesOnlyOnceIfUserPassExists() throws Exception + { + doThrow( authException ).doThrow( new RuntimeException( "second try" ) ).when( shell ).connect( connectionConfig, null ); + doReturn( "bob" ).when( connectionConfig ).username(); + doReturn( "secret" ).when( connectionConfig ).password(); - InputStream inputStream = new ByteArrayInputStream("".getBytes()); + InputStream inputStream = new ByteArrayInputStream( "".getBytes() ); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - PrintStream ps = new PrintStream(baos); + PrintStream ps = new PrintStream( baos ); - Main main = new Main(inputStream, ps); + Main main = new Main( inputStream, ps ); - try { - main.connectMaybeInteractively(shell, connectionConfig, true, true, true); - fail("Expected an exception"); - } catch (Neo4jException e) { - assertEquals(authException.code(), e.code()); - verify(shell, times(1)).connect(connectionConfig, null); + try + { + main.connectMaybeInteractively( shell, connectionConfig, true, true, true ); + fail( "Expected an exception" ); + } + catch ( Neo4jException e ) + { + assertEquals( authException.code(), e.code() ); + verify( shell, times( 1 ) ).connect( connectionConfig, null ); } } @Test - public void repromptsIfUserIsNotProvidedIfInteractive() throws Exception { - doThrow(authException).doNothing().when(shell).connect(connectionConfig, null); + public void repromptsIfUserIsNotProvidedIfInteractive() throws Exception + { + doThrow( authException ).doNothing().when( shell ).connect( connectionConfig, null ); String inputString = "\nbob\nsecret\n"; - InputStream inputStream = new ByteArrayInputStream(inputString.getBytes()); + InputStream inputStream = new ByteArrayInputStream( inputString.getBytes() ); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - PrintStream ps = new PrintStream(baos); + PrintStream ps = new PrintStream( baos ); - Main main = new Main(inputStream, ps); - main.connectMaybeInteractively(shell, connectionConfig, true, true, true); + Main main = new Main( inputStream, ps ); + main.connectMaybeInteractively( shell, connectionConfig, true, true, true ); - String out = new String(baos.toByteArray(), StandardCharsets.UTF_8); + String out = new String( baos.toByteArray(), StandardCharsets.UTF_8 ); - assertEquals(String.format( "username: %nusername cannot be empty%n%nusername: bob%npassword: ******%n"), out ); - verify(connectionConfig).setUsername("bob"); - verify(connectionConfig).setPassword("secret"); - verify(shell, times(2)).connect(connectionConfig, null); + assertEquals( String.format( "username: %nusername cannot be empty%n%nusername: bob%npassword: ******%n" ), out ); + verify( connectionConfig ).setUsername( "bob" ); + verify( connectionConfig ).setPassword( "secret" ); + verify( shell, times( 2 ) ).connect( connectionConfig, null ); } @Test - public void doesNotRepromptIfUserIsNotProvidedIfOutputRedirected() throws Exception { - if (Utils.isWindows()) { + public void doesNotRepromptIfUserIsNotProvidedIfOutputRedirected() throws Exception + { + if ( Utils.isWindows() ) + { // Disable this test on Windows due to problem with redirection return; } - doThrow(authException).doNothing().when(shell).connect(connectionConfig, null); + doThrow( authException ).doNothing().when( shell ).connect( connectionConfig, null ); String inputString = "\nsecret\n"; - InputStream inputStream = new ByteArrayInputStream(inputString.getBytes()); + InputStream inputStream = new ByteArrayInputStream( inputString.getBytes() ); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - PrintStream ps = new PrintStream(baos); + PrintStream ps = new PrintStream( baos ); // Redirect stdin and stdout InputStream stdIn = System.in; PrintStream stdOut = System.out; - System.setIn(inputStream); - System.setOut(ps); + System.setIn( inputStream ); + System.setOut( ps ); - try { + try + { Main main = new Main(); - main.connectMaybeInteractively(shell, connectionConfig, true, false, true); + main.connectMaybeInteractively( shell, connectionConfig, true, false, true ); - String out = new String(baos.toByteArray(), StandardCharsets.UTF_8); + String out = new String( baos.toByteArray(), StandardCharsets.UTF_8 ); - assertEquals("", out ); - verify(connectionConfig).setUsername(""); - verify(connectionConfig).setPassword("secret"); - verify(shell, times(2)).connect(connectionConfig, null); - } finally { - System.setIn(stdIn); - System.setOut(stdOut); + assertEquals( "", out ); + verify( connectionConfig ).setUsername( "" ); + verify( connectionConfig ).setPassword( "secret" ); + verify( shell, times( 2 ) ).connect( connectionConfig, null ); + } + finally + { + System.setIn( stdIn ); + System.setOut( stdOut ); } } @Test - public void printsVersionAndExits() { + public void printsVersionAndExits() + { CliArgs args = new CliArgs(); - args.setVersion(true); + args.setVersion( true ); - PrintStream printStream = mock(PrintStream.class); + PrintStream printStream = mock( PrintStream.class ); - Main main = new Main(System.in, printStream); - main.startShell(args); + Main main = new Main( System.in, printStream ); + main.startShell( args ); - ArgumentCaptor argument = ArgumentCaptor.forClass(String.class); + ArgumentCaptor argument = ArgumentCaptor.forClass( String.class ); - verify(printStream).println(argument.capture()); - assertTrue(argument.getValue().matches("Cypher-Shell \\d+\\.\\d+\\.\\d+.*")); + verify( printStream ).println( argument.capture() ); + assertTrue( argument.getValue().matches( "Cypher-Shell \\d+\\.\\d+\\.\\d+.*" ) ); } @Test - public void printsDriverVersionAndExits() { + public void printsDriverVersionAndExits() + { CliArgs args = new CliArgs(); - args.setDriverVersion(true); + args.setDriverVersion( true ); - PrintStream printStream = mock(PrintStream.class); + PrintStream printStream = mock( PrintStream.class ); - Main main = new Main(System.in, printStream); - main.startShell(args); + Main main = new Main( System.in, printStream ); + main.startShell( args ); - ArgumentCaptor argument = ArgumentCaptor.forClass(String.class); + ArgumentCaptor argument = ArgumentCaptor.forClass( String.class ); - verify(printStream).println(argument.capture()); - assertTrue(argument.getValue().matches("Neo4j Driver \\d+\\.\\d+\\.\\d+.*")); + verify( printStream ).println( argument.capture() ); + assertTrue( argument.getValue().matches( "Neo4j Driver \\d+\\.\\d+\\.\\d+.*" ) ); } } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/OfflineTestShell.java b/cypher-shell/src/test/java/org/neo4j/shell/OfflineTestShell.java index 7af1bfb7..1a05854f 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/OfflineTestShell.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/OfflineTestShell.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell; import org.neo4j.shell.log.Logger; @@ -5,18 +24,20 @@ import org.neo4j.shell.state.BoltStateHandler; /** - * This class initializes a {@link CypherShell} with a fake - * {@link org.neo4j.shell.state.BoltStateHandler} which allows for faked sessions and faked results to test some basic - * shell functionality without requiring a full integration test. + * This class initializes a {@link CypherShell} with a fake {@link org.neo4j.shell.state.BoltStateHandler} which allows for faked sessions and faked results to + * test some basic shell functionality without requiring a full integration test. */ -public class OfflineTestShell extends CypherShell { +public class OfflineTestShell extends CypherShell +{ - public OfflineTestShell(Logger logger, BoltStateHandler boltStateHandler, PrettyPrinter prettyPrinter) { - super(logger, boltStateHandler, prettyPrinter, new ShellParameterMap()); + public OfflineTestShell( Logger logger, BoltStateHandler boltStateHandler, PrettyPrinter prettyPrinter ) + { + super( logger, boltStateHandler, prettyPrinter, new ShellParameterMap() ); } @Override - protected void addRuntimeHookToResetShell() { + protected void addRuntimeHookToResetShell() + { //Do Nothing } } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/ShellParameterMapTest.java b/cypher-shell/src/test/java/org/neo4j/shell/ShellParameterMapTest.java index d9d34b4d..7acae754 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/ShellParameterMapTest.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/ShellParameterMapTest.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell; import org.junit.Before; @@ -9,39 +28,43 @@ import static junit.framework.TestCase.assertTrue; import static org.junit.Assert.assertEquals; -@SuppressWarnings("OptionalGetWithoutIsPresent") +@SuppressWarnings( "OptionalGetWithoutIsPresent" ) public class ShellParameterMapTest { private ParameterMap parameterMap; @Before - public void setup() { + public void setup() + { parameterMap = new ShellParameterMap(); } - @Test - public void newParamMapShouldBeEmpty() { - assertTrue(parameterMap.allParameterValues().isEmpty()); + public void newParamMapShouldBeEmpty() + { + assertTrue( parameterMap.allParameterValues().isEmpty() ); } @Test - public void setParamShouldAddParamWithSpecialCharactersAndValue() throws EvaluationException { - Object result = parameterMap.setParameter("`bo``b`", "99"); - assertEquals(99L, result); - assertEquals(99L, parameterMap.allParameterValues().get("bo`b")); + public void setParamShouldAddParamWithSpecialCharactersAndValue() throws EvaluationException + { + Object result = parameterMap.setParameter( "`bo``b`", "99" ); + assertEquals( 99L, result ); + assertEquals( 99L, parameterMap.allParameterValues().get( "bo`b" ) ); } @Test - public void setParamShouldAddParam() throws EvaluationException { - Object result = parameterMap.setParameter("`bob`", "99"); - assertEquals(99L, result); - assertEquals(99L, parameterMap.allParameterValues().get("bob")); + public void setParamShouldAddParam() throws EvaluationException + { + Object result = parameterMap.setParameter( "`bob`", "99" ); + assertEquals( 99L, result ); + assertEquals( 99L, parameterMap.allParameterValues().get( "bob" ) ); } @Test - public void getUserInput() throws EvaluationException { - parameterMap.setParameter("`bob`", "99"); - assertEquals( new ParamValue( "99", 99L ), parameterMap.getAllAsUserInput().get("bob")); + public void getUserInput() throws EvaluationException + { + parameterMap.setParameter( "`bob`", "99" ); + assertEquals( new ParamValue( "99", 99L ), parameterMap.getAllAsUserInput().get( "bob" ) ); } } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/ShellRunnerTest.java b/cypher-shell/src/test/java/org/neo4j/shell/ShellRunnerTest.java index 1a43d4c6..60c0ef7d 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/ShellRunnerTest.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/ShellRunnerTest.java @@ -1,8 +1,28 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; + import org.neo4j.shell.cli.CliArgs; import org.neo4j.shell.cli.NonInteractiveShellRunner; import org.neo4j.shell.log.Logger; @@ -11,17 +31,19 @@ import static org.mockito.Mockito.mock; import static org.neo4j.shell.ShellRunner.getShellRunner; -public class ShellRunnerTest { +public class ShellRunnerTest +{ @Rule public final ExpectedException thrown = ExpectedException.none(); - private final ConnectionConfig connectionConfig = mock(ConnectionConfig.class); + private final ConnectionConfig connectionConfig = mock( ConnectionConfig.class ); @Test - public void inputIsNonInteractiveIfForced() throws Exception { + public void inputIsNonInteractiveIfForced() throws Exception + { CliArgs args = new CliArgs(); - args.setNonInteractive(true); - ShellRunner runner = getShellRunner(args, mock(CypherShell.class), mock(Logger.class), connectionConfig); - assertTrue("Should be non-interactive shell runner when forced", - runner instanceof NonInteractiveShellRunner); + args.setNonInteractive( true ); + ShellRunner runner = getShellRunner( args, mock( CypherShell.class ), mock( Logger.class ), connectionConfig ); + assertTrue( "Should be non-interactive shell runner when forced", + runner instanceof NonInteractiveShellRunner ); } } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/UserMessagesHandlerTest.java b/cypher-shell/src/test/java/org/neo4j/shell/UserMessagesHandlerTest.java index d5b6f089..d8eb5cf0 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/UserMessagesHandlerTest.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/UserMessagesHandlerTest.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell; import org.junit.Test; @@ -6,27 +25,30 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -public class UserMessagesHandlerTest { - private final ConnectionConfig connectionConfig = mock(ConnectionConfig.class); +public class UserMessagesHandlerTest +{ + private final ConnectionConfig connectionConfig = mock( ConnectionConfig.class ); @Test - public void welcomeMessageTest() { - when(connectionConfig.username()).thenReturn("bob"); - when(connectionConfig.driverUrl()).thenReturn("bolt://some.place.com:99"); + public void welcomeMessageTest() + { + when( connectionConfig.username() ).thenReturn( "bob" ); + when( connectionConfig.driverUrl() ).thenReturn( "bolt://some.place.com:99" ); - UserMessagesHandler userMessagesHandler = new UserMessagesHandler(connectionConfig, "3.1.0-Beta99"); - assertEquals("Connected to Neo4j 3.1.0-Beta99 at @|BOLD bolt://some.place.com:99|@ as user @|BOLD bob|@.\n" + - "Type @|BOLD :help|@ for a list of available commands or @|BOLD :exit|@ to exit the shell.\n" + - "Note that Cypher queries must end with a @|BOLD semicolon.|@", - userMessagesHandler.getWelcomeMessage()); + UserMessagesHandler userMessagesHandler = new UserMessagesHandler( connectionConfig, "3.1.0-Beta99" ); + assertEquals( "Connected to Neo4j 3.1.0-Beta99 at @|BOLD bolt://some.place.com:99|@ as user @|BOLD bob|@.\n" + + "Type @|BOLD :help|@ for a list of available commands or @|BOLD :exit|@ to exit the shell.\n" + + "Note that Cypher queries must end with a @|BOLD semicolon.|@", + userMessagesHandler.getWelcomeMessage() ); } @Test - public void exitMessageTest() { - when(connectionConfig.username()).thenReturn("bob"); - when(connectionConfig.driverUrl()).thenReturn("bolt://some.place.com:99"); + public void exitMessageTest() + { + when( connectionConfig.username() ).thenReturn( "bob" ); + when( connectionConfig.driverUrl() ).thenReturn( "bolt://some.place.com:99" ); - UserMessagesHandler userMessagesHandler = new UserMessagesHandler(connectionConfig, "3.1.0-Beta99"); - assertEquals("\nBye!", userMessagesHandler.getExitMessage()); + UserMessagesHandler userMessagesHandler = new UserMessagesHandler( connectionConfig, "3.1.0-Beta99" ); + assertEquals( "\nBye!", userMessagesHandler.getExitMessage() ); } } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/build/BuildTest.java b/cypher-shell/src/test/java/org/neo4j/shell/build/BuildTest.java index c10e57b6..6a493db8 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/build/BuildTest.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/build/BuildTest.java @@ -1,18 +1,39 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.build; import org.junit.Test; import static org.junit.Assert.assertTrue; - -public class BuildTest { +public class BuildTest +{ @Test - public void versionIsNumeric() throws Exception { - assertTrue(Build.version().matches("\\d+\\.\\d+\\.\\d+.*")); + public void versionIsNumeric() throws Exception + { + assertTrue( Build.version().matches( "\\d+\\.\\d+\\.\\d+.*" ) ); } @Test - public void neo4jDriverVersionIsNumeric() throws Exception { - assertTrue(Build.driverVersion().matches("\\d+\\.\\d+\\.\\d+.*")); + public void neo4jDriverVersionIsNumeric() throws Exception + { + assertTrue( Build.driverVersion().matches( "\\d+\\.\\d+\\.\\d+.*" ) ); } } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/cli/CliArgHelperTest.java b/cypher-shell/src/test/java/org/neo4j/shell/cli/CliArgHelperTest.java index c4b9f292..5c8806df 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/cli/CliArgHelperTest.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/cli/CliArgHelperTest.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.cli; import net.sourceforge.argparse4j.inf.ArgumentParserException; @@ -22,7 +41,8 @@ import static org.mockito.Mockito.mock; import static org.neo4j.shell.test.Util.asArray; -public class CliArgHelperTest { +public class CliArgHelperTest +{ @Rule public final ExpectedException thrown = ExpectedException.none(); @@ -30,129 +50,148 @@ public class CliArgHelperTest { private PrintStream mockedStdErr; @Before - public void setup() { - mockedStdErr = mock(PrintStream.class); + public void setup() + { + mockedStdErr = mock( PrintStream.class ); } @Test - public void testForceNonInteractiveIsNotDefault() { - assertFalse("Force non-interactive should not be the default mode", - CliArgHelper.parse(asArray()).getNonInteractive()); + public void testForceNonInteractiveIsNotDefault() + { + assertFalse( "Force non-interactive should not be the default mode", + CliArgHelper.parse( asArray() ).getNonInteractive() ); } @Test - public void testForceNonInteractiveIsParsed() { - assertTrue("Force non-interactive should have been parsed to true", - CliArgHelper.parse(asArray("--non-interactive")).getNonInteractive()); + public void testForceNonInteractiveIsParsed() + { + assertTrue( "Force non-interactive should have been parsed to true", + CliArgHelper.parse( asArray( "--non-interactive" ) ).getNonInteractive() ); } @Test - public void testNumSampleRows() { - assertEquals("sample-rows 200", 200, CliArgHelper.parse("--sample-rows 200".split(" ")).getNumSampleRows()); - assertNull("invalid sample-rows", CliArgHelper.parse("--sample-rows 0".split(" "))); - assertNull("invalid sample-rows", CliArgHelper.parse("--sample-rows -1".split(" "))); - assertNull("invalid sample-rows", CliArgHelper.parse("--sample-rows foo".split(" "))); + public void testNumSampleRows() + { + assertEquals( "sample-rows 200", 200, CliArgHelper.parse( "--sample-rows 200".split( " " ) ).getNumSampleRows() ); + assertNull( "invalid sample-rows", CliArgHelper.parse( "--sample-rows 0".split( " " ) ) ); + assertNull( "invalid sample-rows", CliArgHelper.parse( "--sample-rows -1".split( " " ) ) ); + assertNull( "invalid sample-rows", CliArgHelper.parse( "--sample-rows foo".split( " " ) ) ); } @Test - public void testWrap() { - assertTrue("wrap true", CliArgHelper.parse("--wrap true".split(" ")).getWrap()); - assertFalse("wrap false", CliArgHelper.parse("--wrap false".split(" ")).getWrap()); - assertTrue("default wrap", CliArgHelper.parse().getWrap()); - assertNull("invalid wrap",CliArgHelper.parse("--wrap foo".split(" "))); + public void testWrap() + { + assertTrue( "wrap true", CliArgHelper.parse( "--wrap true".split( " " ) ).getWrap() ); + assertFalse( "wrap false", CliArgHelper.parse( "--wrap false".split( " " ) ).getWrap() ); + assertTrue( "default wrap", CliArgHelper.parse().getWrap() ); + assertNull( "invalid wrap", CliArgHelper.parse( "--wrap foo".split( " " ) ) ); } @Test - public void testDefaultScheme() { + public void testDefaultScheme() + { CliArgs arguments = CliArgHelper.parse(); assertNotNull( arguments ); assertEquals( "neo4j", arguments.getScheme() ); } @Test - public void testDebugIsNotDefault() { - assertFalse("Debug should not be the default mode", - CliArgHelper.parse(asArray()).getDebugMode()); + public void testDebugIsNotDefault() + { + assertFalse( "Debug should not be the default mode", + CliArgHelper.parse( asArray() ).getDebugMode() ); } @Test - public void testDebugIsParsed() { - assertTrue("Debug should have been parsed to true", - CliArgHelper.parse(asArray("--debug")).getDebugMode()); + public void testDebugIsParsed() + { + assertTrue( "Debug should have been parsed to true", + CliArgHelper.parse( asArray( "--debug" ) ).getDebugMode() ); } @Test - public void testVersionIsParsed() { - assertTrue("Version should have been parsed to true", - CliArgHelper.parse(asArray("--version")).getVersion()); + public void testVersionIsParsed() + { + assertTrue( "Version should have been parsed to true", + CliArgHelper.parse( asArray( "--version" ) ).getVersion() ); } @Test - public void testDriverVersionIsParsed() { - assertTrue("Driver version should have been parsed to true", - CliArgHelper.parse(asArray("--driver-version")).getDriverVersion()); + public void testDriverVersionIsParsed() + { + assertTrue( "Driver version should have been parsed to true", + CliArgHelper.parse( asArray( "--driver-version" ) ).getDriverVersion() ); } @Test - public void testFailFastIsDefault() { - assertEquals("Unexpected fail-behavior", FailBehavior.FAIL_FAST, - CliArgHelper.parse(asArray()).getFailBehavior()); + public void testFailFastIsDefault() + { + assertEquals( "Unexpected fail-behavior", FailBehavior.FAIL_FAST, + CliArgHelper.parse( asArray() ).getFailBehavior() ); } @Test - public void testFailFastIsParsed() { - assertEquals("Unexpected fail-behavior", FailBehavior.FAIL_FAST, - CliArgHelper.parse(asArray("--fail-fast")).getFailBehavior()); + public void testFailFastIsParsed() + { + assertEquals( "Unexpected fail-behavior", FailBehavior.FAIL_FAST, + CliArgHelper.parse( asArray( "--fail-fast" ) ).getFailBehavior() ); } @Test - public void testFailAtEndIsParsed() { - assertEquals("Unexpected fail-behavior", FailBehavior.FAIL_AT_END, - CliArgHelper.parse(asArray("--fail-at-end")).getFailBehavior()); + public void testFailAtEndIsParsed() + { + assertEquals( "Unexpected fail-behavior", FailBehavior.FAIL_AT_END, + CliArgHelper.parse( asArray( "--fail-at-end" ) ).getFailBehavior() ); } @Test - public void singlePositionalArgumentIsFine() { + public void singlePositionalArgumentIsFine() + { String text = "Single string"; - assertEquals("Did not parse cypher string", text, - CliArgHelper.parse(asArray(text)).getCypher().get()); + assertEquals( "Did not parse cypher string", text, + CliArgHelper.parse( asArray( text ) ).getCypher().get() ); } @Test - public void parseArgumentsAndQuery() { + public void parseArgumentsAndQuery() + { String query = "\"match (n) return n\""; ArrayList strings = new ArrayList<>(); - strings.addAll(asList("-a 192.168.1.1 -p 123 --format plain".split(" "))); - strings.add(query); - assertEquals(Optional.of(query), - CliArgHelper.parse(strings.toArray(new String[strings.size()])).getCypher()); + strings.addAll( asList( "-a 192.168.1.1 -p 123 --format plain".split( " " ) ) ); + strings.add( query ); + assertEquals( Optional.of( query ), + CliArgHelper.parse( strings.toArray( new String[strings.size()] ) ).getCypher() ); } @Test - public void parseFormat() { - assertEquals(Format.PLAIN, CliArgHelper.parse("--format", "plain").getFormat()); - assertEquals(Format.VERBOSE, CliArgHelper.parse("--format", "verbose").getFormat()); + public void parseFormat() + { + assertEquals( Format.PLAIN, CliArgHelper.parse( "--format", "plain" ).getFormat() ); + assertEquals( Format.VERBOSE, CliArgHelper.parse( "--format", "verbose" ).getFormat() ); } @Test - public void parsePassword() { - assertEquals("foo", CliArgHelper.parse("--password", "foo").getPassword()); + public void parsePassword() + { + assertEquals( "foo", CliArgHelper.parse( "--password", "foo" ).getPassword() ); } @Test - public void parseUserName() { - assertEquals("foo", CliArgHelper.parse("--username", "foo").getUsername()); + public void parseUserName() + { + assertEquals( "foo", CliArgHelper.parse( "--username", "foo" ).getUsername() ); } @Test - public void parseFullAddress() { - CliArgs cliArgs = CliArgHelper.parse("--address", "bolt+routing://alice:foo@bar:69"); - assertNotNull(cliArgs); - assertEquals("alice", cliArgs.getUsername()); - assertEquals("foo", cliArgs.getPassword()); - assertEquals("bolt+routing", cliArgs.getScheme()); - assertEquals("bar", cliArgs.getHost()); - assertEquals(69, cliArgs.getPort()); + public void parseFullAddress() + { + CliArgs cliArgs = CliArgHelper.parse( "--address", "bolt+routing://alice:foo@bar:69" ); + assertNotNull( cliArgs ); + assertEquals( "alice", cliArgs.getUsername() ); + assertEquals( "foo", cliArgs.getPassword() ); + assertEquals( "bolt+routing", cliArgs.getScheme() ); + assertEquals( "bar", cliArgs.getHost() ); + assertEquals( 69, cliArgs.getPort() ); } @Test @@ -165,13 +204,14 @@ public void defaultAddress() assertEquals( CliArgs.DEFAULT_PORT, cliArgs.getPort() ); } - public void parseWithoutProtocol() { - CliArgs cliArgs = CliArgHelper.parse("--address", "localhost:10000"); - assertNotNull(cliArgs); - assertNotNull(cliArgs); - assertEquals("bolt", cliArgs.getScheme()); - assertEquals("localhost", cliArgs.getHost()); - assertEquals(10000, cliArgs.getPort()); + public void parseWithoutProtocol() + { + CliArgs cliArgs = CliArgHelper.parse( "--address", "localhost:10000" ); + assertNotNull( cliArgs ); + assertNotNull( cliArgs ); + assertEquals( "bolt", cliArgs.getScheme() ); + assertEquals( "localhost", cliArgs.getHost() ); + assertEquals( 10000, cliArgs.getPort() ); } @Test @@ -185,83 +225,93 @@ public void parseAddressWithRoutingContext() } @Test - public void nonsenseArgsGiveError() { + public void nonsenseArgsGiveError() + { ByteArrayOutputStream bout = new ByteArrayOutputStream(); - System.setErr(new PrintStream(bout)); + System.setErr( new PrintStream( bout ) ); - CliArgs cliargs = CliArgHelper.parse("-notreally"); + CliArgs cliargs = CliArgHelper.parse( "-notreally" ); - assertNull(cliargs); + assertNull( cliargs ); - assertTrue(bout.toString().contains("cypher-shell [-h]")); - assertTrue(bout.toString().contains("cypher-shell: error: unrecognized arguments: '-notreally'")); + assertTrue( bout.toString().contains( "cypher-shell [-h]" ) ); + assertTrue( bout.toString().contains( "cypher-shell: error: unrecognized arguments: '-notreally'" ) ); } @Test - public void nonsenseUrlGivesError() { + public void nonsenseUrlGivesError() + { ByteArrayOutputStream bout = new ByteArrayOutputStream(); - System.setErr(new PrintStream(bout)); + System.setErr( new PrintStream( bout ) ); - CliArgs cliargs = CliArgHelper.parse("--address", "host port"); + CliArgs cliargs = CliArgHelper.parse( "--address", "host port" ); - assertNull("should have failed", cliargs); + assertNull( "should have failed", cliargs ); - assertTrue("expected usage: " + bout.toString(), - bout.toString().contains("cypher-shell [-h]")); - assertTrue("expected error: " + bout.toString(), - bout.toString().contains("cypher-shell: error: Failed to parse address")); - assertTrue("expected error detail: " + bout.toString(), - bout.toString().contains("\n Address should be of the form:")); + assertTrue( "expected usage: " + bout.toString(), + bout.toString().contains( "cypher-shell [-h]" ) ); + assertTrue( "expected error: " + bout.toString(), + bout.toString().contains( "cypher-shell: error: Failed to parse address" ) ); + assertTrue( "expected error detail: " + bout.toString(), + bout.toString().contains( "\n Address should be of the form:" ) ); } @Test - public void defaultsEncryptionToDefault() { - assertEquals(Encryption.DEFAULT, CliArgHelper.parse().getEncryption()); + public void defaultsEncryptionToDefault() + { + assertEquals( Encryption.DEFAULT, CliArgHelper.parse().getEncryption() ); } @Test - public void allowsEncryptionToBeTurnedOnOrOff() { - assertEquals(Encryption.TRUE, CliArgHelper.parse("--encryption", "true").getEncryption()); - assertEquals(Encryption.FALSE, CliArgHelper.parse("--encryption", "false").getEncryption()); + public void allowsEncryptionToBeTurnedOnOrOff() + { + assertEquals( Encryption.TRUE, CliArgHelper.parse( "--encryption", "true" ).getEncryption() ); + assertEquals( Encryption.FALSE, CliArgHelper.parse( "--encryption", "false" ).getEncryption() ); } @Test - public void shouldNotAcceptInvalidEncryption() throws Exception { + public void shouldNotAcceptInvalidEncryption() throws Exception + { thrown.expect( ArgumentParserException.class ); - thrown.expectMessage( containsString("argument --encryption: invalid choice: 'bugaluga' (choose from {true,false,default})")); - CliArgHelper.parseAndThrow("--encryption", "bugaluga"); + thrown.expectMessage( containsString( "argument --encryption: invalid choice: 'bugaluga' (choose from {true,false,default})" ) ); + CliArgHelper.parseAndThrow( "--encryption", "bugaluga" ); } @Test - public void shouldParseSingleIntegerArgWithAddition() { + public void shouldParseSingleIntegerArgWithAddition() + { CliArgs cliArgs = CliArgHelper.parse( "-P", "foo=>3+5" ); assertNotNull( cliArgs ); assertEquals( 8L, cliArgs.getParameters().allParameterValues().get( "foo" ) ); } @Test - public void shouldParseSingleIntegerArgWithAdditionAndWhitespace() { + public void shouldParseSingleIntegerArgWithAdditionAndWhitespace() + { CliArgs cliArgs = CliArgHelper.parse( "-P", "foo => 3 + 5" ); assertNotNull( cliArgs ); assertEquals( 8L, cliArgs.getParameters().allParameterValues().get( "foo" ) ); } @Test - public void shouldParseWithSpaceSyntax() { + public void shouldParseWithSpaceSyntax() + { CliArgs cliArgs = CliArgHelper.parse( "-P", "foo 3+5" ); assertNotNull( cliArgs ); assertEquals( 8L, cliArgs.getParameters().allParameterValues().get( "foo" ) ); } @Test - public void shouldParseSingleStringArg() { + public void shouldParseSingleStringArg() + { CliArgs cliArgs = CliArgHelper.parse( "-P", "foo=>'nanana'" ); assertNotNull( cliArgs ); assertEquals( "nanana", cliArgs.getParameters().allParameterValues().get( "foo" ) ); } @Test - public void shouldParseTwoArgs() { + public void shouldParseTwoArgs() + { CliArgs cliArgs = CliArgHelper.parse( "-P", "foo=>'nanana'", "-P", "bar=>3+5" ); assertNotNull( cliArgs ); assertEquals( "nanana", cliArgs.getParameters().allParameterValues().get( "foo" ) ); @@ -269,24 +319,27 @@ public void shouldParseTwoArgs() { } @Test - public void shouldFailForInvalidSyntaxForArg() throws Exception { + public void shouldFailForInvalidSyntaxForArg() throws Exception + { thrown.expect( ArgumentParserException.class ); - thrown.expectMessage(allOf( - containsString("Incorrect usage"), - containsString("usage: --param \"name => value\""))); - CliArgHelper.parseAndThrow( "-P", "foo: => 'nanana'"); + thrown.expectMessage( allOf( + containsString( "Incorrect usage" ), + containsString( "usage: --param \"name => value\"" ) ) ); + CliArgHelper.parseAndThrow( "-P", "foo: => 'nanana'" ); } @Test - public void testDefaultInputFileName() { + public void testDefaultInputFileName() + { CliArgs arguments = CliArgHelper.parse(); assertNotNull( arguments ); assertNull( arguments.getInputFilename() ); } @Test - public void testSetInputFileName() { - CliArgs arguments = CliArgHelper.parse("--file", "foo"); + public void testSetInputFileName() + { + CliArgs arguments = CliArgHelper.parse( "--file", "foo" ); assertNotNull( arguments ); assertEquals( "foo", arguments.getInputFilename() ); } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/cli/CliArgsTest.java b/cypher-shell/src/test/java/org/neo4j/shell/cli/CliArgsTest.java index 645be3f6..e8caf731 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/cli/CliArgsTest.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/cli/CliArgsTest.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.cli; import org.junit.Before; @@ -9,96 +28,105 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; - -public class CliArgsTest { +public class CliArgsTest +{ private CliArgs cliArgs; @Before - public void setup() { + public void setup() + { cliArgs = new CliArgs(); } @Test - public void setHost() throws Exception { - cliArgs.setHost("foo", "bar"); - assertEquals("foo", cliArgs.getHost()); + public void setHost() throws Exception + { + cliArgs.setHost( "foo", "bar" ); + assertEquals( "foo", cliArgs.getHost() ); - cliArgs.setHost(null, "bar"); - assertEquals("bar", cliArgs.getHost()); + cliArgs.setHost( null, "bar" ); + assertEquals( "bar", cliArgs.getHost() ); } @Test - public void setPort() throws Exception { - cliArgs.setPort(999); - assertEquals(999, cliArgs.getPort()); + public void setPort() throws Exception + { + cliArgs.setPort( 999 ); + assertEquals( 999, cliArgs.getPort() ); } @Test - public void setUsername() throws Exception { - cliArgs.setUsername("foo", "bar"); - assertEquals("foo", cliArgs.getUsername()); + public void setUsername() throws Exception + { + cliArgs.setUsername( "foo", "bar" ); + assertEquals( "foo", cliArgs.getUsername() ); - cliArgs.setUsername(null, "bar"); - assertEquals("bar", cliArgs.getUsername()); + cliArgs.setUsername( null, "bar" ); + assertEquals( "bar", cliArgs.getUsername() ); } @Test - public void setPassword() throws Exception { - cliArgs.setPassword("foo", "bar"); - assertEquals("foo", cliArgs.getPassword()); + public void setPassword() throws Exception + { + cliArgs.setPassword( "foo", "bar" ); + assertEquals( "foo", cliArgs.getPassword() ); - cliArgs.setPassword(null, "bar"); - assertEquals("bar", cliArgs.getPassword()); + cliArgs.setPassword( null, "bar" ); + assertEquals( "bar", cliArgs.getPassword() ); } @Test - public void setFailBehavior() throws Exception { + public void setFailBehavior() throws Exception + { // default - assertEquals(FailBehavior.FAIL_FAST, cliArgs.getFailBehavior()); + assertEquals( FailBehavior.FAIL_FAST, cliArgs.getFailBehavior() ); - cliArgs.setFailBehavior(FailBehavior.FAIL_AT_END); - assertEquals(FailBehavior.FAIL_AT_END, cliArgs.getFailBehavior()); + cliArgs.setFailBehavior( FailBehavior.FAIL_AT_END ); + assertEquals( FailBehavior.FAIL_AT_END, cliArgs.getFailBehavior() ); } @Test - public void getNumSampleRows() throws Exception { - assertEquals(1000, CliArgs.DEFAULT_NUM_SAMPLE_ROWS); - assertEquals(CliArgs.DEFAULT_NUM_SAMPLE_ROWS, cliArgs.getNumSampleRows()); + public void getNumSampleRows() throws Exception + { + assertEquals( 1000, CliArgs.DEFAULT_NUM_SAMPLE_ROWS ); + assertEquals( CliArgs.DEFAULT_NUM_SAMPLE_ROWS, cliArgs.getNumSampleRows() ); - cliArgs.setNumSampleRows(null); - assertEquals(CliArgs.DEFAULT_NUM_SAMPLE_ROWS, cliArgs.getNumSampleRows()); + cliArgs.setNumSampleRows( null ); + assertEquals( CliArgs.DEFAULT_NUM_SAMPLE_ROWS, cliArgs.getNumSampleRows() ); - cliArgs.setNumSampleRows(0); - assertEquals(CliArgs.DEFAULT_NUM_SAMPLE_ROWS, cliArgs.getNumSampleRows()); + cliArgs.setNumSampleRows( 0 ); + assertEquals( CliArgs.DEFAULT_NUM_SAMPLE_ROWS, cliArgs.getNumSampleRows() ); - cliArgs.setNumSampleRows(120); - assertEquals(120, cliArgs.getNumSampleRows()); + cliArgs.setNumSampleRows( 120 ); + assertEquals( 120, cliArgs.getNumSampleRows() ); } @Test - public void setFormat() throws Exception { + public void setFormat() throws Exception + { // default - assertEquals(Format.AUTO, cliArgs.getFormat()); + assertEquals( Format.AUTO, cliArgs.getFormat() ); - cliArgs.setFormat(Format.PLAIN); - assertEquals(Format.PLAIN, cliArgs.getFormat()); + cliArgs.setFormat( Format.PLAIN ); + assertEquals( Format.PLAIN, cliArgs.getFormat() ); - cliArgs.setFormat(Format.VERBOSE); - assertEquals(Format.VERBOSE, cliArgs.getFormat()); + cliArgs.setFormat( Format.VERBOSE ); + assertEquals( Format.VERBOSE, cliArgs.getFormat() ); } @Test - public void setCypher() throws Exception { + public void setCypher() throws Exception + { // default - assertFalse(cliArgs.getCypher().isPresent()); + assertFalse( cliArgs.getCypher().isPresent() ); - cliArgs.setCypher("foo"); - assertTrue(cliArgs.getCypher().isPresent()); + cliArgs.setCypher( "foo" ); + assertTrue( cliArgs.getCypher().isPresent() ); //noinspection OptionalGetWithoutIsPresent - assertEquals("foo", cliArgs.getCypher().get()); + assertEquals( "foo", cliArgs.getCypher().get() ); - cliArgs.setCypher(null); - assertFalse(cliArgs.getCypher().isPresent()); + cliArgs.setCypher( null ); + assertFalse( cliArgs.getCypher().isPresent() ); } @Test @@ -112,7 +140,7 @@ public void getParameters() @Test public void setInputFile() { - cliArgs.setInputFilename("foo"); - assertEquals("foo", cliArgs.getInputFilename()); + cliArgs.setInputFilename( "foo" ); + assertEquals( "foo", cliArgs.getInputFilename() ); } } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/cli/CommandHelperTest.java b/cypher-shell/src/test/java/org/neo4j/shell/cli/CommandHelperTest.java index 0515a60c..88ee3d4d 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/cli/CommandHelperTest.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/cli/CommandHelperTest.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.cli; import org.junit.Test; @@ -17,25 +36,32 @@ import static org.junit.Assert.fail; import static org.neo4j.shell.commands.CommandHelper.simpleArgParse; -public class CommandHelperTest { +public class CommandHelperTest +{ @Test - public void emptyStringIsNoArgs() throws CommandException { - assertEquals(0, simpleArgParse("", 0, "", "").length); + public void emptyStringIsNoArgs() throws CommandException + { + assertEquals( 0, simpleArgParse( "", 0, "", "" ).length ); } @Test - public void whitespaceStringIsNoArgs() throws CommandException { - assertEquals(0, simpleArgParse(" \t ", 0, "", "").length); + public void whitespaceStringIsNoArgs() throws CommandException + { + assertEquals( 0, simpleArgParse( " \t ", 0, "", "" ).length ); } @Test - public void oneArg() { - try { - assertEquals(0, simpleArgParse("bob", 0, "", "")); + public void oneArg() + { + try + { + assertEquals( 0, simpleArgParse( "bob", 0, "", "" ) ); fail(); - } catch (CommandException e) { - assertTrue(e.getMessage().contains("Incorrect number of arguments")); + } + catch ( CommandException e ) + { + assertTrue( e.getMessage().contains( "Incorrect number of arguments" ) ); } } @@ -44,7 +70,8 @@ public void shouldIgnoreCaseForCommands() { // Given AnsiLogger logger = new AnsiLogger( false ); - CommandHelper commandHelper = new CommandHelper( logger, Historian.empty, new CypherShell(logger, PrettyConfig.DEFAULT, false, new ShellParameterMap() ) ); + CommandHelper commandHelper = + new CommandHelper( logger, Historian.empty, new CypherShell( logger, PrettyConfig.DEFAULT, false, new ShellParameterMap() ) ); // When Command begin = commandHelper.getCommand( ":BEGIN" ); diff --git a/cypher-shell/src/test/java/org/neo4j/shell/cli/FileHistorianTest.java b/cypher-shell/src/test/java/org/neo4j/shell/cli/FileHistorianTest.java index 92a823f0..b333c3c4 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/cli/FileHistorianTest.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/cli/FileHistorianTest.java @@ -1,19 +1,38 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.cli; - import jline.console.ConsoleReader; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; -import org.neo4j.shell.Historian; -import org.neo4j.shell.log.Logger; import java.io.File; import java.io.InputStream; import java.nio.file.Path; import java.nio.file.Paths; +import org.neo4j.shell.Historian; +import org.neo4j.shell.log.Logger; + import static java.lang.System.getProperty; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -23,38 +42,42 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; -public class FileHistorianTest { +public class FileHistorianTest +{ @Rule public TemporaryFolder temp = new TemporaryFolder(); - private Logger logger = mock(Logger.class); - private InputStream mockedInput = mock(InputStream.class); - private ConsoleReader reader = mock(ConsoleReader.class); + private Logger logger = mock( Logger.class ); + private InputStream mockedInput = mock( InputStream.class ); + private ConsoleReader reader = mock( ConsoleReader.class ); @Before - public void setup() { - doReturn(System.out).when(logger).getOutputStream(); + public void setup() + { + doReturn( System.out ).when( logger ).getOutputStream(); } @Test - public void defaultHistoryFile() throws Exception { - Path expectedPath = Paths.get(getProperty("user.home"), ".neo4j", ".neo4j_history"); + public void defaultHistoryFile() throws Exception + { + Path expectedPath = Paths.get( getProperty( "user.home" ), ".neo4j", ".neo4j_history" ); File history = FileHistorian.getDefaultHistoryFile(); - assertEquals(expectedPath.toString(), history.getPath()); + assertEquals( expectedPath.toString(), history.getPath() ); } @Test - public void noHistoryFileGivesMemoryHistory() throws Exception { - File historyFile = Paths.get(temp.newFolder().getAbsolutePath(), "asfasd", "zxvses", "fanjtaacf").toFile(); - assertFalse(historyFile.getParentFile().isDirectory()); - assertFalse(historyFile.getParentFile().getParentFile().isDirectory()); - Historian historian = FileHistorian.setupHistory(reader, logger, historyFile); + public void noHistoryFileGivesMemoryHistory() throws Exception + { + File historyFile = Paths.get( temp.newFolder().getAbsolutePath(), "asfasd", "zxvses", "fanjtaacf" ).toFile(); + assertFalse( historyFile.getParentFile().isDirectory() ); + assertFalse( historyFile.getParentFile().getParentFile().isDirectory() ); + Historian historian = FileHistorian.setupHistory( reader, logger, historyFile ); - assertNotNull(historian); + assertNotNull( historian ); - verify(logger).printError(contains("Could not load history file. Falling back to session-based history.\n" + - "Failed to create directory for history")); + verify( logger ).printError( contains( "Could not load history file. Falling back to session-based history.\n" + + "Failed to create directory for history" ) ); } } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/cli/InteractiveShellRunnerTest.java b/cypher-shell/src/test/java/org/neo4j/shell/cli/InteractiveShellRunnerTest.java index f789b800..b56f5ad6 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/cli/InteractiveShellRunnerTest.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/cli/InteractiveShellRunnerTest.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.cli; import org.junit.Before; @@ -5,6 +24,19 @@ import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; +import sun.misc.Signal; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintStream; +import java.nio.file.Files; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; +import javax.annotation.Nonnull; + import org.neo4j.driver.exceptions.ClientException; import org.neo4j.driver.exceptions.DiscoveryException; import org.neo4j.driver.exceptions.ServiceUnavailableException; @@ -31,19 +63,6 @@ import org.neo4j.shell.prettyprint.PrettyPrinter; import org.neo4j.shell.state.BoltStateHandler; -import sun.misc.Signal; - -import javax.annotation.Nonnull; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.PrintStream; -import java.nio.file.Files; -import java.util.List; -import java.util.concurrent.atomic.AtomicReference; - import static java.lang.String.format; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.is; @@ -60,7 +79,8 @@ import static org.mockito.Mockito.when; import static org.neo4j.shell.cli.InteractiveShellRunner.DATABASE_UNAVAILABLE_ERROR_PROMPT_TEXT; -public class InteractiveShellRunnerTest { +public class InteractiveShellRunnerTest +{ @Rule public final ExpectedException thrown = ExpectedException.none(); @@ -78,101 +98,110 @@ public class InteractiveShellRunnerTest { private ConnectionConfig connectionConfig; @Before - public void setup() throws Exception { + public void setup() throws Exception + { statementParser = new ShellStatementParser(); - logger = mock(Logger.class); - cmdExecuter = mock(StatementExecuter.class); - txHandler = mock(TransactionHandler.class); - databaseManager = mock(DatabaseManager.class); - connectionConfig = mock(ConnectionConfig.class); + logger = mock( Logger.class ); + cmdExecuter = mock( StatementExecuter.class ); + txHandler = mock( TransactionHandler.class ); + databaseManager = mock( DatabaseManager.class ); + connectionConfig = mock( ConnectionConfig.class ); historyFile = temp.newFile(); - badLineError = new ClientException("Found a bad line"); - userMessagesHandler = mock(UserMessagesHandler.class); - when(databaseManager.getActualDatabaseAsReportedByServer()).thenReturn("mydb"); - when(userMessagesHandler.getWelcomeMessage()).thenReturn("Welcome to cypher-shell!"); - when(userMessagesHandler.getExitMessage()).thenReturn("Exit message"); - when(connectionConfig.username()).thenReturn("myusername"); - - doThrow(badLineError).when(cmdExecuter).execute(contains("bad")); - doReturn(System.out).when(logger).getOutputStream(); + badLineError = new ClientException( "Found a bad line" ); + userMessagesHandler = mock( UserMessagesHandler.class ); + when( databaseManager.getActualDatabaseAsReportedByServer() ).thenReturn( "mydb" ); + when( userMessagesHandler.getWelcomeMessage() ).thenReturn( "Welcome to cypher-shell!" ); + when( userMessagesHandler.getExitMessage() ).thenReturn( "Exit message" ); + when( connectionConfig.username() ).thenReturn( "myusername" ); + + doThrow( badLineError ).when( cmdExecuter ).execute( contains( "bad" ) ); + doReturn( System.out ).when( logger ).getOutputStream(); } @Test - public void testSimple() throws Exception { + public void testSimple() throws Exception + { String input = "good1;\n" + - "good2;\n"; - InteractiveShellRunner runner = new InteractiveShellRunner(cmdExecuter, txHandler, databaseManager, logger, statementParser, - new ByteArrayInputStream(input.getBytes()), historyFile, userMessagesHandler, connectionConfig); + "good2;\n"; + InteractiveShellRunner runner = new InteractiveShellRunner( cmdExecuter, txHandler, databaseManager, logger, statementParser, + new ByteArrayInputStream( input.getBytes() ), historyFile, userMessagesHandler, + connectionConfig ); runner.runUntilEnd(); - verify(cmdExecuter).execute("good1;"); - verify(cmdExecuter).execute("\ngood2;"); - verify(cmdExecuter, times(3)).lastNeo4jErrorCode(); - verifyNoMoreInteractions(cmdExecuter); + verify( cmdExecuter ).execute( "good1;" ); + verify( cmdExecuter ).execute( "\ngood2;" ); + verify( cmdExecuter, times( 3 ) ).lastNeo4jErrorCode(); + verifyNoMoreInteractions( cmdExecuter ); } @Test - public void runUntilEndShouldKeepGoingOnErrors() throws IOException, CommandException { + public void runUntilEndShouldKeepGoingOnErrors() throws IOException, CommandException + { String input = "good1;\n" + - "bad1;\n" + - "good2;\n" + - "bad2;\n" + - "good3;\n"; - InteractiveShellRunner runner = new InteractiveShellRunner(cmdExecuter, txHandler, databaseManager, logger, statementParser, - new ByteArrayInputStream(input.getBytes()), historyFile, userMessagesHandler, connectionConfig); + "bad1;\n" + + "good2;\n" + + "bad2;\n" + + "good3;\n"; + InteractiveShellRunner runner = new InteractiveShellRunner( cmdExecuter, txHandler, databaseManager, logger, statementParser, + new ByteArrayInputStream( input.getBytes() ), historyFile, userMessagesHandler, + connectionConfig ); int code = runner.runUntilEnd(); - assertEquals("Wrong exit code", 0, code); + assertEquals( "Wrong exit code", 0, code ); - verify(cmdExecuter).execute("good1;"); - verify(cmdExecuter).execute("\nbad1;"); - verify(cmdExecuter).execute("\ngood2;"); - verify(cmdExecuter).execute("\nbad2;"); - verify(cmdExecuter).execute("\ngood3;"); - verify(cmdExecuter, times(6)).lastNeo4jErrorCode(); - verifyNoMoreInteractions(cmdExecuter); + verify( cmdExecuter ).execute( "good1;" ); + verify( cmdExecuter ).execute( "\nbad1;" ); + verify( cmdExecuter ).execute( "\ngood2;" ); + verify( cmdExecuter ).execute( "\nbad2;" ); + verify( cmdExecuter ).execute( "\ngood3;" ); + verify( cmdExecuter, times( 6 ) ).lastNeo4jErrorCode(); + verifyNoMoreInteractions( cmdExecuter ); - verify(logger, times(2)).printError(badLineError); + verify( logger, times( 2 ) ).printError( badLineError ); } @Test - public void runUntilEndShouldStopOnExitExceptionAndReturnCode() throws IOException, CommandException { + public void runUntilEndShouldStopOnExitExceptionAndReturnCode() throws IOException, CommandException + { String input = "good1;\n" + - "bad1;\n" + - "good2;\n" + - "exit;\n" + - "bad2;\n" + - "good3;\n"; - InteractiveShellRunner runner = new InteractiveShellRunner(cmdExecuter, txHandler, databaseManager, logger, statementParser, - new ByteArrayInputStream(input.getBytes()), historyFile, userMessagesHandler, connectionConfig); + "bad1;\n" + + "good2;\n" + + "exit;\n" + + "bad2;\n" + + "good3;\n"; + InteractiveShellRunner runner = new InteractiveShellRunner( cmdExecuter, txHandler, databaseManager, logger, statementParser, + new ByteArrayInputStream( input.getBytes() ), historyFile, userMessagesHandler, + connectionConfig ); - doThrow(new ExitException(1234)).when(cmdExecuter).execute(contains("exit;")); + doThrow( new ExitException( 1234 ) ).when( cmdExecuter ).execute( contains( "exit;" ) ); int code = runner.runUntilEnd(); - assertEquals("Wrong exit code", 1234, code); + assertEquals( "Wrong exit code", 1234, code ); - verify(cmdExecuter).execute("good1;"); - verify(cmdExecuter).execute("\nbad1;"); - verify(cmdExecuter).execute("\ngood2;"); - verify(cmdExecuter).execute("\nexit;"); - verify(cmdExecuter, times(4)).lastNeo4jErrorCode(); - verifyNoMoreInteractions(cmdExecuter); + verify( cmdExecuter ).execute( "good1;" ); + verify( cmdExecuter ).execute( "\nbad1;" ); + verify( cmdExecuter ).execute( "\ngood2;" ); + verify( cmdExecuter ).execute( "\nexit;" ); + verify( cmdExecuter, times( 4 ) ).lastNeo4jErrorCode(); + verifyNoMoreInteractions( cmdExecuter ); - verify(logger).printError(badLineError); + verify( logger ).printError( badLineError ); } @Test - public void historyIsRecorded() throws Exception { + public void historyIsRecorded() throws Exception + { // given String cmd1 = ":set var \"3\""; String cmd2 = ":help exit"; String input = cmd1 + "\n" + cmd2 + "\n"; - InteractiveShellRunner runner = new InteractiveShellRunner(cmdExecuter, txHandler, databaseManager, logger, statementParser, - new ByteArrayInputStream(input.getBytes()), historyFile, userMessagesHandler, connectionConfig); + InteractiveShellRunner runner = new InteractiveShellRunner( cmdExecuter, txHandler, databaseManager, logger, statementParser, + new ByteArrayInputStream( input.getBytes() ), historyFile, userMessagesHandler, + connectionConfig ); // when runner.runUntilEnd(); @@ -181,511 +210,550 @@ public void historyIsRecorded() throws Exception { Historian historian = runner.getHistorian(); historian.flushHistory(); - List history = Files.readAllLines(historyFile.toPath()); + List history = Files.readAllLines( historyFile.toPath() ); - assertEquals(2, history.size()); - assertEquals(cmd1, history.get(0)); - assertEquals(cmd2, history.get(1)); + assertEquals( 2, history.size() ); + assertEquals( cmd1, history.get( 0 ) ); + assertEquals( cmd2, history.get( 1 ) ); history = historian.getHistory(); - assertEquals(2, history.size()); - assertEquals(cmd1, history.get(0)); - assertEquals(cmd2, history.get(1)); + assertEquals( 2, history.size() ); + assertEquals( cmd1, history.get( 0 ) ); + assertEquals( cmd2, history.get( 1 ) ); } @Test - public void unescapedBangWorks() throws Exception { + public void unescapedBangWorks() throws Exception + { // given - PrintStream mockedErr = mock(PrintStream.class); - when(logger.getErrorStream()).thenReturn(mockedErr); + PrintStream mockedErr = mock( PrintStream.class ); + when( logger.getErrorStream() ).thenReturn( mockedErr ); // Bangs need escaping in JLine by default, just like in bash, but we have disabled that - InputStream inputStream = new ByteArrayInputStream(":set var \"String with !bang\"\n".getBytes()); - InteractiveShellRunner runner = new InteractiveShellRunner(cmdExecuter, txHandler, databaseManager, logger, statementParser, inputStream, historyFile, - userMessagesHandler, connectionConfig); + InputStream inputStream = new ByteArrayInputStream( ":set var \"String with !bang\"\n".getBytes() ); + InteractiveShellRunner runner = new InteractiveShellRunner( cmdExecuter, txHandler, databaseManager, logger, statementParser, inputStream, historyFile, + userMessagesHandler, connectionConfig ); // when List statements = runner.readUntilStatement(); // then - assertEquals(":set var \"String with !bang\"\n", statements.get(0)); + assertEquals( ":set var \"String with !bang\"\n", statements.get( 0 ) ); } @Test - public void escapedBangWorks() throws Exception { + public void escapedBangWorks() throws Exception + { // given - PrintStream mockedErr = mock(PrintStream.class); - when(logger.getErrorStream()).thenReturn(mockedErr); + PrintStream mockedErr = mock( PrintStream.class ); + when( logger.getErrorStream() ).thenReturn( mockedErr ); // Bangs need escaping in JLine by default, just like in bash, but we have disabled that - InputStream inputStream = new ByteArrayInputStream(":set var \"String with \\!bang\"\n".getBytes()); - InteractiveShellRunner runner = new InteractiveShellRunner(cmdExecuter, txHandler, databaseManager, logger, statementParser, inputStream, historyFile, - userMessagesHandler, connectionConfig); + InputStream inputStream = new ByteArrayInputStream( ":set var \"String with \\!bang\"\n".getBytes() ); + InteractiveShellRunner runner = new InteractiveShellRunner( cmdExecuter, txHandler, databaseManager, logger, statementParser, inputStream, historyFile, + userMessagesHandler, connectionConfig ); // when List statements = runner.readUntilStatement(); // then - assertEquals(":set var \"String with \\!bang\"\n", statements.get(0)); + assertEquals( ":set var \"String with \\!bang\"\n", statements.get( 0 ) ); } @Test - public void justNewLineThrowsNoMoreInput() throws Exception { + public void justNewLineThrowsNoMoreInput() throws Exception + { // then - thrown.expect(NoMoreInputException.class); + thrown.expect( NoMoreInputException.class ); // given String inputString = "\n"; - InputStream inputStream = new ByteArrayInputStream(inputString.getBytes()); - InteractiveShellRunner runner = new InteractiveShellRunner(cmdExecuter, txHandler, databaseManager, logger, new ShellStatementParser(), inputStream, - historyFile, userMessagesHandler, connectionConfig); + InputStream inputStream = new ByteArrayInputStream( inputString.getBytes() ); + InteractiveShellRunner runner = new InteractiveShellRunner( cmdExecuter, txHandler, databaseManager, logger, new ShellStatementParser(), inputStream, + historyFile, userMessagesHandler, connectionConfig ); // when runner.readUntilStatement(); } @Test - public void emptyStringThrowsNoMoreInput() throws Exception { + public void emptyStringThrowsNoMoreInput() throws Exception + { // then - thrown.expect(NoMoreInputException.class); + thrown.expect( NoMoreInputException.class ); // given String inputString = ""; - InputStream inputStream = new ByteArrayInputStream(inputString.getBytes()); - InteractiveShellRunner runner = new InteractiveShellRunner(cmdExecuter, txHandler, databaseManager, logger, new ShellStatementParser(), inputStream, - historyFile, userMessagesHandler, connectionConfig); + InputStream inputStream = new ByteArrayInputStream( inputString.getBytes() ); + InteractiveShellRunner runner = new InteractiveShellRunner( cmdExecuter, txHandler, databaseManager, logger, new ShellStatementParser(), inputStream, + historyFile, userMessagesHandler, connectionConfig ); // when runner.readUntilStatement(); } @Test - public void emptyLineIsIgnored() throws Exception { + public void emptyLineIsIgnored() throws Exception + { // given String inputString = " \nCREATE (n:Person) RETURN n;\n"; - InputStream inputStream = new ByteArrayInputStream(inputString.getBytes()); - InteractiveShellRunner runner = new InteractiveShellRunner(cmdExecuter, txHandler, databaseManager, logger, new ShellStatementParser(), inputStream, - historyFile, userMessagesHandler, connectionConfig); + InputStream inputStream = new ByteArrayInputStream( inputString.getBytes() ); + InteractiveShellRunner runner = new InteractiveShellRunner( cmdExecuter, txHandler, databaseManager, logger, new ShellStatementParser(), inputStream, + historyFile, userMessagesHandler, connectionConfig ); // when List statements = runner.readUntilStatement(); // then - assertEquals(1, statements.size()); - assertThat(statements.get(0), is("CREATE (n:Person) RETURN n;")); + assertEquals( 1, statements.size() ); + assertThat( statements.get( 0 ), is( "CREATE (n:Person) RETURN n;" ) ); } @Test - public void testPrompt() throws Exception { + public void testPrompt() throws Exception + { // given - InputStream inputStream = new ByteArrayInputStream("".getBytes()); - InteractiveShellRunner runner = new InteractiveShellRunner(cmdExecuter, txHandler, databaseManager, logger, statementParser, inputStream, - historyFile, userMessagesHandler, connectionConfig); + InputStream inputStream = new ByteArrayInputStream( "".getBytes() ); + InteractiveShellRunner runner = new InteractiveShellRunner( cmdExecuter, txHandler, databaseManager, logger, statementParser, inputStream, + historyFile, userMessagesHandler, connectionConfig ); // when - when(txHandler.isTransactionOpen()).thenReturn(false); + when( txHandler.isTransactionOpen() ).thenReturn( false ); AnsiFormattedText prompt = runner.updateAndGetPrompt(); // then String wantedPrompt = "myusername@mydb> "; - assertEquals(wantedPrompt, prompt.plainString()); + assertEquals( wantedPrompt, prompt.plainString() ); // when - statementParser.parseMoreText(" \t \n "); // whitespace + statementParser.parseMoreText( " \t \n " ); // whitespace prompt = runner.updateAndGetPrompt(); // then - assertEquals(wantedPrompt, prompt.plainString()); + assertEquals( wantedPrompt, prompt.plainString() ); // when - statementParser.parseMoreText("bla bla"); // non whitespace + statementParser.parseMoreText( "bla bla" ); // non whitespace prompt = runner.updateAndGetPrompt(); // then - assertEquals(OutputFormatter.repeat(' ', wantedPrompt.length()), prompt.plainString()); + assertEquals( OutputFormatter.repeat( ' ', wantedPrompt.length() ), prompt.plainString() ); } @Test - public void testPromptShowDatabaseAsSetByUserWhenServerReportNull() throws Exception { + public void testPromptShowDatabaseAsSetByUserWhenServerReportNull() throws Exception + { // given - InputStream inputStream = new ByteArrayInputStream("".getBytes()); - InteractiveShellRunner runner = new InteractiveShellRunner(cmdExecuter, txHandler, databaseManager, logger, statementParser, inputStream, - historyFile, userMessagesHandler, connectionConfig); + InputStream inputStream = new ByteArrayInputStream( "".getBytes() ); + InteractiveShellRunner runner = new InteractiveShellRunner( cmdExecuter, txHandler, databaseManager, logger, statementParser, inputStream, + historyFile, userMessagesHandler, connectionConfig ); // when - when(txHandler.isTransactionOpen()).thenReturn(false); - when(databaseManager.getActiveDatabaseAsSetByUser()).thenReturn("foo"); - when(databaseManager.getActualDatabaseAsReportedByServer()).thenReturn(null); + when( txHandler.isTransactionOpen() ).thenReturn( false ); + when( databaseManager.getActiveDatabaseAsSetByUser() ).thenReturn( "foo" ); + when( databaseManager.getActualDatabaseAsReportedByServer() ).thenReturn( null ); AnsiFormattedText prompt = runner.updateAndGetPrompt(); // then String wantedPrompt = "myusername@foo> "; - assertEquals(wantedPrompt, prompt.plainString()); + assertEquals( wantedPrompt, prompt.plainString() ); } @Test - public void testPromptShowDatabaseAsSetByUserWhenServerReportAbsent() throws Exception { + public void testPromptShowDatabaseAsSetByUserWhenServerReportAbsent() throws Exception + { // given - InputStream inputStream = new ByteArrayInputStream("".getBytes()); - InteractiveShellRunner runner = new InteractiveShellRunner(cmdExecuter, txHandler, databaseManager, logger, statementParser, inputStream, - historyFile, userMessagesHandler, connectionConfig); + InputStream inputStream = new ByteArrayInputStream( "".getBytes() ); + InteractiveShellRunner runner = new InteractiveShellRunner( cmdExecuter, txHandler, databaseManager, logger, statementParser, inputStream, + historyFile, userMessagesHandler, connectionConfig ); // when - when(txHandler.isTransactionOpen()).thenReturn(false); - when(databaseManager.getActiveDatabaseAsSetByUser()).thenReturn("foo"); - when(databaseManager.getActualDatabaseAsReportedByServer()).thenReturn(DatabaseManager.ABSENT_DB_NAME); + when( txHandler.isTransactionOpen() ).thenReturn( false ); + when( databaseManager.getActiveDatabaseAsSetByUser() ).thenReturn( "foo" ); + when( databaseManager.getActualDatabaseAsReportedByServer() ).thenReturn( DatabaseManager.ABSENT_DB_NAME ); AnsiFormattedText prompt = runner.updateAndGetPrompt(); // then String wantedPrompt = "myusername@foo> "; - assertEquals(wantedPrompt, prompt.plainString()); + assertEquals( wantedPrompt, prompt.plainString() ); } @Test - public void testPromptShowUnresolvedDefaultDatabaseWhenServerReportNull() throws Exception { + public void testPromptShowUnresolvedDefaultDatabaseWhenServerReportNull() throws Exception + { // given - InputStream inputStream = new ByteArrayInputStream("".getBytes()); - InteractiveShellRunner runner = new InteractiveShellRunner(cmdExecuter, txHandler, databaseManager, logger, statementParser, inputStream, - historyFile, userMessagesHandler, connectionConfig); + InputStream inputStream = new ByteArrayInputStream( "".getBytes() ); + InteractiveShellRunner runner = new InteractiveShellRunner( cmdExecuter, txHandler, databaseManager, logger, statementParser, inputStream, + historyFile, userMessagesHandler, connectionConfig ); // when - when(txHandler.isTransactionOpen()).thenReturn(false); - when(databaseManager.getActiveDatabaseAsSetByUser()).thenReturn(DatabaseManager.ABSENT_DB_NAME); - when(databaseManager.getActualDatabaseAsReportedByServer()).thenReturn(null); + when( txHandler.isTransactionOpen() ).thenReturn( false ); + when( databaseManager.getActiveDatabaseAsSetByUser() ).thenReturn( DatabaseManager.ABSENT_DB_NAME ); + when( databaseManager.getActualDatabaseAsReportedByServer() ).thenReturn( null ); AnsiFormattedText prompt = runner.updateAndGetPrompt(); // then - String wantedPrompt = format("myusername@%s> ", InteractiveShellRunner.UNRESOLVED_DEFAULT_DB_PROPMPT_TEXT); - assertEquals(wantedPrompt, prompt.plainString()); + String wantedPrompt = format( "myusername@%s> ", InteractiveShellRunner.UNRESOLVED_DEFAULT_DB_PROPMPT_TEXT ); + assertEquals( wantedPrompt, prompt.plainString() ); } @Test - public void testPromptShowUnresolvedDefaultDatabaseWhenServerReportAbsent() throws Exception { + public void testPromptShowUnresolvedDefaultDatabaseWhenServerReportAbsent() throws Exception + { // given - InputStream inputStream = new ByteArrayInputStream("".getBytes()); - InteractiveShellRunner runner = new InteractiveShellRunner(cmdExecuter, txHandler, databaseManager, logger, statementParser, inputStream, - historyFile, userMessagesHandler, connectionConfig); + InputStream inputStream = new ByteArrayInputStream( "".getBytes() ); + InteractiveShellRunner runner = new InteractiveShellRunner( cmdExecuter, txHandler, databaseManager, logger, statementParser, inputStream, + historyFile, userMessagesHandler, connectionConfig ); // when - when(txHandler.isTransactionOpen()).thenReturn(false); - when(databaseManager.getActiveDatabaseAsSetByUser()).thenReturn(DatabaseManager.ABSENT_DB_NAME); - when(databaseManager.getActualDatabaseAsReportedByServer()).thenReturn(DatabaseManager.ABSENT_DB_NAME); + when( txHandler.isTransactionOpen() ).thenReturn( false ); + when( databaseManager.getActiveDatabaseAsSetByUser() ).thenReturn( DatabaseManager.ABSENT_DB_NAME ); + when( databaseManager.getActualDatabaseAsReportedByServer() ).thenReturn( DatabaseManager.ABSENT_DB_NAME ); AnsiFormattedText prompt = runner.updateAndGetPrompt(); // then - String wantedPrompt = format("myusername@%s> ", InteractiveShellRunner.UNRESOLVED_DEFAULT_DB_PROPMPT_TEXT); - assertEquals(wantedPrompt, prompt.plainString()); + String wantedPrompt = format( "myusername@%s> ", InteractiveShellRunner.UNRESOLVED_DEFAULT_DB_PROPMPT_TEXT ); + assertEquals( wantedPrompt, prompt.plainString() ); } @Test - public void testLongPrompt() throws Exception { + public void testLongPrompt() throws Exception + { // given - InputStream inputStream = new ByteArrayInputStream("".getBytes()); + InputStream inputStream = new ByteArrayInputStream( "".getBytes() ); String actualDbName = "TheLongestDbNameEverCreatedInAllOfHistoryAndTheUniversePlusSome"; - when(databaseManager.getActualDatabaseAsReportedByServer()).thenReturn(actualDbName); - InteractiveShellRunner runner = new InteractiveShellRunner(cmdExecuter, txHandler, databaseManager, logger, statementParser, inputStream, - historyFile, userMessagesHandler, connectionConfig); + when( databaseManager.getActualDatabaseAsReportedByServer() ).thenReturn( actualDbName ); + InteractiveShellRunner runner = new InteractiveShellRunner( cmdExecuter, txHandler, databaseManager, logger, statementParser, inputStream, + historyFile, userMessagesHandler, connectionConfig ); // when - when(txHandler.isTransactionOpen()).thenReturn(false); + when( txHandler.isTransactionOpen() ).thenReturn( false ); AnsiFormattedText prompt = runner.updateAndGetPrompt(); // then - String wantedPrompt = format("myusername@%s%n> ", actualDbName); - assertEquals(wantedPrompt, prompt.plainString()); + String wantedPrompt = format( "myusername@%s%n> ", actualDbName ); + assertEquals( wantedPrompt, prompt.plainString() ); // when - statementParser.parseMoreText(" \t \n "); // whitespace + statementParser.parseMoreText( " \t \n " ); // whitespace prompt = runner.updateAndGetPrompt(); // then - assertEquals(wantedPrompt, prompt.plainString()); + assertEquals( wantedPrompt, prompt.plainString() ); // when - statementParser.parseMoreText("bla bla"); // non whitespace + statementParser.parseMoreText( "bla bla" ); // non whitespace prompt = runner.updateAndGetPrompt(); // then - assertEquals("", prompt.plainString()); + assertEquals( "", prompt.plainString() ); } @Test - public void testPromptInTx() throws Exception { + public void testPromptInTx() throws Exception + { // given - InputStream inputStream = new ByteArrayInputStream("".getBytes()); - InteractiveShellRunner runner = new InteractiveShellRunner(cmdExecuter, txHandler, databaseManager, logger, statementParser, inputStream, historyFile, - userMessagesHandler, connectionConfig); + InputStream inputStream = new ByteArrayInputStream( "".getBytes() ); + InteractiveShellRunner runner = new InteractiveShellRunner( cmdExecuter, txHandler, databaseManager, logger, statementParser, inputStream, historyFile, + userMessagesHandler, connectionConfig ); // when - when(txHandler.isTransactionOpen()).thenReturn(true); + when( txHandler.isTransactionOpen() ).thenReturn( true ); AnsiFormattedText prompt = runner.updateAndGetPrompt(); // then String wantedPrompt = "myusername@mydb# "; - assertEquals(wantedPrompt, prompt.plainString()); + assertEquals( wantedPrompt, prompt.plainString() ); // when - statementParser.parseMoreText(" \t \n "); // whitespace + statementParser.parseMoreText( " \t \n " ); // whitespace prompt = runner.updateAndGetPrompt(); // then - assertEquals(wantedPrompt, prompt.plainString()); + assertEquals( wantedPrompt, prompt.plainString() ); // when - statementParser.parseMoreText("bla bla"); // non whitespace + statementParser.parseMoreText( "bla bla" ); // non whitespace prompt = runner.updateAndGetPrompt(); // then - assertEquals(OutputFormatter.repeat(' ', wantedPrompt.length()), prompt.plainString()); + assertEquals( OutputFormatter.repeat( ' ', wantedPrompt.length() ), prompt.plainString() ); } @Test - public void multilineRequiresNewLineOrSemicolonToEnd() throws Exception { + public void multilineRequiresNewLineOrSemicolonToEnd() throws Exception + { // given String inputString = " \\ \nCREATE (n:Person) RETURN n\n"; - InputStream inputStream = new ByteArrayInputStream(inputString.getBytes()); - InteractiveShellRunner runner = new InteractiveShellRunner(cmdExecuter, txHandler, databaseManager, logger, new ShellStatementParser(), inputStream, - historyFile, userMessagesHandler, connectionConfig); + InputStream inputStream = new ByteArrayInputStream( inputString.getBytes() ); + InteractiveShellRunner runner = new InteractiveShellRunner( cmdExecuter, txHandler, databaseManager, logger, new ShellStatementParser(), inputStream, + historyFile, userMessagesHandler, connectionConfig ); // when runner.runUntilEnd(); // then - verify(cmdExecuter).lastNeo4jErrorCode(); - verifyNoMoreInteractions(cmdExecuter); + verify( cmdExecuter ).lastNeo4jErrorCode(); + verifyNoMoreInteractions( cmdExecuter ); } @Test - public void printsWelcomeAndExitMessage() throws Exception { + public void printsWelcomeAndExitMessage() throws Exception + { // given String inputString = "\nCREATE (n:Person) RETURN n\n;\n"; - InputStream inputStream = new ByteArrayInputStream(inputString.getBytes()); - InteractiveShellRunner runner = new InteractiveShellRunner(cmdExecuter, txHandler, databaseManager, logger, - new ShellStatementParser(), inputStream, historyFile, userMessagesHandler, connectionConfig); + InputStream inputStream = new ByteArrayInputStream( inputString.getBytes() ); + InteractiveShellRunner runner = new InteractiveShellRunner( cmdExecuter, txHandler, databaseManager, logger, + new ShellStatementParser(), inputStream, historyFile, userMessagesHandler, + connectionConfig ); // when runner.runUntilEnd(); // then - verify(logger).printIfVerbose("Welcome to cypher-shell!"); - verify(logger).printIfVerbose("Exit message"); + verify( logger ).printIfVerbose( "Welcome to cypher-shell!" ); + verify( logger ).printIfVerbose( "Exit message" ); } @Test - public void multilineEndsOnSemicolonOnNewLine() throws Exception { + public void multilineEndsOnSemicolonOnNewLine() throws Exception + { // given String inputString = "\nCREATE (n:Person) RETURN n\n;\n"; - InputStream inputStream = new ByteArrayInputStream(inputString.getBytes()); - InteractiveShellRunner runner = new InteractiveShellRunner(cmdExecuter, txHandler, databaseManager, logger, new ShellStatementParser(), inputStream, - historyFile, userMessagesHandler, connectionConfig); + InputStream inputStream = new ByteArrayInputStream( inputString.getBytes() ); + InteractiveShellRunner runner = new InteractiveShellRunner( cmdExecuter, txHandler, databaseManager, logger, new ShellStatementParser(), inputStream, + historyFile, userMessagesHandler, connectionConfig ); // when runner.runUntilEnd(); // then - verify(cmdExecuter).execute("CREATE (n:Person) RETURN n\n;"); + verify( cmdExecuter ).execute( "CREATE (n:Person) RETURN n\n;" ); } @Test - public void multilineEndsOnSemicolonOnSameLine() throws Exception { + public void multilineEndsOnSemicolonOnSameLine() throws Exception + { // given String inputString = "\nCREATE (n:Person) RETURN n;\n"; - InputStream inputStream = new ByteArrayInputStream(inputString.getBytes()); - InteractiveShellRunner runner = new InteractiveShellRunner(cmdExecuter, txHandler, databaseManager, logger, new ShellStatementParser(), inputStream, - historyFile, userMessagesHandler, connectionConfig); + InputStream inputStream = new ByteArrayInputStream( inputString.getBytes() ); + InteractiveShellRunner runner = new InteractiveShellRunner( cmdExecuter, txHandler, databaseManager, logger, new ShellStatementParser(), inputStream, + historyFile, userMessagesHandler, connectionConfig ); // when runner.runUntilEnd(); // then - verify(cmdExecuter).execute("CREATE (n:Person) RETURN n;"); + verify( cmdExecuter ).execute( "CREATE (n:Person) RETURN n;" ); } @Test - public void testSignalHandleOutsideExecution() throws Exception { + public void testSignalHandleOutsideExecution() throws Exception + { // given - InputStream inputStream = new ByteArrayInputStream("".getBytes()); - InteractiveShellRunner runner = new InteractiveShellRunner(cmdExecuter, txHandler, databaseManager, logger, - new ShellStatementParser(), inputStream, historyFile, userMessagesHandler, connectionConfig); + InputStream inputStream = new ByteArrayInputStream( "".getBytes() ); + InteractiveShellRunner runner = new InteractiveShellRunner( cmdExecuter, txHandler, databaseManager, logger, + new ShellStatementParser(), inputStream, historyFile, userMessagesHandler, + connectionConfig ); // when - runner.handle(new Signal(InteractiveShellRunner.INTERRUPT_SIGNAL)); + runner.handle( new Signal( InteractiveShellRunner.INTERRUPT_SIGNAL ) ); // then - verify(cmdExecuter).lastNeo4jErrorCode(); - verifyNoMoreInteractions(cmdExecuter); - verify(logger).printError("@|RED \nInterrupted (Note that Cypher queries must end with a |@" + - "@|RED,BOLD semicolon. |@" + - "@|RED Type |@@|RED,BOLD :exit|@@|RED,BOLD |@" + - "@|RED to exit the shell.)|@"); + verify( cmdExecuter ).lastNeo4jErrorCode(); + verifyNoMoreInteractions( cmdExecuter ); + verify( logger ).printError( "@|RED \nInterrupted (Note that Cypher queries must end with a |@" + + "@|RED,BOLD semicolon. |@" + + "@|RED Type |@@|RED,BOLD :exit|@@|RED,BOLD |@" + + "@|RED to exit the shell.)|@" ); } @Test - public void testSignalHandleDuringExecution() throws Exception { + public void testSignalHandleDuringExecution() throws Exception + { // given - BoltStateHandler boltStateHandler = mock(BoltStateHandler.class); - FakeInterruptableShell fakeShell = spy(new FakeInterruptableShell(logger, boltStateHandler)); - InputStream inputStream = new ByteArrayInputStream("RETURN 1;\n".getBytes()); - InteractiveShellRunner runner = new InteractiveShellRunner(fakeShell, fakeShell, fakeShell, logger, - new ShellStatementParser(), inputStream, historyFile, userMessagesHandler, connectionConfig); + BoltStateHandler boltStateHandler = mock( BoltStateHandler.class ); + FakeInterruptableShell fakeShell = spy( new FakeInterruptableShell( logger, boltStateHandler ) ); + InputStream inputStream = new ByteArrayInputStream( "RETURN 1;\n".getBytes() ); + InteractiveShellRunner runner = new InteractiveShellRunner( fakeShell, fakeShell, fakeShell, logger, + new ShellStatementParser(), inputStream, historyFile, userMessagesHandler, + connectionConfig ); // during - Thread t = new Thread(runner::runUntilEnd); + Thread t = new Thread( runner::runUntilEnd ); t.start(); // wait until execution has begun - while (!t.getState().equals(Thread.State.TIMED_WAITING)) { - Thread.sleep(100L); + while ( !t.getState().equals( Thread.State.TIMED_WAITING ) ) + { + Thread.sleep( 100L ); } // when - runner.handle(new Signal(InteractiveShellRunner.INTERRUPT_SIGNAL)); + runner.handle( new Signal( InteractiveShellRunner.INTERRUPT_SIGNAL ) ); // then - verify(fakeShell).execute("RETURN 1;"); - verify(fakeShell).reset(); - verify(boltStateHandler).reset(); - } - - private static class FakeInterruptableShell extends CypherShell { - private AtomicReference executionThread = new AtomicReference<>(); - - FakeInterruptableShell(@Nonnull Logger logger, - @Nonnull BoltStateHandler boltStateHandler) { - super(logger, boltStateHandler, mock(PrettyPrinter.class), new ShellParameterMap()); - } - - @Override - public void execute(@Nonnull String statement) throws ExitException, CommandException { - try { - executionThread.set(Thread.currentThread()); - Thread.sleep(10_000L); - } catch (InterruptedException ignored) { - throw new CommandException("execution interrupted"); - } - } - - @Override - public void reset() { - // Do whatever usually happens - super.reset(); - // But also simulate reset by interrupting the thread - executionThread.get().interrupt(); - } - - @Override - public String getActiveDatabaseAsSetByUser() { - return ABSENT_DB_NAME; - } - - @Override - public String getActualDatabaseAsReportedByServer() { - return DEFAULT_DEFAULT_DB_NAME; - } + verify( fakeShell ).execute( "RETURN 1;" ); + verify( fakeShell ).reset(); + verify( boltStateHandler ).reset(); } - private static class TestInteractiveShellRunner { - InteractiveShellRunner runner; - ByteArrayOutputStream output; - ByteArrayOutputStream error; - BoltStateHandler mockedBoltStateHandler; - - TestInteractiveShellRunner(InteractiveShellRunner runner, ByteArrayOutputStream output, - ByteArrayOutputStream error, BoltStateHandler mockedBoltStateHandler) { - this.runner = runner; - this.output = output; - this.error = error; - this.mockedBoltStateHandler = mockedBoltStateHandler; - } - } - - private TestInteractiveShellRunner setupInteractiveTestShellRunner(String input) throws Exception { + private TestInteractiveShellRunner setupInteractiveTestShellRunner( String input ) throws Exception + { // NOTE: Tests using this will test a bit more of the stack using OfflineTestShell ByteArrayOutputStream output = new ByteArrayOutputStream(); ByteArrayOutputStream error = new ByteArrayOutputStream(); - BoltStateHandler mockedBoltStateHandler = mock(BoltStateHandler.class); - when(mockedBoltStateHandler.getServerVersion()).thenReturn(""); + BoltStateHandler mockedBoltStateHandler = mock( BoltStateHandler.class ); + when( mockedBoltStateHandler.getServerVersion() ).thenReturn( "" ); - final PrettyPrinter mockedPrettyPrinter = mock(PrettyPrinter.class); + final PrettyPrinter mockedPrettyPrinter = mock( PrettyPrinter.class ); - Logger logger = new AnsiLogger(false, Format.VERBOSE, new PrintStream(output), new PrintStream(error)); + Logger logger = new AnsiLogger( false, Format.VERBOSE, new PrintStream( output ), new PrintStream( error ) ); - OfflineTestShell offlineTestShell = new OfflineTestShell(logger, mockedBoltStateHandler, mockedPrettyPrinter); - CommandHelper commandHelper = new CommandHelper(logger, Historian.empty, offlineTestShell); - offlineTestShell.setCommandHelper(commandHelper); + OfflineTestShell offlineTestShell = new OfflineTestShell( logger, mockedBoltStateHandler, mockedPrettyPrinter ); + CommandHelper commandHelper = new CommandHelper( logger, Historian.empty, offlineTestShell ); + offlineTestShell.setCommandHelper( commandHelper ); - InputStream inputStream = new ByteArrayInputStream(input.getBytes()); - InteractiveShellRunner runner = new InteractiveShellRunner(offlineTestShell, offlineTestShell, offlineTestShell, logger, - new ShellStatementParser(), inputStream, historyFile, userMessagesHandler, connectionConfig); + InputStream inputStream = new ByteArrayInputStream( input.getBytes() ); + InteractiveShellRunner runner = new InteractiveShellRunner( offlineTestShell, offlineTestShell, offlineTestShell, logger, + new ShellStatementParser(), inputStream, historyFile, userMessagesHandler, + connectionConfig ); - return new TestInteractiveShellRunner(runner, output, error, mockedBoltStateHandler); + return new TestInteractiveShellRunner( runner, output, error, mockedBoltStateHandler ); } @Test - public void testSwitchToUnavailableDatabase1() throws Exception { + public void testSwitchToUnavailableDatabase1() throws Exception + { // given String input = ":use foo;\n"; - TestInteractiveShellRunner sr = setupInteractiveTestShellRunner(input); + TestInteractiveShellRunner sr = setupInteractiveTestShellRunner( input ); // when - when(sr.mockedBoltStateHandler.getActualDatabaseAsReportedByServer()).thenReturn("foo"); - doThrow(new TransientException(DatabaseManager.DATABASE_UNAVAILABLE_ERROR_CODE, "Not available")) - .when(sr.mockedBoltStateHandler).setActiveDatabase("foo"); + when( sr.mockedBoltStateHandler.getActualDatabaseAsReportedByServer() ).thenReturn( "foo" ); + doThrow( new TransientException( DatabaseManager.DATABASE_UNAVAILABLE_ERROR_CODE, "Not available" ) ) + .when( sr.mockedBoltStateHandler ).setActiveDatabase( "foo" ); sr.runner.runUntilEnd(); // then - assertThat(sr.output.toString(), containsString(format("myusername@foo%s> ", DATABASE_UNAVAILABLE_ERROR_PROMPT_TEXT))); - assertThat(sr.error.toString(), containsString("Not available")); + assertThat( sr.output.toString(), containsString( format( "myusername@foo%s> ", DATABASE_UNAVAILABLE_ERROR_PROMPT_TEXT ) ) ); + assertThat( sr.error.toString(), containsString( "Not available" ) ); } @Test - public void testSwitchToUnavailableDatabase2() throws Exception { + public void testSwitchToUnavailableDatabase2() throws Exception + { // given String input = ":use foo;\n"; - TestInteractiveShellRunner sr = setupInteractiveTestShellRunner(input); + TestInteractiveShellRunner sr = setupInteractiveTestShellRunner( input ); // when - when(sr.mockedBoltStateHandler.getActualDatabaseAsReportedByServer()).thenReturn("foo"); - doThrow(new ServiceUnavailableException("Not available")).when(sr.mockedBoltStateHandler).setActiveDatabase("foo"); + when( sr.mockedBoltStateHandler.getActualDatabaseAsReportedByServer() ).thenReturn( "foo" ); + doThrow( new ServiceUnavailableException( "Not available" ) ).when( sr.mockedBoltStateHandler ).setActiveDatabase( "foo" ); sr.runner.runUntilEnd(); // then - assertThat(sr.output.toString(), containsString(format("myusername@foo%s> ", DATABASE_UNAVAILABLE_ERROR_PROMPT_TEXT))); - assertThat(sr.error.toString(), containsString("Not available")); + assertThat( sr.output.toString(), containsString( format( "myusername@foo%s> ", DATABASE_UNAVAILABLE_ERROR_PROMPT_TEXT ) ) ); + assertThat( sr.error.toString(), containsString( "Not available" ) ); } @Test - public void testSwitchToUnavailableDatabase3() throws Exception { + public void testSwitchToUnavailableDatabase3() throws Exception + { // given String input = ":use foo;\n"; - TestInteractiveShellRunner sr = setupInteractiveTestShellRunner(input); + TestInteractiveShellRunner sr = setupInteractiveTestShellRunner( input ); // when - when(sr.mockedBoltStateHandler.getActualDatabaseAsReportedByServer()).thenReturn("foo"); - doThrow(new DiscoveryException("Not available", null)).when(sr.mockedBoltStateHandler).setActiveDatabase("foo"); + when( sr.mockedBoltStateHandler.getActualDatabaseAsReportedByServer() ).thenReturn( "foo" ); + doThrow( new DiscoveryException( "Not available", null ) ).when( sr.mockedBoltStateHandler ).setActiveDatabase( "foo" ); sr.runner.runUntilEnd(); // then - assertThat(sr.output.toString(), containsString(format("myusername@foo%s> ", DATABASE_UNAVAILABLE_ERROR_PROMPT_TEXT))); - assertThat(sr.error.toString(), containsString("Not available")); + assertThat( sr.output.toString(), containsString( format( "myusername@foo%s> ", DATABASE_UNAVAILABLE_ERROR_PROMPT_TEXT ) ) ); + assertThat( sr.error.toString(), containsString( "Not available" ) ); } @Test - public void testSwitchToNonExistingDatabase() throws Exception { + public void testSwitchToNonExistingDatabase() throws Exception + { // given String input = ":use foo;\n"; - TestInteractiveShellRunner sr = setupInteractiveTestShellRunner(input); + TestInteractiveShellRunner sr = setupInteractiveTestShellRunner( input ); // when - when(sr.mockedBoltStateHandler.getActualDatabaseAsReportedByServer()).thenReturn("mydb"); - doThrow(new ClientException("Non existing")).when(sr.mockedBoltStateHandler).setActiveDatabase("foo"); + when( sr.mockedBoltStateHandler.getActualDatabaseAsReportedByServer() ).thenReturn( "mydb" ); + doThrow( new ClientException( "Non existing" ) ).when( sr.mockedBoltStateHandler ).setActiveDatabase( "foo" ); sr.runner.runUntilEnd(); // then - assertThat(sr.output.toString(), containsString("myusername@mydb> ")); - assertThat(sr.error.toString(), containsString("Non existing")); + assertThat( sr.output.toString(), containsString( "myusername@mydb> " ) ); + assertThat( sr.error.toString(), containsString( "Non existing" ) ); + } + + private static class FakeInterruptableShell extends CypherShell + { + private AtomicReference executionThread = new AtomicReference<>(); + + FakeInterruptableShell( @Nonnull Logger logger, + @Nonnull BoltStateHandler boltStateHandler ) + { + super( logger, boltStateHandler, mock( PrettyPrinter.class ), new ShellParameterMap() ); + } + + @Override + public void execute( @Nonnull String statement ) throws ExitException, CommandException + { + try + { + executionThread.set( Thread.currentThread() ); + Thread.sleep( 10_000L ); + } + catch ( InterruptedException ignored ) + { + throw new CommandException( "execution interrupted" ); + } + } + + @Override + public void reset() + { + // Do whatever usually happens + super.reset(); + // But also simulate reset by interrupting the thread + executionThread.get().interrupt(); + } + + @Override + public String getActiveDatabaseAsSetByUser() + { + return ABSENT_DB_NAME; + } + + @Override + public String getActualDatabaseAsReportedByServer() + { + return DEFAULT_DEFAULT_DB_NAME; + } + } + + private static class TestInteractiveShellRunner + { + InteractiveShellRunner runner; + ByteArrayOutputStream output; + ByteArrayOutputStream error; + BoltStateHandler mockedBoltStateHandler; + + TestInteractiveShellRunner( InteractiveShellRunner runner, ByteArrayOutputStream output, + ByteArrayOutputStream error, BoltStateHandler mockedBoltStateHandler ) + { + this.runner = runner; + this.output = output; + this.error = error; + this.mockedBoltStateHandler = mockedBoltStateHandler; + } } } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/cli/NonInteractiveShellRunnerTest.java b/cypher-shell/src/test/java/org/neo4j/shell/cli/NonInteractiveShellRunnerTest.java index d662c5e8..3123f1fe 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/cli/NonInteractiveShellRunnerTest.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/cli/NonInteractiveShellRunnerTest.java @@ -1,9 +1,31 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.cli; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; + +import java.io.ByteArrayInputStream; + import org.neo4j.driver.exceptions.ClientException; import org.neo4j.shell.Historian; import org.neo4j.shell.StatementExecuter; @@ -13,8 +35,6 @@ import org.neo4j.shell.parser.ShellStatementParser; import org.neo4j.shell.parser.StatementParser; -import java.io.ByteArrayInputStream; - import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.contains; @@ -25,132 +45,140 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; -public class NonInteractiveShellRunnerTest { +public class NonInteractiveShellRunnerTest +{ @Rule public final ExpectedException thrown = ExpectedException.none(); - private Logger logger = mock(Logger.class); - private StatementExecuter cmdExecuter = mock(StatementExecuter.class); + private Logger logger = mock( Logger.class ); + private StatementExecuter cmdExecuter = mock( StatementExecuter.class ); private StatementParser statementParser; private ClientException badLineError; @Before - public void setup() throws CommandException { + public void setup() throws CommandException + { statementParser = new ShellStatementParser(); - badLineError = new ClientException("Found a bad line"); - doThrow(badLineError).when(cmdExecuter).execute(contains("bad")); - doReturn(System.out).when(logger).getOutputStream(); + badLineError = new ClientException( "Found a bad line" ); + doThrow( badLineError ).when( cmdExecuter ).execute( contains( "bad" ) ); + doReturn( System.out ).when( logger ).getOutputStream(); } @Test - public void testSimple() throws Exception { + public void testSimple() throws Exception + { String input = "good1;\n" + - "good2;\n"; + "good2;\n"; NonInteractiveShellRunner runner = new NonInteractiveShellRunner( FailBehavior.FAIL_FAST, cmdExecuter, logger, statementParser, - new ByteArrayInputStream(input.getBytes())); + new ByteArrayInputStream( input.getBytes() ) ); int code = runner.runUntilEnd(); - assertEquals("Exit code incorrect", 0, code); - verify(logger, times(0)).printError(anyString()); + assertEquals( "Exit code incorrect", 0, code ); + verify( logger, times( 0 ) ).printError( anyString() ); } @Test - public void testFailFast() throws Exception { + public void testFailFast() throws Exception + { String input = "good1;\n" + - "bad;\n" + - "good2;\n" + - "bad;\n"; + "bad;\n" + + "good2;\n" + + "bad;\n"; NonInteractiveShellRunner runner = new NonInteractiveShellRunner( FailBehavior.FAIL_FAST, cmdExecuter, logger, statementParser, - new ByteArrayInputStream(input.getBytes())); + new ByteArrayInputStream( input.getBytes() ) ); int code = runner.runUntilEnd(); - assertEquals("Exit code incorrect", 1, code); - verify(logger).printError(badLineError); + assertEquals( "Exit code incorrect", 1, code ); + verify( logger ).printError( badLineError ); } @Test - public void testFailAtEnd() throws Exception { + public void testFailAtEnd() throws Exception + { String input = "good1;\n" + - "bad;\n" + - "good2;\n" + - "bad;\n"; + "bad;\n" + + "good2;\n" + + "bad;\n"; NonInteractiveShellRunner runner = new NonInteractiveShellRunner( FailBehavior.FAIL_AT_END, cmdExecuter, logger, statementParser, - new ByteArrayInputStream(input.getBytes())); + new ByteArrayInputStream( input.getBytes() ) ); int code = runner.runUntilEnd(); - assertEquals("Exit code incorrect", 1, code); - verify(logger, times(2)).printError(badLineError); + assertEquals( "Exit code incorrect", 1, code ); + verify( logger, times( 2 ) ).printError( badLineError ); } @Test - public void runUntilEndExitsImmediatelyOnParseError() throws Exception { + public void runUntilEndExitsImmediatelyOnParseError() throws Exception + { // given - StatementParser statementParser = mock(StatementParser.class); - RuntimeException boom = new RuntimeException("BOOM"); - doThrow(boom).when(statementParser).parseMoreText(anyString()); + StatementParser statementParser = mock( StatementParser.class ); + RuntimeException boom = new RuntimeException( "BOOM" ); + doThrow( boom ).when( statementParser ).parseMoreText( anyString() ); String input = "good1;\n" + - "bad;\n" + - "good2;\n" + - "bad;\n"; + "bad;\n" + + "good2;\n" + + "bad;\n"; NonInteractiveShellRunner runner = new NonInteractiveShellRunner( FailBehavior.FAIL_AT_END, cmdExecuter, logger, statementParser, - new ByteArrayInputStream(input.getBytes())); + new ByteArrayInputStream( input.getBytes() ) ); // when int code = runner.runUntilEnd(); // then - assertEquals(1, code); - verify(logger).printError(boom); + assertEquals( 1, code ); + verify( logger ).printError( boom ); } @Test - public void runUntilEndExitsImmediatelyOnExitCommand() throws Exception { + public void runUntilEndExitsImmediatelyOnExitCommand() throws Exception + { // given String input = "good1;\n" + - "bad;\n" + - "good2;\n" + - "bad;\n"; + "bad;\n" + + "good2;\n" + + "bad;\n"; NonInteractiveShellRunner runner = new NonInteractiveShellRunner( FailBehavior.FAIL_AT_END, cmdExecuter, logger, statementParser, - new ByteArrayInputStream(input.getBytes())); + new ByteArrayInputStream( input.getBytes() ) ); // when - doThrow(new ExitException(99)).when(cmdExecuter).execute(anyString()); + doThrow( new ExitException( 99 ) ).when( cmdExecuter ).execute( anyString() ); int code = runner.runUntilEnd(); // then - assertEquals(99, code); - verify(cmdExecuter).execute("good1;"); - verifyNoMoreInteractions(cmdExecuter); + assertEquals( 99, code ); + verify( cmdExecuter ).execute( "good1;" ); + verifyNoMoreInteractions( cmdExecuter ); } @Test - public void nonInteractiveHasNoHistory() throws Exception { + public void nonInteractiveHasNoHistory() throws Exception + { // given NonInteractiveShellRunner runner = new NonInteractiveShellRunner( FailBehavior.FAIL_AT_END, cmdExecuter, logger, statementParser, - new ByteArrayInputStream("".getBytes())); + new ByteArrayInputStream( "".getBytes() ) ); // when then - assertEquals(Historian.empty, runner.getHistorian()); + assertEquals( Historian.empty, runner.getHistorian() ); } } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/commands/BeginTest.java b/cypher-shell/src/test/java/org/neo4j/shell/commands/BeginTest.java index 86b422a9..8c549156 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/commands/BeginTest.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/commands/BeginTest.java @@ -1,10 +1,29 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.commands; - import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; + import org.neo4j.shell.TransactionHandler; import org.neo4j.shell.exception.CommandException; @@ -12,30 +31,34 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; -public class BeginTest { +public class BeginTest +{ @Rule public final ExpectedException thrown = ExpectedException.none(); private Command beginCommand; - private TransactionHandler mockShell = mock(TransactionHandler.class); + private TransactionHandler mockShell = mock( TransactionHandler.class ); @Before - public void setup() { - this.beginCommand = new Begin(mockShell); + public void setup() + { + this.beginCommand = new Begin( mockShell ); } @Test - public void shouldNotAcceptArgs() throws CommandException { - thrown.expect(CommandException.class); - thrown.expectMessage(containsString("Incorrect number of arguments")); + public void shouldNotAcceptArgs() throws CommandException + { + thrown.expect( CommandException.class ); + thrown.expectMessage( containsString( "Incorrect number of arguments" ) ); - beginCommand.execute("bob"); + beginCommand.execute( "bob" ); } @Test - public void beginTransactionOnShell() throws CommandException { - beginCommand.execute(""); + public void beginTransactionOnShell() throws CommandException + { + beginCommand.execute( "" ); - verify(mockShell).beginTransaction(); + verify( mockShell ).beginTransaction(); } } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/commands/CommitTest.java b/cypher-shell/src/test/java/org/neo4j/shell/commands/CommitTest.java index 317cc0fa..9e778694 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/commands/CommitTest.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/commands/CommitTest.java @@ -1,42 +1,63 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.commands; - import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; + import org.neo4j.shell.TransactionHandler; import org.neo4j.shell.exception.CommandException; -import org.neo4j.shell.log.Logger; import static org.hamcrest.CoreMatchers.containsString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; - -public class CommitTest { +public class CommitTest +{ @Rule public final ExpectedException thrown = ExpectedException.none(); private Command commitCommand; - private TransactionHandler mockShell = mock(TransactionHandler.class); + private TransactionHandler mockShell = mock( TransactionHandler.class ); @Before - public void setup() { - this.commitCommand = new Commit(mockShell); + public void setup() + { + this.commitCommand = new Commit( mockShell ); } @Test - public void shouldNotAcceptArgs() throws CommandException { - thrown.expect(CommandException.class); - thrown.expectMessage(containsString("Incorrect number of arguments")); + public void shouldNotAcceptArgs() throws CommandException + { + thrown.expect( CommandException.class ); + thrown.expectMessage( containsString( "Incorrect number of arguments" ) ); - commitCommand.execute("bob"); + commitCommand.execute( "bob" ); } @Test - public void commitTransactionOnShell() throws CommandException { - commitCommand.execute(""); + public void commitTransactionOnShell() throws CommandException + { + commitCommand.execute( "" ); - verify(mockShell).commitTransaction(); + verify( mockShell ).commitTransaction(); } } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/commands/ExitTest.java b/cypher-shell/src/test/java/org/neo4j/shell/commands/ExitTest.java index 2f63f2a7..697f6c52 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/commands/ExitTest.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/commands/ExitTest.java @@ -1,10 +1,29 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.commands; - import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; + import org.neo4j.shell.exception.CommandException; import org.neo4j.shell.exception.ExitException; import org.neo4j.shell.log.Logger; @@ -12,34 +31,37 @@ import static junit.framework.TestCase.fail; import static org.hamcrest.CoreMatchers.containsString; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -public class ExitTest { +public class ExitTest +{ @Rule public final ExpectedException thrown = ExpectedException.none(); - Logger logger = mock(Logger.class); + Logger logger = mock( Logger.class ); private Exit cmd; @Before - public void setup() { - this.cmd = new Exit(logger); + public void setup() + { + this.cmd = new Exit( logger ); } @Test - public void shouldNotAcceptArgs() throws CommandException { - thrown.expect(CommandException.class); - thrown.expectMessage(containsString("Incorrect number of arguments")); + public void shouldNotAcceptArgs() throws CommandException + { + thrown.expect( CommandException.class ); + thrown.expectMessage( containsString( "Incorrect number of arguments" ) ); - cmd.execute("bob"); - fail("Should not accept args"); + cmd.execute( "bob" ); + fail( "Should not accept args" ); } @Test - public void shouldExitShell() throws CommandException { - thrown.expect(ExitException.class); + public void shouldExitShell() throws CommandException + { + thrown.expect( ExitException.class ); - cmd.execute(""); + cmd.execute( "" ); } } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/commands/HelpTest.java b/cypher-shell/src/test/java/org/neo4j/shell/commands/HelpTest.java index 7db1d00e..e89a22e8 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/commands/HelpTest.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/commands/HelpTest.java @@ -1,151 +1,189 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.commands; - import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import org.neo4j.shell.exception.CommandException; -import org.neo4j.shell.exception.ExitException; -import org.neo4j.shell.log.Logger; -import javax.annotation.Nonnull; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import javax.annotation.Nonnull; + +import org.neo4j.shell.exception.CommandException; +import org.neo4j.shell.exception.ExitException; +import org.neo4j.shell.log.Logger; import static junit.framework.TestCase.fail; import static org.hamcrest.CoreMatchers.containsString; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; -public class HelpTest { +public class HelpTest +{ @Rule public final ExpectedException thrown = ExpectedException.none(); - private Logger logger = mock(Logger.class); - private CommandHelper cmdHelper = mock(CommandHelper.class); + private Logger logger = mock( Logger.class ); + private CommandHelper cmdHelper = mock( CommandHelper.class ); private Command cmd; @Before - public void setup() { + public void setup() + { - this.cmd = new Help(logger, cmdHelper); + this.cmd = new Help( logger, cmdHelper ); } @Test - public void shouldAcceptNoArgs() throws CommandException { - cmd.execute(""); + public void shouldAcceptNoArgs() throws CommandException + { + cmd.execute( "" ); // Should not throw } @Test - public void shouldNotAcceptTooManyArgs() throws CommandException { - thrown.expect(CommandException.class); - thrown.expectMessage(containsString("Incorrect number of arguments")); + public void shouldNotAcceptTooManyArgs() throws CommandException + { + thrown.expect( CommandException.class ); + thrown.expectMessage( containsString( "Incorrect number of arguments" ) ); - cmd.execute("bob alice"); - fail("Should not accept too many args"); + cmd.execute( "bob alice" ); + fail( "Should not accept too many args" ); } @Test - public void helpListing() throws CommandException { + public void helpListing() throws CommandException + { // given List commandList = new ArrayList<>(); - commandList.add(new FakeCommand("bob")); - commandList.add(new FakeCommand("bobby")); + commandList.add( new FakeCommand( "bob" ) ); + commandList.add( new FakeCommand( "bobby" ) ); - doReturn(commandList).when(cmdHelper).getAllCommands(); + doReturn( commandList ).when( cmdHelper ).getAllCommands(); // when - cmd.execute(""); + cmd.execute( "" ); // then - verify(logger).printOut("\nAvailable commands:"); - verify(logger).printOut(" @|BOLD bob |@ description for bob"); - verify(logger).printOut(" @|BOLD bobby|@ description for bobby"); - verify(logger).printOut("\nFor help on a specific command type:"); - verify(logger).printOut(" :help@|BOLD command|@\n"); - verify(logger).printOut("\nFor help on cypher please visit:"); - verify(logger).printOut(" " + Help.CYPHER_REFCARD_LINK + "\n"); + verify( logger ).printOut( "\nAvailable commands:" ); + verify( logger ).printOut( " @|BOLD bob |@ description for bob" ); + verify( logger ).printOut( " @|BOLD bobby|@ description for bobby" ); + verify( logger ).printOut( "\nFor help on a specific command type:" ); + verify( logger ).printOut( " :help@|BOLD command|@\n" ); + verify( logger ).printOut( "\nFor help on cypher please visit:" ); + verify( logger ).printOut( " " + Help.CYPHER_REFCARD_LINK + "\n" ); } @Test - public void helpForCommand() throws CommandException { + public void helpForCommand() throws CommandException + { // given - doReturn(new FakeCommand("bob")).when(cmdHelper).getCommand(eq("bob")); + doReturn( new FakeCommand( "bob" ) ).when( cmdHelper ).getCommand( eq( "bob" ) ); // when - cmd.execute("bob"); + cmd.execute( "bob" ); // then - verify(logger).printOut("\nusage: @|BOLD bob|@ usage for bob\n" - + "\nhelp for bob\n"); + verify( logger ).printOut( "\nusage: @|BOLD bob|@ usage for bob\n" + + "\nhelp for bob\n" ); } @Test - public void helpForNonExistingCommandThrows() throws CommandException { + public void helpForNonExistingCommandThrows() throws CommandException + { // then - thrown.expect(CommandException.class); - thrown.expectMessage("No such command: notacommandname"); + thrown.expect( CommandException.class ); + thrown.expectMessage( "No such command: notacommandname" ); // when - cmd.execute("notacommandname"); + cmd.execute( "notacommandname" ); } @Test - public void helpForCommandHasOptionalColon() throws CommandException { + public void helpForCommandHasOptionalColon() throws CommandException + { // given - doReturn(new FakeCommand(":bob")).when(cmdHelper).getCommand(eq(":bob")); + doReturn( new FakeCommand( ":bob" ) ).when( cmdHelper ).getCommand( eq( ":bob" ) ); // when - cmd.execute("bob"); + cmd.execute( "bob" ); // then - verify(logger).printOut("\nusage: @|BOLD :bob|@ usage for :bob\n" - + "\nhelp for :bob\n"); + verify( logger ).printOut( "\nusage: @|BOLD :bob|@ usage for :bob\n" + + "\nhelp for :bob\n" ); } - private class FakeCommand implements Command { + private class FakeCommand implements Command + { private final String name; - FakeCommand(String name) { + FakeCommand( String name ) + { this.name = name; } @Nonnull @Override - public String getName() { + public String getName() + { return name; } @Nonnull @Override - public String getDescription() { + public String getDescription() + { return "description for " + name; } @Nonnull @Override - public String getUsage() { + public String getUsage() + { return "usage for " + name; } @Nonnull @Override - public String getHelp() { + public String getHelp() + { return "help for " + name; } @Nonnull @Override - public List getAliases() { + public List getAliases() + { return Collections.emptyList(); } @Override - public void execute(@Nonnull String args) throws ExitException, CommandException { + public void execute( @Nonnull String args ) throws ExitException, CommandException + { } } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/commands/HistoryTest.java b/cypher-shell/src/test/java/org/neo4j/shell/commands/HistoryTest.java index 189f9cb8..c0f3ed86 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/commands/HistoryTest.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/commands/HistoryTest.java @@ -1,50 +1,76 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.commands; - import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; + +import java.util.Arrays; + import org.neo4j.shell.Historian; import org.neo4j.shell.exception.CommandException; import org.neo4j.shell.log.Logger; -import java.util.Arrays; - import static junit.framework.TestCase.fail; import static org.hamcrest.CoreMatchers.containsString; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; -public class HistoryTest { +public class HistoryTest +{ @Rule public final ExpectedException thrown = ExpectedException.none(); - private Logger logger = mock(Logger.class); - private Historian historian = mock(Historian.class); + private Logger logger = mock( Logger.class ); + private Historian historian = mock( Historian.class ); private Command cmd; @Before - public void setup() { - this.cmd = new History(logger, historian); + public void setup() + { + this.cmd = new History( logger, historian ); } @Test - public void shouldNotAcceptArgs() throws CommandException { - thrown.expect(CommandException.class); - thrown.expectMessage(containsString("Incorrect number of arguments")); + public void shouldNotAcceptArgs() throws CommandException + { + thrown.expect( CommandException.class ); + thrown.expectMessage( containsString( "Incorrect number of arguments" ) ); - cmd.execute("bob"); - fail("Should not accept args"); + cmd.execute( "bob" ); + fail( "Should not accept args" ); } @Test - public void shouldPrintHistoryCorrectlyNumberedFrom1() throws CommandException { - when(historian.getHistory()).thenReturn(Arrays.asList(":help", ":exit")); + public void shouldPrintHistoryCorrectlyNumberedFrom1() throws CommandException + { + when( historian.getHistory() ).thenReturn( Arrays.asList( ":help", ":exit" ) ); - cmd.execute(""); + cmd.execute( "" ); - verify(logger).printOut(eq(" 1 :help\n" + - " 2 :exit\n")); + verify( logger ).printOut( eq( " 1 :help\n" + + " 2 :exit\n" ) ); } } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/commands/ParamTest.java b/cypher-shell/src/test/java/org/neo4j/shell/commands/ParamTest.java index 8e7a473c..4968691f 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/commands/ParamTest.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/commands/ParamTest.java @@ -1,6 +1,24 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.commands; - import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -16,169 +34,191 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; -public class ParamTest { +public class ParamTest +{ @Rule public final ExpectedException thrown = ExpectedException.none(); - private ParameterMap mockShell = mock( ParameterMap.class); + private ParameterMap mockShell = mock( ParameterMap.class ); private Command cmd; @Before - public void setup() { - this.cmd = new Param(mockShell); + public void setup() + { + this.cmd = new Param( mockShell ); } @Test - public void shouldFailIfNoArgs() throws CommandException { - thrown.expect(CommandException.class); - thrown.expectMessage(containsString("Incorrect number of arguments")); + public void shouldFailIfNoArgs() throws CommandException + { + thrown.expect( CommandException.class ); + thrown.expectMessage( containsString( "Incorrect number of arguments" ) ); - cmd.execute(""); + cmd.execute( "" ); } @Test - public void shouldFailIfOneArg() throws CommandException { - thrown.expect(CommandException.class); - thrown.expectMessage(containsString("Incorrect number of arguments")); + public void shouldFailIfOneArg() throws CommandException + { + thrown.expect( CommandException.class ); + thrown.expectMessage( containsString( "Incorrect number of arguments" ) ); - cmd.execute("bob"); + cmd.execute( "bob" ); } @Test - public void setParam() throws EvaluationException, CommandException { - cmd.execute("bob 9"); + public void setParam() throws EvaluationException, CommandException + { + cmd.execute( "bob 9" ); - verify(mockShell).setParameter("bob", "9"); + verify( mockShell ).setParameter( "bob", "9" ); } @Test - public void setLambdasAsParam() throws EvaluationException, CommandException { - cmd.execute("bob => 9"); + public void setLambdasAsParam() throws EvaluationException, CommandException + { + cmd.execute( "bob => 9" ); - verify(mockShell).setParameter("bob", "9"); + verify( mockShell ).setParameter( "bob", "9" ); } @Test - public void setLambdasAsParamWithBackticks() throws EvaluationException, CommandException { - cmd.execute("`bob` => 9"); + public void setLambdasAsParamWithBackticks() throws EvaluationException, CommandException + { + cmd.execute( "`bob` => 9" ); - verify(mockShell).setParameter("`bob`", "9"); + verify( mockShell ).setParameter( "`bob`", "9" ); } @Test - public void setSpecialCharacterParameter() throws EvaluationException, CommandException { - cmd.execute("bØb 9"); + public void setSpecialCharacterParameter() throws EvaluationException, CommandException + { + cmd.execute( "bØb 9" ); - verify(mockShell).setParameter("bØb", "9"); + verify( mockShell ).setParameter( "bØb", "9" ); } @Test - public void setSpecialCharacterParameterForLambdaExpressions() throws EvaluationException, CommandException { - cmd.execute("`first=>Name` => \"Bruce\""); + public void setSpecialCharacterParameterForLambdaExpressions() throws EvaluationException, CommandException + { + cmd.execute( "`first=>Name` => \"Bruce\"" ); - verify(mockShell).setParameter("`first=>Name`", "\"Bruce\""); + verify( mockShell ).setParameter( "`first=>Name`", "\"Bruce\"" ); } @Test - public void setParamWithSpecialCharacters() throws EvaluationException, CommandException { - cmd.execute("`bob#` 9"); + public void setParamWithSpecialCharacters() throws EvaluationException, CommandException + { + cmd.execute( "`bob#` 9" ); - verify(mockShell).setParameter("`bob#`", "9"); + verify( mockShell ).setParameter( "`bob#`", "9" ); } @Test - public void setParamWithOddNoOfBackTicks() throws EvaluationException, CommandException { - cmd.execute(" `bo `` sömething ``` 9"); + public void setParamWithOddNoOfBackTicks() throws EvaluationException, CommandException + { + cmd.execute( " `bo `` sömething ``` 9" ); - verify(mockShell).setParameter("`bo `` sömething ```", "9"); + verify( mockShell ).setParameter( "`bo `` sömething ```", "9" ); } @Test - public void shouldFailForVariablesWithoutEscaping() throws CommandException { - thrown.expect(CommandException.class); - thrown.expectMessage(containsString("Incorrect number of arguments")); + public void shouldFailForVariablesWithoutEscaping() throws CommandException + { + thrown.expect( CommandException.class ); + thrown.expectMessage( containsString( "Incorrect number of arguments" ) ); - cmd.execute("bob# 9"); + cmd.execute( "bob# 9" ); - fail("Expected error"); + fail( "Expected error" ); } @Test - public void shouldFailForVariablesMixingMapStyleAssignmentAndLambdas() throws CommandException { - thrown.expect(CommandException.class); - thrown.expectMessage(containsString("Incorrect usage")); + public void shouldFailForVariablesMixingMapStyleAssignmentAndLambdas() throws CommandException + { + thrown.expect( CommandException.class ); + thrown.expectMessage( containsString( "Incorrect usage" ) ); - cmd.execute("bob: => 9"); + cmd.execute( "bob: => 9" ); - fail("Expected error"); + fail( "Expected error" ); } @Test - public void shouldFailForEmptyVariables() throws CommandException { - thrown.expect(CommandException.class); - thrown.expectMessage(containsString("Incorrect number of arguments")); + public void shouldFailForEmptyVariables() throws CommandException + { + thrown.expect( CommandException.class ); + thrown.expectMessage( containsString( "Incorrect number of arguments" ) ); - cmd.execute("`` 9"); + cmd.execute( "`` 9" ); - fail("Expected error"); + fail( "Expected error" ); } @Test - public void shouldFailForInvalidVariables() throws CommandException { - thrown.expect(CommandException.class); - thrown.expectMessage(containsString("Incorrect number of arguments")); + public void shouldFailForInvalidVariables() throws CommandException + { + thrown.expect( CommandException.class ); + thrown.expectMessage( containsString( "Incorrect number of arguments" ) ); - cmd.execute("` 9"); + cmd.execute( "` 9" ); - fail("Expected error"); + fail( "Expected error" ); } @Test - public void shouldFailForVariablesWithoutText() throws CommandException { - thrown.expect(CommandException.class); - thrown.expectMessage(containsString("Incorrect number of arguments")); + public void shouldFailForVariablesWithoutText() throws CommandException + { + thrown.expect( CommandException.class ); + thrown.expectMessage( containsString( "Incorrect number of arguments" ) ); - cmd.execute("``` 9"); + cmd.execute( "``` 9" ); - fail("Expected error"); + fail( "Expected error" ); } @Test - public void shouldNotSplitOnSpace() throws EvaluationException, CommandException { - cmd.execute("bob 'one two'"); - verify(mockShell).setParameter("bob", "'one two'"); + public void shouldNotSplitOnSpace() throws EvaluationException, CommandException + { + cmd.execute( "bob 'one two'" ); + verify( mockShell ).setParameter( "bob", "'one two'" ); } @Test - public void shouldAcceptUnicodeAlphaNumeric() throws EvaluationException, CommandException { - cmd.execute("böb 'one two'"); - verify(mockShell).setParameter("böb", "'one two'"); + public void shouldAcceptUnicodeAlphaNumeric() throws EvaluationException, CommandException + { + cmd.execute( "böb 'one two'" ); + verify( mockShell ).setParameter( "böb", "'one two'" ); } @Test - public void shouldAcceptColonFormOfParams() throws EvaluationException, CommandException { - cmd.execute("bob: one"); - verify(mockShell).setParameter("bob", "one"); + public void shouldAcceptColonFormOfParams() throws EvaluationException, CommandException + { + cmd.execute( "bob: one" ); + verify( mockShell ).setParameter( "bob", "one" ); } @Test - public void shouldAcceptForTwoColonsFormOfParams() throws EvaluationException, CommandException { - cmd.execute("`bob:`: one"); - verify(mockShell).setParameter("`bob:`", "one"); + public void shouldAcceptForTwoColonsFormOfParams() throws EvaluationException, CommandException + { + cmd.execute( "`bob:`: one" ); + verify( mockShell ).setParameter( "`bob:`", "one" ); - cmd.execute("`t:om` two"); - verify(mockShell).setParameter("`t:om`", "two"); + cmd.execute( "`t:om` two" ); + verify( mockShell ).setParameter( "`t:om`", "two" ); } @Test - public void shouldNotExecuteEscapedCypher() throws EvaluationException, CommandException { - cmd.execute("bob \"RETURN 5 as bob\""); - verify(mockShell).setParameter("bob", "\"RETURN 5 as bob\""); + public void shouldNotExecuteEscapedCypher() throws EvaluationException, CommandException + { + cmd.execute( "bob \"RETURN 5 as bob\"" ); + verify( mockShell ).setParameter( "bob", "\"RETURN 5 as bob\"" ); } @Test - public void printUsage() { + public void printUsage() + { String usage = cmd.getUsage(); - assertEquals(usage, "name => value"); + assertEquals( usage, "name => value" ); } } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/commands/ParamsTest.java b/cypher-shell/src/test/java/org/neo4j/shell/commands/ParamsTest.java index 300457ff..84364521 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/commands/ParamsTest.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/commands/ParamsTest.java @@ -1,16 +1,36 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.commands; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; + +import java.util.HashMap; + import org.neo4j.shell.ParameterMap; import org.neo4j.shell.exception.CommandException; import org.neo4j.shell.log.Logger; import org.neo4j.shell.state.ParamValue; -import java.util.HashMap; - import static org.hamcrest.CoreMatchers.containsString; import static org.junit.Assert.assertNotNull; import static org.mockito.Mockito.mock; @@ -18,7 +38,8 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; -public class ParamsTest { +public class ParamsTest +{ @Rule public final ExpectedException thrown = ExpectedException.none(); @@ -27,119 +48,131 @@ public class ParamsTest { private Params cmd; @Before - public void setup() throws CommandException { + public void setup() throws CommandException + { vars = new HashMap<>(); - logger = mock(Logger.class); - ParameterMap shell = mock( ParameterMap.class); - when(shell.getAllAsUserInput()).thenReturn(vars); - cmd = new Params(logger, shell); + logger = mock( Logger.class ); + ParameterMap shell = mock( ParameterMap.class ); + when( shell.getAllAsUserInput() ).thenReturn( vars ); + cmd = new Params( logger, shell ); } @Test - public void descriptionNotNull() { - assertNotNull(cmd.getDescription()); + public void descriptionNotNull() + { + assertNotNull( cmd.getDescription() ); } @Test - public void usageNotNull() { - assertNotNull(cmd.getUsage()); + public void usageNotNull() + { + assertNotNull( cmd.getUsage() ); } @Test - public void helpNotNull() { - assertNotNull(cmd.getHelp()); + public void helpNotNull() + { + assertNotNull( cmd.getHelp() ); } @Test - public void runCommand() throws CommandException { + public void runCommand() throws CommandException + { // given String var = "var"; int value = 9; - vars.put(var, new ParamValue(String.valueOf(value), value)); + vars.put( var, new ParamValue( String.valueOf( value ), value ) ); // when - cmd.execute(""); + cmd.execute( "" ); // then - verify(logger).printOut(":param var => 9"); - verifyNoMoreInteractions(logger); + verify( logger ).printOut( ":param var => 9" ); + verifyNoMoreInteractions( logger ); } @Test - public void runCommandAlignment() throws CommandException { + public void runCommandAlignment() throws CommandException + { // given - vars.put("var", new ParamValue(String.valueOf(9), 9)); - vars.put("param", new ParamValue(String.valueOf(99999), 99999)); + vars.put( "var", new ParamValue( String.valueOf( 9 ), 9 ) ); + vars.put( "param", new ParamValue( String.valueOf( 99999 ), 99999 ) ); // when - cmd.execute(""); + cmd.execute( "" ); // then - verify(logger).printOut(":param param => 99999"); - verify(logger).printOut(":param var => 9"); - verifyNoMoreInteractions(logger); + verify( logger ).printOut( ":param param => 99999" ); + verify( logger ).printOut( ":param var => 9" ); + verifyNoMoreInteractions( logger ); } @Test - public void runCommandWithArg() throws CommandException { + public void runCommandWithArg() throws CommandException + { // given - vars.put("var", new ParamValue(String.valueOf(9), 9)); - vars.put("param", new ParamValue(String.valueOf(9999), 9999)); + vars.put( "var", new ParamValue( String.valueOf( 9 ), 9 ) ); + vars.put( "param", new ParamValue( String.valueOf( 9999 ), 9999 ) ); // when - cmd.execute("var"); + cmd.execute( "var" ); // then - verify(logger).printOut(":param var => 9"); - verifyNoMoreInteractions(logger); + verify( logger ).printOut( ":param var => 9" ); + verifyNoMoreInteractions( logger ); } @Test - public void runCommandWithArgWithExtraSpace() throws CommandException { + public void runCommandWithArgWithExtraSpace() throws CommandException + { // given - vars.put("var", new ParamValue(String.valueOf(9), 9)); - vars.put("param", new ParamValue(String.valueOf(9999), 9999)); + vars.put( "var", new ParamValue( String.valueOf( 9 ), 9 ) ); + vars.put( "param", new ParamValue( String.valueOf( 9999 ), 9999 ) ); // when - cmd.execute(" var"); + cmd.execute( " var" ); // then - verify(logger).printOut(":param var => 9"); - verifyNoMoreInteractions(logger); + verify( logger ).printOut( ":param var => 9" ); + verifyNoMoreInteractions( logger ); } @Test - public void runCommandWithArgWithBackticks() throws CommandException { + public void runCommandWithArgWithBackticks() throws CommandException + { // given - vars.put("var", new ParamValue(String.valueOf(9), 9)); - vars.put("param", new ParamValue(String.valueOf(9999), 9999)); + vars.put( "var", new ParamValue( String.valueOf( 9 ), 9 ) ); + vars.put( "param", new ParamValue( String.valueOf( 9999 ), 9999 ) ); // when - cmd.execute("`var`"); + cmd.execute( "`var`" ); // then - verify(logger).printOut(":param `var` => 9"); - verifyNoMoreInteractions(logger); + verify( logger ).printOut( ":param `var` => 9" ); + verifyNoMoreInteractions( logger ); } @Test - public void runCommandWithSpecialCharacters() throws CommandException { + public void runCommandWithSpecialCharacters() throws CommandException + { // given - vars.put("var `", new ParamValue(String.valueOf(9), 9)); - vars.put("param", new ParamValue(String.valueOf(9999), 9999)); + vars.put( "var `", new ParamValue( String.valueOf( 9 ), 9 ) ); + vars.put( "param", new ParamValue( String.valueOf( 9999 ), 9999 ) ); // when - cmd.execute("`var ```"); + cmd.execute( "`var ```" ); // then - verify(logger).printOut(":param `var ``` => 9"); - verifyNoMoreInteractions(logger); + verify( logger ).printOut( ":param `var ``` => 9" ); + verifyNoMoreInteractions( logger ); } @Test - public void runCommandWithUnknownArg() throws CommandException { + public void runCommandWithUnknownArg() throws CommandException + { // then - thrown.expect(CommandException.class); - thrown.expectMessage(containsString("Unknown parameter: bob")); + thrown.expect( CommandException.class ); + thrown.expectMessage( containsString( "Unknown parameter: bob" ) ); // given - vars.put("var", new ParamValue(String.valueOf(9), 9)); + vars.put( "var", new ParamValue( String.valueOf( 9 ), 9 ) ); // when - cmd.execute("bob"); + cmd.execute( "bob" ); } @Test - public void shouldNotAcceptMoreThanOneArgs() throws CommandException { - thrown.expect(CommandException.class); - thrown.expectMessage(containsString("Incorrect number of arguments")); + public void shouldNotAcceptMoreThanOneArgs() throws CommandException + { + thrown.expect( CommandException.class ); + thrown.expectMessage( containsString( "Incorrect number of arguments" ) ); - cmd.execute("bob sob"); + cmd.execute( "bob sob" ); } } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/commands/RollbackTest.java b/cypher-shell/src/test/java/org/neo4j/shell/commands/RollbackTest.java index 97458ab5..5419a533 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/commands/RollbackTest.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/commands/RollbackTest.java @@ -1,10 +1,29 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.commands; - import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; + import org.neo4j.shell.TransactionHandler; import org.neo4j.shell.exception.CommandException; @@ -12,32 +31,34 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; -public class RollbackTest { - - private Command rollbackCommand; +public class RollbackTest +{ @Rule public final ExpectedException thrown = ExpectedException.none(); - private TransactionHandler mockShell = mock(TransactionHandler.class); - + private Command rollbackCommand; + private TransactionHandler mockShell = mock( TransactionHandler.class ); @Before - public void setup() { - this.rollbackCommand = new Rollback(mockShell); + public void setup() + { + this.rollbackCommand = new Rollback( mockShell ); } @Test - public void shouldNotAcceptArgs() throws CommandException { - thrown.expect(CommandException.class); - thrown.expectMessage(containsString("Incorrect number of arguments")); + public void shouldNotAcceptArgs() throws CommandException + { + thrown.expect( CommandException.class ); + thrown.expectMessage( containsString( "Incorrect number of arguments" ) ); - rollbackCommand.execute("bob"); + rollbackCommand.execute( "bob" ); } @Test - public void rollbackTransaction() throws CommandException { - rollbackCommand.execute(""); + public void rollbackTransaction() throws CommandException + { + rollbackCommand.execute( "" ); - verify(mockShell).rollbackTransaction(); + verify( mockShell ).rollbackTransaction(); } } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/commands/SourceTest.java b/cypher-shell/src/test/java/org/neo4j/shell/commands/SourceTest.java index b4baf1d2..74755104 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/commands/SourceTest.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/commands/SourceTest.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.commands; import org.junit.Before; @@ -31,61 +50,67 @@ public class SourceTest @Before public void setup() { - logger = mock(Logger.class); - shell = mock(CypherShell.class); - cmd = new Source(shell, new ShellStatementParser() ); + logger = mock( Logger.class ); + shell = mock( CypherShell.class ); + cmd = new Source( shell, new ShellStatementParser() ); } @Test - public void descriptionNotNull() { - assertNotNull(cmd.getDescription()); + public void descriptionNotNull() + { + assertNotNull( cmd.getDescription() ); } @Test - public void usageNotNull() { - assertNotNull(cmd.getUsage()); + public void usageNotNull() + { + assertNotNull( cmd.getUsage() ); } @Test - public void helpNotNull() { - assertNotNull(cmd.getHelp()); + public void helpNotNull() + { + assertNotNull( cmd.getHelp() ); } @Test - public void runCommand() throws CommandException { + public void runCommand() throws CommandException + { // given - cmd.execute( fileFromResource( "test.cypher" ) ); - verify(shell).execute( "RETURN 42;" ); - verifyNoMoreInteractions( shell ); + cmd.execute( fileFromResource( "test.cypher" ) ); + verify( shell ).execute( "RETURN 42;" ); + verifyNoMoreInteractions( shell ); } @Test public void shouldFailIfFileNotThere() throws CommandException { thrown.expect( CommandException.class ); - thrown.expectMessage(containsString("Cannot find file: 'not.there'")); - thrown.expectCause(isA(FileNotFoundException.class)); + thrown.expectMessage( containsString( "Cannot find file: 'not.there'" ) ); + thrown.expectCause( isA( FileNotFoundException.class ) ); cmd.execute( "not.there" ); } @Test - public void shouldNotAcceptMoreThanOneArgs() throws CommandException { - thrown.expect(CommandException.class); - thrown.expectMessage(containsString("Incorrect number of arguments")); + public void shouldNotAcceptMoreThanOneArgs() throws CommandException + { + thrown.expect( CommandException.class ); + thrown.expectMessage( containsString( "Incorrect number of arguments" ) ); - cmd.execute("bob sob"); + cmd.execute( "bob sob" ); } @Test - public void shouldNotAcceptZeroArgs() throws CommandException { - thrown.expect(CommandException.class); - thrown.expectMessage(containsString("Incorrect number of arguments")); + public void shouldNotAcceptZeroArgs() throws CommandException + { + thrown.expect( CommandException.class ); + thrown.expectMessage( containsString( "Incorrect number of arguments" ) ); - cmd.execute(""); + cmd.execute( "" ); } - private String fileFromResource(String filename) + private String fileFromResource( String filename ) { - return getClass().getResource(filename).getFile(); + return getClass().getResource( filename ).getFile(); } } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/commands/UseTest.java b/cypher-shell/src/test/java/org/neo4j/shell/commands/UseTest.java index 65de54c1..5bd44a42 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/commands/UseTest.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/commands/UseTest.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.commands; import org.junit.Before; @@ -19,40 +38,45 @@ public class UseTest @Rule public final ExpectedException thrown = ExpectedException.none(); - private DatabaseManager mockShell = mock(DatabaseManager.class); + private DatabaseManager mockShell = mock( DatabaseManager.class ); private Command cmd; @Before - public void setup() { - this.cmd = new Use(mockShell); + public void setup() + { + this.cmd = new Use( mockShell ); } @Test - public void setAbsentDatabaseOnNoArgument() throws CommandException { - cmd.execute(""); + public void setAbsentDatabaseOnNoArgument() throws CommandException + { + cmd.execute( "" ); - verify(mockShell).setActiveDatabase(DatabaseManager.ABSENT_DB_NAME); + verify( mockShell ).setActiveDatabase( DatabaseManager.ABSENT_DB_NAME ); } @Test - public void shouldFailIfMoreThanOneArg() throws CommandException { - thrown.expect(CommandException.class); - thrown.expectMessage(containsString("Incorrect number of arguments")); + public void shouldFailIfMoreThanOneArg() throws CommandException + { + thrown.expect( CommandException.class ); + thrown.expectMessage( containsString( "Incorrect number of arguments" ) ); - cmd.execute("db1 db2"); - fail("Expected error"); + cmd.execute( "db1 db2" ); + fail( "Expected error" ); } @Test - public void setActiveDatabase() throws CommandException { - cmd.execute("db1"); + public void setActiveDatabase() throws CommandException + { + cmd.execute( "db1" ); - verify(mockShell).setActiveDatabase("db1"); + verify( mockShell ).setActiveDatabase( "db1" ); } @Test - public void printUsage() throws CommandException { + public void printUsage() throws CommandException + { String usage = cmd.getUsage(); - assertEquals(usage, "database"); + assertEquals( usage, "database" ); } } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/log/AnsiFormattedTextTest.java b/cypher-shell/src/test/java/org/neo4j/shell/log/AnsiFormattedTextTest.java index ceda9af2..65a0d7b7 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/log/AnsiFormattedTextTest.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/log/AnsiFormattedTextTest.java @@ -1,86 +1,112 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.log; - import org.junit.Test; import static org.junit.Assert.assertEquals; -public class AnsiFormattedTextTest { +public class AnsiFormattedTextTest +{ @Test - public void simpleString() { - AnsiFormattedText st = AnsiFormattedText.from("hello"); - assertEquals("hello", st.plainString()); - assertEquals("hello", st.formattedString()); + public void simpleString() + { + AnsiFormattedText st = AnsiFormattedText.from( "hello" ); + assertEquals( "hello", st.plainString() ); + assertEquals( "hello", st.formattedString() ); } @Test - public void noStyleShouldBePlain() throws Exception { + public void noStyleShouldBePlain() throws Exception + { AnsiFormattedText st = AnsiFormattedText.s() .colorDefault() .boldOff() - .append("yo"); + .append( "yo" ); - assertEquals("yo", st.plainString()); - assertEquals("yo", st.formattedString()); + assertEquals( "yo", st.plainString() ); + assertEquals( "yo", st.formattedString() ); } @Test - public void withFormatting() throws Exception { + public void withFormatting() throws Exception + { AnsiFormattedText st = AnsiFormattedText.s() .bold() .colorRed() - .append("hello") + .append( "hello" ) .colorDefault() .boldOff() - .append(" world"); + .append( " world" ); - assertEquals("hello world", st.plainString()); - assertEquals("@|RED,BOLD hello|@ world", st.formattedString()); + assertEquals( "hello world", st.plainString() ); + assertEquals( "@|RED,BOLD hello|@ world", st.formattedString() ); } @Test - public void nestedFormattingWorks() throws Exception { + public void nestedFormattingWorks() throws Exception + { AnsiFormattedText st = AnsiFormattedText.s() .colorDefault() .bold() - .append("hello") + .append( "hello" ) .boldOff() - .append(" world"); - st = AnsiFormattedText.s().colorRed().append(st); + .append( " world" ); + st = AnsiFormattedText.s().colorRed().append( st ); - assertEquals("hello world", st.plainString()); - assertEquals("@|RED,BOLD hello|@@|RED world|@", st.formattedString()); + assertEquals( "hello world", st.plainString() ); + assertEquals( "@|RED,BOLD hello|@@|RED world|@", st.formattedString() ); } @Test - public void outerAttributeTakesColorPrecedence() throws Exception { - AnsiFormattedText st = AnsiFormattedText.s().colorRed().append("inner"); + public void outerAttributeTakesColorPrecedence() throws Exception + { + AnsiFormattedText st = AnsiFormattedText.s().colorRed().append( "inner" ); - assertEquals("@|RED inner|@", st.formattedString()); + assertEquals( "@|RED inner|@", st.formattedString() ); - st = AnsiFormattedText.s().colorDefault().append(st); + st = AnsiFormattedText.s().colorDefault().append( st ); - assertEquals("inner", st.formattedString()); + assertEquals( "inner", st.formattedString() ); } @Test - public void outerAttributeTakesBoldPrecedence() throws Exception { - AnsiFormattedText st = AnsiFormattedText.s().colorRed().bold().append("inner"); + public void outerAttributeTakesBoldPrecedence() throws Exception + { + AnsiFormattedText st = AnsiFormattedText.s().colorRed().bold().append( "inner" ); - assertEquals("@|RED,BOLD inner|@", st.formattedString()); + assertEquals( "@|RED,BOLD inner|@", st.formattedString() ); - st = AnsiFormattedText.s().boldOff().append(st); + st = AnsiFormattedText.s().boldOff().append( st ); - assertEquals("@|RED inner|@", st.formattedString()); + assertEquals( "@|RED inner|@", st.formattedString() ); } @Test - public void shouldAppend() throws Exception { - AnsiFormattedText st = AnsiFormattedText.from("hello"); + public void shouldAppend() throws Exception + { + AnsiFormattedText st = AnsiFormattedText.from( "hello" ); - st = st.append(" world"); + st = st.append( " world" ); - assertEquals("hello world", st.plainString()); + assertEquals( "hello world", st.plainString() ); } } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/log/AnsiLoggerTest.java b/cypher-shell/src/test/java/org/neo4j/shell/log/AnsiLoggerTest.java index ba9457af..22b84f2f 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/log/AnsiLoggerTest.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/log/AnsiLoggerTest.java @@ -1,13 +1,33 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.log; import org.junit.Before; import org.junit.Test; + +import java.io.PrintStream; + import org.neo4j.driver.exceptions.ClientException; import org.neo4j.shell.cli.Format; import org.neo4j.shell.exception.CommandException; -import java.io.PrintStream; - import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.contains; import static org.mockito.Mockito.mock; @@ -15,149 +35,166 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; - -public class AnsiLoggerTest { +public class AnsiLoggerTest +{ private PrintStream out; private PrintStream err; private AnsiLogger logger; @Before - public void setup() { - out = mock(PrintStream.class); - err = mock(PrintStream.class); - logger = new AnsiLogger(false, Format.VERBOSE, out, err); + public void setup() + { + out = mock( PrintStream.class ); + err = mock( PrintStream.class ); + logger = new AnsiLogger( false, Format.VERBOSE, out, err ); } @Test - public void defaultStreams() throws Exception { - Logger logger = new AnsiLogger(false); + public void defaultStreams() throws Exception + { + Logger logger = new AnsiLogger( false ); - assertEquals(System.out, logger.getOutputStream()); - assertEquals(System.err, logger.getErrorStream()); + assertEquals( System.out, logger.getOutputStream() ); + assertEquals( System.err, logger.getErrorStream() ); } @Test - public void customStreams() throws Exception { - assertEquals(out, logger.getOutputStream()); - assertEquals(err, logger.getErrorStream()); + public void customStreams() throws Exception + { + assertEquals( out, logger.getOutputStream() ); + assertEquals( err, logger.getErrorStream() ); } @Test - public void printError() throws Exception { - logger.printError("bob"); - verify(err).println("bob"); + public void printError() throws Exception + { + logger.printError( "bob" ); + verify( err ).println( "bob" ); } @Test - public void printException() throws Exception { - logger.printError(new Throwable("bam")); - verify(err).println("bam"); + public void printException() throws Exception + { + logger.printError( new Throwable( "bam" ) ); + verify( err ).println( "bam" ); } @Test - public void printExceptionWithDebug() throws Exception { - Logger logger = new AnsiLogger(true, Format.VERBOSE, out, err); - logger.printError(new Throwable("bam")); - verify(err).println(contains("java.lang.Throwable: bam")); - verify(err).println(contains("at org.neo4j.shell.log.AnsiLoggerTest.printExceptionWithDebug")); + public void printExceptionWithDebug() throws Exception + { + Logger logger = new AnsiLogger( true, Format.VERBOSE, out, err ); + logger.printError( new Throwable( "bam" ) ); + verify( err ).println( contains( "java.lang.Throwable: bam" ) ); + verify( err ).println( contains( "at org.neo4j.shell.log.AnsiLoggerTest.printExceptionWithDebug" ) ); } @Test - public void printOut() throws Exception { - logger.printOut("sob"); - verify(out).println("sob"); + public void printOut() throws Exception + { + logger.printOut( "sob" ); + verify( out ).println( "sob" ); } @Test - public void printOutManyShouldNotBuildState() throws Exception { - logger.printOut("bob"); - logger.printOut("nob"); - logger.printOut("cod"); + public void printOutManyShouldNotBuildState() throws Exception + { + logger.printOut( "bob" ); + logger.printOut( "nob" ); + logger.printOut( "cod" ); - verify(out).println("bob"); - verify(out).println("nob"); - verify(out).println("cod"); + verify( out ).println( "bob" ); + verify( out ).println( "nob" ); + verify( out ).println( "cod" ); } @Test - public void printErrManyShouldNotBuildState() throws Exception { - logger.printError("bob"); - logger.printError("nob"); - logger.printError("cod"); + public void printErrManyShouldNotBuildState() throws Exception + { + logger.printError( "bob" ); + logger.printError( "nob" ); + logger.printError( "cod" ); - verify(err).println("bob"); - verify(err).println("nob"); - verify(err).println("cod"); + verify( err ).println( "bob" ); + verify( err ).println( "nob" ); + verify( err ).println( "cod" ); } @Test - public void printIfVerbose() throws Exception { - logger = new AnsiLogger(false, Format.VERBOSE, out, err); + public void printIfVerbose() throws Exception + { + logger = new AnsiLogger( false, Format.VERBOSE, out, err ); - logger.printIfDebug("deb"); - logger.printIfVerbose("foo"); - logger.printIfPlain("bar"); + logger.printIfDebug( "deb" ); + logger.printIfVerbose( "foo" ); + logger.printIfPlain( "bar" ); - verify(out).println("foo"); - verifyNoMoreInteractions(out); + verify( out ).println( "foo" ); + verifyNoMoreInteractions( out ); } @Test - public void printIfPlain() throws Exception { - logger = new AnsiLogger(false, Format.PLAIN, out, err); + public void printIfPlain() throws Exception + { + logger = new AnsiLogger( false, Format.PLAIN, out, err ); - logger.printIfDebug("deb"); - logger.printIfVerbose("foo"); - logger.printIfPlain("bar"); + logger.printIfDebug( "deb" ); + logger.printIfVerbose( "foo" ); + logger.printIfPlain( "bar" ); - verify(out).println("bar"); - verifyNoMoreInteractions(out); + verify( out ).println( "bar" ); + verifyNoMoreInteractions( out ); } @Test - public void printIfDebug() throws Exception { - logger = new AnsiLogger(true, Format.PLAIN, out, err); + public void printIfDebug() throws Exception + { + logger = new AnsiLogger( true, Format.PLAIN, out, err ); - logger.printIfDebug("deb"); - logger.printIfVerbose("foo"); - logger.printIfPlain("bar"); + logger.printIfDebug( "deb" ); + logger.printIfVerbose( "foo" ); + logger.printIfPlain( "bar" ); - verify(out).println("deb"); - verify(out).println("bar"); - verifyNoMoreInteractions(out); + verify( out ).println( "deb" ); + verify( out ).println( "bar" ); + verifyNoMoreInteractions( out ); } @Test - public void testSimple() { - assertEquals("@|RED yahoo|@", logger.getFormattedMessage(new NullPointerException("yahoo"))); + public void testSimple() + { + assertEquals( "@|RED yahoo|@", logger.getFormattedMessage( new NullPointerException( "yahoo" ) ) ); } @Test - public void testNested() { - assertEquals("@|RED outer|@", logger.getFormattedMessage(new ClientException("outer", - new CommandException("nested")))); + public void testNested() + { + assertEquals( "@|RED outer|@", logger.getFormattedMessage( new ClientException( "outer", + new CommandException( "nested" ) ) ) ); } @Test - public void testNestedDeep() { - assertEquals("@|RED outer|@", logger.getFormattedMessage( - new ClientException("outer", - new ClientException("nested", - new ClientException("nested deep"))))); + public void testNestedDeep() + { + assertEquals( "@|RED outer|@", logger.getFormattedMessage( + new ClientException( "outer", + new ClientException( "nested", + new ClientException( "nested deep" ) ) ) ) ); } @Test - public void testNullMessage() { - assertEquals("@|RED ClientException|@", logger.getFormattedMessage(new ClientException(null))); - assertEquals("@|RED outer|@", - logger.getFormattedMessage(new ClientException("outer", new NullPointerException(null)))); + public void testNullMessage() + { + assertEquals( "@|RED ClientException|@", logger.getFormattedMessage( new ClientException( null ) ) ); + assertEquals( "@|RED outer|@", + logger.getFormattedMessage( new ClientException( "outer", new NullPointerException( null ) ) ) ); } @Test - public void testExceptionGetsFormattedMessage() { - AnsiLogger logger = spy(this.logger); - logger.printError(new NullPointerException("yahoo")); - verify(logger).printError("@|RED yahoo|@"); + public void testExceptionGetsFormattedMessage() + { + AnsiLogger logger = spy( this.logger ); + logger.printError( new NullPointerException( "yahoo" ) ); + verify( logger ).printError( "@|RED yahoo|@" ); } } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/parser/ShellStatementParserTest.java b/cypher-shell/src/test/java/org/neo4j/shell/parser/ShellStatementParserTest.java index fa8d077c..18c2fbf4 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/parser/ShellStatementParserTest.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/parser/ShellStatementParserTest.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.parser; import org.junit.Before; @@ -11,407 +30,430 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -public class ShellStatementParserTest { +public class ShellStatementParserTest +{ @Rule public final ExpectedException thrown = ExpectedException.none(); private ShellStatementParser parser; @Before - public void setup() { + public void setup() + { parser = new ShellStatementParser(); } @Test - public void parseEmptyLineDoesNothing() throws Exception { + public void parseEmptyLineDoesNothing() throws Exception + { // when - parser.parseMoreText("\n"); + parser.parseMoreText( "\n" ); // then - assertFalse(parser.containsText()); - assertFalse(parser.hasStatements()); - assertEquals(0, parser.consumeStatements().size()); + assertFalse( parser.containsText() ); + assertFalse( parser.hasStatements() ); + assertEquals( 0, parser.consumeStatements().size() ); } @Test - public void parseAShellCommand() throws Exception { + public void parseAShellCommand() throws Exception + { // when - parser.parseMoreText(" :help exit bob snob "); + parser.parseMoreText( " :help exit bob snob " ); // then - assertFalse(parser.containsText()); - assertTrue(parser.hasStatements()); + assertFalse( parser.containsText() ); + assertTrue( parser.hasStatements() ); List statements = parser.consumeStatements(); - assertEquals(1, statements.size()); - assertEquals(" :help exit bob snob ", statements.get(0)); + assertEquals( 1, statements.size() ); + assertEquals( " :help exit bob snob ", statements.get( 0 ) ); - assertFalse(parser.hasStatements()); - assertEquals(0, parser.consumeStatements().size()); + assertFalse( parser.hasStatements() ); + assertEquals( 0, parser.consumeStatements().size() ); } @Test - public void parseAShellCommandWithNewLine() throws Exception { + public void parseAShellCommandWithNewLine() throws Exception + { // when - parser.parseMoreText(":help exit bob snob\n"); + parser.parseMoreText( ":help exit bob snob\n" ); // then - assertFalse(parser.containsText()); - assertTrue(parser.hasStatements()); + assertFalse( parser.containsText() ); + assertTrue( parser.hasStatements() ); List statements = parser.consumeStatements(); - assertEquals(1, statements.size()); - assertEquals(":help exit bob snob\n", statements.get(0)); + assertEquals( 1, statements.size() ); + assertEquals( ":help exit bob snob\n", statements.get( 0 ) ); - assertFalse(parser.hasStatements()); - assertEquals(0, parser.consumeStatements().size()); + assertFalse( parser.hasStatements() ); + assertEquals( 0, parser.consumeStatements().size() ); } @Test - public void parseIncompleteCypher() throws Exception { + public void parseIncompleteCypher() throws Exception + { // when - parser.parseMoreText("CREATE ()\n"); + parser.parseMoreText( "CREATE ()\n" ); // then - assertTrue(parser.containsText()); - assertFalse(parser.hasStatements()); - assertEquals(0, parser.consumeStatements().size()); + assertTrue( parser.containsText() ); + assertFalse( parser.hasStatements() ); + assertEquals( 0, parser.consumeStatements().size() ); } @Test - public void parseCompleteCypher() throws Exception { + public void parseCompleteCypher() throws Exception + { // when - parser.parseMoreText("CREATE (n)\n"); - assertTrue(parser.containsText()); - parser.parseMoreText("CREATE ();"); - assertFalse(parser.containsText()); + parser.parseMoreText( "CREATE (n)\n" ); + assertTrue( parser.containsText() ); + parser.parseMoreText( "CREATE ();" ); + assertFalse( parser.containsText() ); // then - assertTrue(parser.hasStatements()); + assertTrue( parser.hasStatements() ); List statements = parser.consumeStatements(); - assertEquals(1, statements.size()); - assertEquals("CREATE (n)\nCREATE ();", statements.get(0)); + assertEquals( 1, statements.size() ); + assertEquals( "CREATE (n)\nCREATE ();", statements.get( 0 ) ); - assertFalse(parser.hasStatements()); - assertEquals(0, parser.consumeStatements().size()); + assertFalse( parser.hasStatements() ); + assertEquals( 0, parser.consumeStatements().size() ); } @Test - public void parseMultipleCypherSingleLine() throws Exception { + public void parseMultipleCypherSingleLine() throws Exception + { // when - parser.parseMoreText("RETURN 1;RETURN 2;"); + parser.parseMoreText( "RETURN 1;RETURN 2;" ); // then - assertTrue(parser.hasStatements()); + assertTrue( parser.hasStatements() ); List statements = parser.consumeStatements(); - assertEquals(2, statements.size()); - assertEquals("RETURN 1;", statements.get(0)); - assertEquals("RETURN 2;", statements.get(1)); + assertEquals( 2, statements.size() ); + assertEquals( "RETURN 1;", statements.get( 0 ) ); + assertEquals( "RETURN 2;", statements.get( 1 ) ); - assertFalse(parser.hasStatements()); - assertEquals(0, parser.consumeStatements().size()); - assertFalse(parser.containsText()); + assertFalse( parser.hasStatements() ); + assertEquals( 0, parser.consumeStatements().size() ); + assertFalse( parser.containsText() ); } @Test - public void parseMultipleCypherMultipleLine() throws Exception { + public void parseMultipleCypherMultipleLine() throws Exception + { // when - parser.parseMoreText("RETURN 1;"); - parser.parseMoreText("RETURN 2;"); + parser.parseMoreText( "RETURN 1;" ); + parser.parseMoreText( "RETURN 2;" ); // then - assertTrue(parser.hasStatements()); + assertTrue( parser.hasStatements() ); List statements = parser.consumeStatements(); - assertEquals(2, statements.size()); - assertEquals("RETURN 1;", statements.get(0)); - assertEquals("RETURN 2;", statements.get(1)); + assertEquals( 2, statements.size() ); + assertEquals( "RETURN 1;", statements.get( 0 ) ); + assertEquals( "RETURN 2;", statements.get( 1 ) ); - assertFalse(parser.hasStatements()); - assertEquals(0, parser.consumeStatements().size()); - assertFalse(parser.containsText()); + assertFalse( parser.hasStatements() ); + assertEquals( 0, parser.consumeStatements().size() ); + assertFalse( parser.containsText() ); } @Test - public void singleQuotedSemicolon() throws Exception { + public void singleQuotedSemicolon() throws Exception + { // when - parser.parseMoreText("hello '\n"); - parser.parseMoreText(";\n"); - parser.parseMoreText("'\n"); - parser.parseMoreText(";\n"); + parser.parseMoreText( "hello '\n" ); + parser.parseMoreText( ";\n" ); + parser.parseMoreText( "'\n" ); + parser.parseMoreText( ";\n" ); // then - assertTrue(parser.hasStatements()); + assertTrue( parser.hasStatements() ); List statements = parser.consumeStatements(); - assertEquals(1, statements.size()); - assertEquals("hello '\n;\n'\n;", statements.get(0)); + assertEquals( 1, statements.size() ); + assertEquals( "hello '\n;\n'\n;", statements.get( 0 ) ); - assertFalse(parser.hasStatements()); - assertEquals(0, parser.consumeStatements().size()); - assertFalse(parser.containsText()); + assertFalse( parser.hasStatements() ); + assertEquals( 0, parser.consumeStatements().size() ); + assertFalse( parser.containsText() ); } @Test - public void backtickQuotedSemicolon() throws Exception { + public void backtickQuotedSemicolon() throws Exception + { // when - parser.parseMoreText("hello `\n"); - parser.parseMoreText(";\n"); - parser.parseMoreText("`\n"); - parser.parseMoreText("; \n"); + parser.parseMoreText( "hello `\n" ); + parser.parseMoreText( ";\n" ); + parser.parseMoreText( "`\n" ); + parser.parseMoreText( "; \n" ); // then - assertTrue(parser.hasStatements()); + assertTrue( parser.hasStatements() ); List statements = parser.consumeStatements(); - assertEquals(1, statements.size()); - assertEquals("hello `\n;\n`\n;", statements.get(0)); + assertEquals( 1, statements.size() ); + assertEquals( "hello `\n;\n`\n;", statements.get( 0 ) ); - assertFalse(parser.hasStatements()); - assertEquals(0, parser.consumeStatements().size()); - assertFalse(parser.containsText()); + assertFalse( parser.hasStatements() ); + assertEquals( 0, parser.consumeStatements().size() ); + assertFalse( parser.containsText() ); } @Test - public void doubleQuotedSemicolon() throws Exception { + public void doubleQuotedSemicolon() throws Exception + { // when - parser.parseMoreText("hello \"\n"); - parser.parseMoreText(";\n"); - parser.parseMoreText("\"\n"); - parser.parseMoreText("; \n"); + parser.parseMoreText( "hello \"\n" ); + parser.parseMoreText( ";\n" ); + parser.parseMoreText( "\"\n" ); + parser.parseMoreText( "; \n" ); // then - assertTrue(parser.hasStatements()); + assertTrue( parser.hasStatements() ); List statements = parser.consumeStatements(); - assertEquals(1, statements.size()); - assertEquals("hello \"\n;\n\"\n;", statements.get(0)); + assertEquals( 1, statements.size() ); + assertEquals( "hello \"\n;\n\"\n;", statements.get( 0 ) ); - assertFalse(parser.hasStatements()); - assertEquals(0, parser.consumeStatements().size()); - assertFalse(parser.containsText()); + assertFalse( parser.hasStatements() ); + assertEquals( 0, parser.consumeStatements().size() ); + assertFalse( parser.containsText() ); } @Test - public void escapedChars() throws Exception { + public void escapedChars() throws Exception + { // when - parser.parseMoreText("one \\;\n"); - parser.parseMoreText("\"two \\\"\n"); - parser.parseMoreText(";\n"); - parser.parseMoreText("\";\n"); + parser.parseMoreText( "one \\;\n" ); + parser.parseMoreText( "\"two \\\"\n" ); + parser.parseMoreText( ";\n" ); + parser.parseMoreText( "\";\n" ); // then - assertTrue(parser.hasStatements()); + assertTrue( parser.hasStatements() ); List statements = parser.consumeStatements(); - assertEquals(1, statements.size()); - assertEquals("one \\;\n\"two \\\"\n;\n\";", statements.get(0)); + assertEquals( 1, statements.size() ); + assertEquals( "one \\;\n\"two \\\"\n;\n\";", statements.get( 0 ) ); - assertFalse(parser.hasStatements()); - assertEquals(0, parser.consumeStatements().size()); - assertFalse(parser.containsText()); + assertFalse( parser.hasStatements() ); + assertEquals( 0, parser.consumeStatements().size() ); + assertFalse( parser.containsText() ); } @Test - public void nestedQuoting() throws Exception { + public void nestedQuoting() throws Exception + { // when - parser.parseMoreText("go `tick;'single;\"double;\n"); - parser.parseMoreText("end`;\n"); + parser.parseMoreText( "go `tick;'single;\"double;\n" ); + parser.parseMoreText( "end`;\n" ); // then - assertTrue(parser.hasStatements()); + assertTrue( parser.hasStatements() ); List statements = parser.consumeStatements(); - assertEquals(1, statements.size()); - assertEquals("go `tick;'single;\"double;\nend`;", statements.get(0)); + assertEquals( 1, statements.size() ); + assertEquals( "go `tick;'single;\"double;\nend`;", statements.get( 0 ) ); - assertFalse(parser.hasStatements()); - assertEquals(0, parser.consumeStatements().size()); - assertFalse(parser.containsText()); + assertFalse( parser.hasStatements() ); + assertEquals( 0, parser.consumeStatements().size() ); + assertFalse( parser.containsText() ); } @Test - public void mixCommandAndCypherWithSpacingsAdded() throws Exception { + public void mixCommandAndCypherWithSpacingsAdded() throws Exception + { // when - parser.parseMoreText(" :help me \n"); - parser.parseMoreText(" cypher me up \n"); - parser.parseMoreText(" :scotty \n"); - parser.parseMoreText(" ; \n"); - parser.parseMoreText(" :do it now! \n"); + parser.parseMoreText( " :help me \n" ); + parser.parseMoreText( " cypher me up \n" ); + parser.parseMoreText( " :scotty \n" ); + parser.parseMoreText( " ; \n" ); + parser.parseMoreText( " :do it now! \n" ); // then - assertTrue(parser.hasStatements()); + assertTrue( parser.hasStatements() ); List statements = parser.consumeStatements(); - assertEquals(3, statements.size()); - assertEquals(" :help me \n", statements.get(0)); - assertEquals(" cypher me up \n :scotty \n ;", statements.get(1)); - assertEquals(" :do it now! \n", statements.get(2)); + assertEquals( 3, statements.size() ); + assertEquals( " :help me \n", statements.get( 0 ) ); + assertEquals( " cypher me up \n :scotty \n ;", statements.get( 1 ) ); + assertEquals( " :do it now! \n", statements.get( 2 ) ); - assertFalse(parser.hasStatements()); - assertEquals(0, parser.consumeStatements().size()); - assertFalse(parser.containsText()); + assertFalse( parser.hasStatements() ); + assertEquals( 0, parser.consumeStatements().size() ); + assertFalse( parser.containsText() ); } @Test - public void commentHandlingIfSemicolon() throws Exception { + public void commentHandlingIfSemicolon() throws Exception + { // when - parser.parseMoreText(" first // ;\n"); - parser.parseMoreText("// /* ;\n"); - parser.parseMoreText(" third ; // actually a semicolon here\n"); + parser.parseMoreText( " first // ;\n" ); + parser.parseMoreText( "// /* ;\n" ); + parser.parseMoreText( " third ; // actually a semicolon here\n" ); // then - assertTrue(parser.hasStatements()); - assertFalse(parser.containsText()); + assertTrue( parser.hasStatements() ); + assertFalse( parser.containsText() ); List statements = parser.consumeStatements(); - assertEquals(1, statements.size()); - assertEquals(" first third ;", statements.get(0)); + assertEquals( 1, statements.size() ); + assertEquals( " first third ;", statements.get( 0 ) ); - assertFalse(parser.hasStatements()); - assertEquals(0, parser.consumeStatements().size()); + assertFalse( parser.hasStatements() ); + assertEquals( 0, parser.consumeStatements().size() ); } @Test - public void backslashDeadInBlockQuote() throws Exception { + public void backslashDeadInBlockQuote() throws Exception + { // when - parser.parseMoreText("/* block \\*/\nCREATE ();"); + parser.parseMoreText( "/* block \\*/\nCREATE ();" ); // then - assertTrue(parser.hasStatements()); + assertTrue( parser.hasStatements() ); List statements = parser.consumeStatements(); - assertEquals(1, statements.size()); - assertEquals("\nCREATE ();", statements.get(0)); + assertEquals( 1, statements.size() ); + assertEquals( "\nCREATE ();", statements.get( 0 ) ); - assertFalse(parser.hasStatements()); - assertEquals(0, parser.consumeStatements().size()); - assertFalse(parser.containsText()); + assertFalse( parser.hasStatements() ); + assertEquals( 0, parser.consumeStatements().size() ); + assertFalse( parser.containsText() ); } @Test - public void commentInQuote() throws Exception { + public void commentInQuote() throws Exception + { // when - parser.parseMoreText("` here // comment `;"); + parser.parseMoreText( "` here // comment `;" ); // then - assertTrue(parser.hasStatements()); + assertTrue( parser.hasStatements() ); List statements = parser.consumeStatements(); - assertEquals(1, statements.size()); - assertEquals("` here // comment `;", statements.get(0)); + assertEquals( 1, statements.size() ); + assertEquals( "` here // comment `;", statements.get( 0 ) ); - assertFalse(parser.hasStatements()); - assertEquals(0, parser.consumeStatements().size()); - assertFalse(parser.containsText()); + assertFalse( parser.hasStatements() ); + assertEquals( 0, parser.consumeStatements().size() ); + assertFalse( parser.containsText() ); } @Test - public void blockCommentInQuote() throws Exception { + public void blockCommentInQuote() throws Exception + { // when - parser.parseMoreText("` here /* comment `;"); + parser.parseMoreText( "` here /* comment `;" ); // then - assertTrue(parser.hasStatements()); + assertTrue( parser.hasStatements() ); List statements = parser.consumeStatements(); - assertEquals(1, statements.size()); - assertEquals("` here /* comment `;", statements.get(0)); + assertEquals( 1, statements.size() ); + assertEquals( "` here /* comment `;", statements.get( 0 ) ); - assertFalse(parser.hasStatements()); - assertEquals(0, parser.consumeStatements().size()); - assertFalse(parser.containsText()); + assertFalse( parser.hasStatements() ); + assertEquals( 0, parser.consumeStatements().size() ); + assertFalse( parser.containsText() ); } @Test - public void quoteInComment() throws Exception { + public void quoteInComment() throws Exception + { // when - parser.parseMoreText("// `;\n;"); + parser.parseMoreText( "// `;\n;" ); // then - assertTrue(parser.hasStatements()); + assertTrue( parser.hasStatements() ); List statements = parser.consumeStatements(); - assertEquals(1, statements.size()); - assertEquals(";", statements.get(0)); + assertEquals( 1, statements.size() ); + assertEquals( ";", statements.get( 0 ) ); - assertFalse(parser.hasStatements()); - assertEquals(0, parser.consumeStatements().size()); - assertFalse(parser.containsText()); + assertFalse( parser.hasStatements() ); + assertEquals( 0, parser.consumeStatements().size() ); + assertFalse( parser.containsText() ); } @Test - public void quoteInBlockomment() throws Exception { + public void quoteInBlockomment() throws Exception + { // when - parser.parseMoreText("/* `;\n;*/\n;"); + parser.parseMoreText( "/* `;\n;*/\n;" ); // then - assertTrue(parser.hasStatements()); + assertTrue( parser.hasStatements() ); List statements = parser.consumeStatements(); - assertEquals(1, statements.size()); - assertEquals("\n;", statements.get(0)); + assertEquals( 1, statements.size() ); + assertEquals( "\n;", statements.get( 0 ) ); - assertFalse(parser.hasStatements()); - assertEquals(0, parser.consumeStatements().size()); - assertFalse(parser.containsText()); + assertFalse( parser.hasStatements() ); + assertEquals( 0, parser.consumeStatements().size() ); + assertFalse( parser.containsText() ); } @Test - public void testReset() throws Exception { + public void testReset() throws Exception + { // given - parser.parseMoreText("/* `;\n;*/\n;"); - parser.parseMoreText("bob"); - assertTrue(parser.hasStatements()); - assertTrue(parser.containsText()); + parser.parseMoreText( "/* `;\n;*/\n;" ); + parser.parseMoreText( "bob" ); + assertTrue( parser.hasStatements() ); + assertTrue( parser.containsText() ); // when parser.reset(); - + // then - assertFalse(parser.hasStatements()); - assertFalse(parser.containsText()); + assertFalse( parser.hasStatements() ); + assertFalse( parser.containsText() ); } @Test - public void commentsBeforeBegin() throws Exception { + public void commentsBeforeBegin() throws Exception + { // when - parser.parseMoreText("//comment \n"); - parser.parseMoreText(":begin\n"); - parser.parseMoreText("RETURN 42;\n"); - parser.parseMoreText(":end\n"); + parser.parseMoreText( "//comment \n" ); + parser.parseMoreText( ":begin\n" ); + parser.parseMoreText( "RETURN 42;\n" ); + parser.parseMoreText( ":end\n" ); // then - assertTrue(parser.hasStatements()); + assertTrue( parser.hasStatements() ); List statements = parser.consumeStatements(); - assertEquals(3, statements.size()); - assertEquals(":begin\n", statements.get(0)); - assertEquals("RETURN 42;", statements.get(1)); - assertEquals(":end\n", statements.get(2)); + assertEquals( 3, statements.size() ); + assertEquals( ":begin\n", statements.get( 0 ) ); + assertEquals( "RETURN 42;", statements.get( 1 ) ); + assertEquals( ":end\n", statements.get( 2 ) ); - assertFalse(parser.hasStatements()); - assertEquals(0, parser.consumeStatements().size()); - assertFalse(parser.containsText()); + assertFalse( parser.hasStatements() ); + assertEquals( 0, parser.consumeStatements().size() ); + assertFalse( parser.containsText() ); } } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/prettyprint/CypherVariablesFormatterTest.java b/cypher-shell/src/test/java/org/neo4j/shell/prettyprint/CypherVariablesFormatterTest.java index fe2d2f32..be329120 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/prettyprint/CypherVariablesFormatterTest.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/prettyprint/CypherVariablesFormatterTest.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.prettyprint; import org.junit.Test; @@ -5,32 +24,35 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; -public class CypherVariablesFormatterTest { +public class CypherVariablesFormatterTest +{ private final CypherVariablesFormatter formatter = new CypherVariablesFormatter(); @Test - public void escapeNonAlphanumericStrings() throws Exception { - assertThat(formatter.escape("abc12_A"), is("abc12_A")); - assertThat(formatter.escape("Åbc12_A"), is("Åbc12_A")); - assertThat(formatter.escape("\0"), is("`\0`")); - assertThat(formatter.escape("\n"), is("`\n`")); - assertThat(formatter.escape("comma, separated"), is("`comma, separated`")); - assertThat(formatter.escape("escaped content `back ticks #"), is("`escaped content ``back ticks #`")); - assertThat(formatter.escape("escaped content two `back `ticks"), - is("`escaped content two ``back ``ticks`")); + public void escapeNonAlphanumericStrings() throws Exception + { + assertThat( formatter.escape( "abc12_A" ), is( "abc12_A" ) ); + assertThat( formatter.escape( "Åbc12_A" ), is( "Åbc12_A" ) ); + assertThat( formatter.escape( "\0" ), is( "`\0`" ) ); + assertThat( formatter.escape( "\n" ), is( "`\n`" ) ); + assertThat( formatter.escape( "comma, separated" ), is( "`comma, separated`" ) ); + assertThat( formatter.escape( "escaped content `back ticks #" ), is( "`escaped content ``back ticks #`" ) ); + assertThat( formatter.escape( "escaped content two `back `ticks" ), + is( "`escaped content two ``back ``ticks`" ) ); } @Test - public void reEscapeNonAlphanumericStrings() throws Exception { - assertThat(formatter.unescapedCypherVariable("abc12_A"), is("abc12_A")); - assertThat(formatter.unescapedCypherVariable("Åbc12_A"), is("Åbc12_A")); - assertThat(formatter.unescapedCypherVariable("`\0`"), is("\0")); - assertThat(formatter.unescapedCypherVariable("`\n`"), is("\n")); - assertThat(formatter.unescapedCypherVariable("`comma, separated`"), is("comma, separated")); - assertThat(formatter.unescapedCypherVariable("`escaped content ``back ticks #`"), - is("escaped content `back ticks #")); - assertThat(formatter.unescapedCypherVariable("`escaped content two ``back ``ticks`"), - is("escaped content two `back `ticks")); + public void reEscapeNonAlphanumericStrings() throws Exception + { + assertThat( formatter.unescapedCypherVariable( "abc12_A" ), is( "abc12_A" ) ); + assertThat( formatter.unescapedCypherVariable( "Åbc12_A" ), is( "Åbc12_A" ) ); + assertThat( formatter.unescapedCypherVariable( "`\0`" ), is( "\0" ) ); + assertThat( formatter.unescapedCypherVariable( "`\n`" ), is( "\n" ) ); + assertThat( formatter.unescapedCypherVariable( "`comma, separated`" ), is( "comma, separated" ) ); + assertThat( formatter.unescapedCypherVariable( "`escaped content ``back ticks #`" ), + is( "escaped content `back ticks #" ) ); + assertThat( formatter.unescapedCypherVariable( "`escaped content two ``back ``ticks`" ), + is( "escaped content two `back `ticks" ) ); } } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/prettyprint/OutputFormatterTest.java b/cypher-shell/src/test/java/org/neo4j/shell/prettyprint/OutputFormatterTest.java index f73c162c..8236c60f 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/prettyprint/OutputFormatterTest.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/prettyprint/OutputFormatterTest.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.prettyprint; import org.junit.Test; @@ -27,7 +46,8 @@ public class OutputFormatterTest { @Test - public void shouldReportTotalDBHits() { + public void shouldReportTotalDBHits() + { Value labelScan = buildOperator( "NodeByLabelScan", 1002L, 1001L, null ); Value filter = buildOperator( "Filter", 1402, 280, labelScan ); Value planMap = buildOperator( "ProduceResults", 0, 280, filter ); @@ -36,7 +56,7 @@ public void shouldReportTotalDBHits() { ResultSummary summary = new InternalResultSummary( new Query( "PROFILE MATCH (n:LABEL) WHERE 20 < n.age < 35 return n" ), new InternalServerInfo( new BoltServerAddress( "localhost:7687" ), ServerVersion.vInDev ), - new InternalDatabaseInfo("neo4j"), + new InternalDatabaseInfo( "neo4j" ), QueryType.READ_ONLY, null, plan, @@ -46,18 +66,20 @@ public void shouldReportTotalDBHits() { 55 ); // When - Map info = OutputFormatter.info( summary ); + Map info = OutputFormatter.info( summary ); //Then assertThat( info.get( "DbHits" ).asLong(), equalTo( 2404L ) ); } - private Value buildOperator( String operator, long dbHits, long rows, Value child ) { + private Value buildOperator( String operator, long dbHits, long rows, Value child ) + { Map operatorMap = new HashMap<>(); operatorMap.put( "operatorType", Values.value( operator ) ); operatorMap.put( "dbHits", Values.value( dbHits ) ); operatorMap.put( "rows", Values.value( rows ) ); - if ( child != null ) { + if ( child != null ) + { operatorMap.put( "children", new ListValue( child ) ); } return new MapValue( operatorMap ); diff --git a/cypher-shell/src/test/java/org/neo4j/shell/prettyprint/PrettyPrinterTest.java b/cypher-shell/src/test/java/org/neo4j/shell/prettyprint/PrettyPrinterTest.java index e0b7d69b..4b2664c5 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/prettyprint/PrettyPrinterTest.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/prettyprint/PrettyPrinterTest.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.prettyprint; import org.junit.Test; @@ -35,55 +54,58 @@ import static org.neo4j.driver.internal.util.Iterables.map; import static org.neo4j.shell.prettyprint.OutputFormatter.NEWLINE; -@SuppressWarnings("ArraysAsListWithZeroOrOneArgument") -public class PrettyPrinterTest { +@SuppressWarnings( "ArraysAsListWithZeroOrOneArgument" ) +public class PrettyPrinterTest +{ - private final PrettyPrinter plainPrinter = new PrettyPrinter(new PrettyConfig(Format.PLAIN, false, 100)); - private final PrettyPrinter verbosePrinter = new PrettyPrinter(new PrettyConfig(Format.VERBOSE, true, 100)); + private final PrettyPrinter plainPrinter = new PrettyPrinter( new PrettyConfig( Format.PLAIN, false, 100 ) ); + private final PrettyPrinter verbosePrinter = new PrettyPrinter( new PrettyConfig( Format.VERBOSE, true, 100 ) ); @Test - public void returnStatisticsForEmptyRecords() { + public void returnStatisticsForEmptyRecords() + { // given - ResultSummary resultSummary = mock(ResultSummary.class); - SummaryCounters summaryCounters = mock(SummaryCounters.class); - BoltResult result = new ListBoltResult(Collections.emptyList(), resultSummary); + ResultSummary resultSummary = mock( ResultSummary.class ); + SummaryCounters summaryCounters = mock( SummaryCounters.class ); + BoltResult result = new ListBoltResult( Collections.emptyList(), resultSummary ); - when(resultSummary.counters()).thenReturn(summaryCounters); - when(summaryCounters.labelsAdded()).thenReturn(1); - when(summaryCounters.nodesCreated()).thenReturn(10); + when( resultSummary.counters() ).thenReturn( summaryCounters ); + when( summaryCounters.labelsAdded() ).thenReturn( 1 ); + when( summaryCounters.nodesCreated() ).thenReturn( 10 ); // when - String actual = verbosePrinter.format(result); + String actual = verbosePrinter.format( result ); // then - assertThat(actual, containsString("Added 10 nodes, Added 1 labels")); + assertThat( actual, containsString( "Added 10 nodes, Added 1 labels" ) ); } @Test - public void prettyPrintProfileInformation() { + public void prettyPrintProfileInformation() + { // given - ResultSummary resultSummary = mock(ResultSummary.class); - ProfiledPlan plan = mock(ProfiledPlan.class); - when(plan.dbHits()).thenReturn(1000L); - when(plan.records()).thenReturn(20L); - - when(resultSummary.hasPlan()).thenReturn(true); - when(resultSummary.hasProfile()).thenReturn(true); - when(resultSummary.plan()).thenReturn(plan); - when(resultSummary.profile()).thenReturn(plan); - when(resultSummary.resultAvailableAfter(anyObject())).thenReturn(5L); - when(resultSummary.resultConsumedAfter(anyObject())).thenReturn(7L); - when(resultSummary.queryType()).thenReturn(QueryType.READ_ONLY); - Map argumentMap = Values.parameters("Version", "3.1", - "Planner", "COST", - "Runtime", "INTERPRETED", - "GlobalMemory", 10).asMap(v -> v); - when(plan.arguments()).thenReturn(argumentMap); - - BoltResult result = new ListBoltResult(Collections.emptyList(), resultSummary); + ResultSummary resultSummary = mock( ResultSummary.class ); + ProfiledPlan plan = mock( ProfiledPlan.class ); + when( plan.dbHits() ).thenReturn( 1000L ); + when( plan.records() ).thenReturn( 20L ); + + when( resultSummary.hasPlan() ).thenReturn( true ); + when( resultSummary.hasProfile() ).thenReturn( true ); + when( resultSummary.plan() ).thenReturn( plan ); + when( resultSummary.profile() ).thenReturn( plan ); + when( resultSummary.resultAvailableAfter( anyObject() ) ).thenReturn( 5L ); + when( resultSummary.resultConsumedAfter( anyObject() ) ).thenReturn( 7L ); + when( resultSummary.queryType() ).thenReturn( QueryType.READ_ONLY ); + Map argumentMap = Values.parameters( "Version", "3.1", + "Planner", "COST", + "Runtime", "INTERPRETED", + "GlobalMemory", 10 ).asMap( v -> v ); + when( plan.arguments() ).thenReturn( argumentMap ); + + BoltResult result = new ListBoltResult( Collections.emptyList(), resultSummary ); // when - String actual = plainPrinter.format(result); + String actual = plainPrinter.format( result ); // then String expected = @@ -96,33 +118,34 @@ public void prettyPrintProfileInformation() { "Rows: 20\n" + "DbHits: 1000\n" + "Memory (Bytes): 10"; - Stream.of(expected.split("\n")).forEach(e -> assertThat(actual, containsString(e))); + Stream.of( expected.split( "\n" ) ).forEach( e -> assertThat( actual, containsString( e ) ) ); } @Test - public void prettyPrintProfileInformationIfGlobalMemoryIsMissing() { + public void prettyPrintProfileInformationIfGlobalMemoryIsMissing() + { // given - ResultSummary resultSummary = mock(ResultSummary.class); - ProfiledPlan plan = mock(ProfiledPlan.class); - when(plan.dbHits()).thenReturn(1000L); - when(plan.records()).thenReturn(20L); - - when(resultSummary.hasPlan()).thenReturn(true); - when(resultSummary.hasProfile()).thenReturn(true); - when(resultSummary.plan()).thenReturn(plan); - when(resultSummary.profile()).thenReturn(plan); - when(resultSummary.resultAvailableAfter(anyObject())).thenReturn(5L); - when(resultSummary.resultConsumedAfter(anyObject())).thenReturn(7L); - when(resultSummary.queryType()).thenReturn(QueryType.READ_ONLY); - Map argumentMap = Values.parameters("Version", "3.1", - "Planner", "COST", - "Runtime", "INTERPRETED").asMap(v -> v); - when(plan.arguments()).thenReturn(argumentMap); - - BoltResult result = new ListBoltResult(Collections.emptyList(), resultSummary); + ResultSummary resultSummary = mock( ResultSummary.class ); + ProfiledPlan plan = mock( ProfiledPlan.class ); + when( plan.dbHits() ).thenReturn( 1000L ); + when( plan.records() ).thenReturn( 20L ); + + when( resultSummary.hasPlan() ).thenReturn( true ); + when( resultSummary.hasProfile() ).thenReturn( true ); + when( resultSummary.plan() ).thenReturn( plan ); + when( resultSummary.profile() ).thenReturn( plan ); + when( resultSummary.resultAvailableAfter( anyObject() ) ).thenReturn( 5L ); + when( resultSummary.resultConsumedAfter( anyObject() ) ).thenReturn( 7L ); + when( resultSummary.queryType() ).thenReturn( QueryType.READ_ONLY ); + Map argumentMap = Values.parameters( "Version", "3.1", + "Planner", "COST", + "Runtime", "INTERPRETED" ).asMap( v -> v ); + when( plan.arguments() ).thenReturn( argumentMap ); + + BoltResult result = new ListBoltResult( Collections.emptyList(), resultSummary ); // when - String actual = plainPrinter.format(result); + String actual = plainPrinter.format( result ); // then String expected = @@ -135,30 +158,31 @@ public void prettyPrintProfileInformationIfGlobalMemoryIsMissing() { "Rows: 20\n" + "DbHits: 1000\n" + "Memory (Bytes): \"?\""; - Stream.of(expected.split("\n")).forEach(e -> assertThat(actual, containsString(e))); + Stream.of( expected.split( "\n" ) ).forEach( e -> assertThat( actual, containsString( e ) ) ); } @Test - public void prettyPrintExplainInformation() { + public void prettyPrintExplainInformation() + { // given - ResultSummary resultSummary = mock(ResultSummary.class); - ProfiledPlan plan = mock(ProfiledPlan.class); - when(plan.dbHits()).thenReturn(1000L); - when(plan.records()).thenReturn(20L); - - when(resultSummary.hasPlan()).thenReturn(true); - when(resultSummary.hasProfile()).thenReturn(false); - when(resultSummary.plan()).thenReturn(plan); - when(resultSummary.resultAvailableAfter(anyObject())).thenReturn(5L); - when(resultSummary.resultConsumedAfter(anyObject())).thenReturn(7L); - when(resultSummary.queryType()).thenReturn(QueryType.READ_ONLY); - Map argumentMap = Values.parameters("Version", "3.1", "Planner", "COST", "Runtime", "INTERPRETED").asMap(v -> v); - when(plan.arguments()).thenReturn(argumentMap); - - BoltResult result = new ListBoltResult(Collections.emptyList(), resultSummary); + ResultSummary resultSummary = mock( ResultSummary.class ); + ProfiledPlan plan = mock( ProfiledPlan.class ); + when( plan.dbHits() ).thenReturn( 1000L ); + when( plan.records() ).thenReturn( 20L ); + + when( resultSummary.hasPlan() ).thenReturn( true ); + when( resultSummary.hasProfile() ).thenReturn( false ); + when( resultSummary.plan() ).thenReturn( plan ); + when( resultSummary.resultAvailableAfter( anyObject() ) ).thenReturn( 5L ); + when( resultSummary.resultConsumedAfter( anyObject() ) ).thenReturn( 7L ); + when( resultSummary.queryType() ).thenReturn( QueryType.READ_ONLY ); + Map argumentMap = Values.parameters( "Version", "3.1", "Planner", "COST", "Runtime", "INTERPRETED" ).asMap( v -> v ); + when( plan.arguments() ).thenReturn( argumentMap ); + + BoltResult result = new ListBoltResult( Collections.emptyList(), resultSummary ); // when - String actual = plainPrinter.format(result); + String actual = plainPrinter.format( result ); // then String expected = @@ -168,327 +192,334 @@ public void prettyPrintExplainInformation() { "Planner: \"COST\"\n" + "Runtime: \"INTERPRETED\"\n" + "Time: 12"; - Stream.of(expected.split("\n")).forEach(e -> assertThat(actual, containsString(e))); + Stream.of( expected.split( "\n" ) ).forEach( e -> assertThat( actual, containsString( e ) ) ); } @Test - public void prettyPrintList() { + public void prettyPrintList() + { // given - Record record1 = mock(Record.class); - Record record2 = mock(Record.class); - Value value1 = Values.value("val1_1", "val1_2"); - Value value2 = Values.value(new String[]{"val2_1"}); + Record record1 = mock( Record.class ); + Record record2 = mock( Record.class ); + Value value1 = Values.value( "val1_1", "val1_2" ); + Value value2 = Values.value( new String[] {"val2_1"} ); - when(record1.keys()).thenReturn(asList("col1", "col2")); - when(record1.values()).thenReturn(asList(value1, value2)); - when(record2.values()).thenReturn(asList(value2)); + when( record1.keys() ).thenReturn( asList( "col1", "col2" ) ); + when( record1.values() ).thenReturn( asList( value1, value2 ) ); + when( record2.values() ).thenReturn( asList( value2 ) ); - BoltResult result = new ListBoltResult(asList(record1, record2), mock(ResultSummary.class)); + BoltResult result = new ListBoltResult( asList( record1, record2 ), mock( ResultSummary.class ) ); // when - String actual = plainPrinter.format(result); + String actual = plainPrinter.format( result ); // then - assertThat(actual, is(String.join(NEWLINE, - "col1, col2", - "[\"val1_1\", \"val1_2\"], [\"val2_1\"]", - "[\"val2_1\"]", - ""))); + assertThat( actual, is( String.join( NEWLINE, + "col1, col2", + "[\"val1_1\", \"val1_2\"], [\"val2_1\"]", + "[\"val2_1\"]", + "" ) ) ); } @Test - public void prettyPrintMaps() { - checkMapForPrettyPrint(map(), "map"+NEWLINE+"{}"+NEWLINE); - checkMapForPrettyPrint(map("abc", "def"), "map"+NEWLINE+"{abc: def}"+NEWLINE); + public void prettyPrintMaps() + { + checkMapForPrettyPrint( map(), "map" + NEWLINE + "{}" + NEWLINE ); + checkMapForPrettyPrint( map( "abc", "def" ), "map" + NEWLINE + "{abc: def}" + NEWLINE ); } - private void checkMapForPrettyPrint(Map map, String expectedResult) { + private void checkMapForPrettyPrint( Map map, String expectedResult ) + { // given - Record record = mock(Record.class); - Value value = mock(Value.class); + Record record = mock( Record.class ); + Value value = mock( Value.class ); - when(value.type()).thenReturn(InternalTypeSystem.TYPE_SYSTEM.MAP()); + when( value.type() ).thenReturn( InternalTypeSystem.TYPE_SYSTEM.MAP() ); - when(value.asMap((Function) anyObject())).thenReturn(map); + when( value.asMap( (Function) anyObject() ) ).thenReturn( map ); - when(record.keys()).thenReturn(asList("map")); - when(record.values()).thenReturn(asList(value)); + when( record.keys() ).thenReturn( asList( "map" ) ); + when( record.values() ).thenReturn( asList( value ) ); - BoltResult result = new ListBoltResult(asList(record), mock(ResultSummary.class)); + BoltResult result = new ListBoltResult( asList( record ), mock( ResultSummary.class ) ); // when - String actual = plainPrinter.format(result); + String actual = plainPrinter.format( result ); // then - assertThat(actual, is(expectedResult)); + assertThat( actual, is( expectedResult ) ); } @Test - public void prettyPrintNode() { + public void prettyPrintNode() + { // given - Record record = mock(Record.class); - Value value = mock(Value.class); + Record record = mock( Record.class ); + Value value = mock( Value.class ); - Node node = mock(Node.class); + Node node = mock( Node.class ); HashMap propertiesAsMap = new HashMap<>(); - propertiesAsMap.put("prop1", "prop1_value"); - propertiesAsMap.put("prop2", "prop2_value"); + propertiesAsMap.put( "prop1", "prop1_value" ); + propertiesAsMap.put( "prop2", "prop2_value" ); - when(value.type()).thenReturn(InternalTypeSystem.TYPE_SYSTEM.NODE()); + when( value.type() ).thenReturn( InternalTypeSystem.TYPE_SYSTEM.NODE() ); - when(value.asNode()).thenReturn(node); - when(node.labels()).thenReturn(asList("label1", "label2")); - when(node.asMap(anyObject())).thenReturn(unmodifiableMap(propertiesAsMap)); + when( value.asNode() ).thenReturn( node ); + when( node.labels() ).thenReturn( asList( "label1", "label2" ) ); + when( node.asMap( anyObject() ) ).thenReturn( unmodifiableMap( propertiesAsMap ) ); - when(record.keys()).thenReturn(asList("col1", "col2")); - when(record.values()).thenReturn(asList(value)); + when( record.keys() ).thenReturn( asList( "col1", "col2" ) ); + when( record.values() ).thenReturn( asList( value ) ); - BoltResult result = new ListBoltResult(asList(record), mock(ResultSummary.class)); + BoltResult result = new ListBoltResult( asList( record ), mock( ResultSummary.class ) ); // when - String actual = plainPrinter.format(result); + String actual = plainPrinter.format( result ); // then - assertThat(actual, is("col1, col2" + NEWLINE + - "(:label1:label2 {prop2: prop2_value, prop1: prop1_value})" + NEWLINE)); + assertThat( actual, is( "col1, col2" + NEWLINE + + "(:label1:label2 {prop2: prop2_value, prop1: prop1_value})" + NEWLINE ) ); } @Test - public void prettyPrintRelationships() { + public void prettyPrintRelationships() + { // given - Record record = mock(Record.class); - Value value = mock(Value.class); + Record record = mock( Record.class ); + Value value = mock( Value.class ); - Relationship relationship = mock(Relationship.class); + Relationship relationship = mock( Relationship.class ); HashMap propertiesAsMap = new HashMap<>(); - propertiesAsMap.put("prop1", "prop1_value"); - propertiesAsMap.put("prop2", "prop2_value"); + propertiesAsMap.put( "prop1", "prop1_value" ); + propertiesAsMap.put( "prop2", "prop2_value" ); - when(value.type()).thenReturn(InternalTypeSystem.TYPE_SYSTEM.RELATIONSHIP()); + when( value.type() ).thenReturn( InternalTypeSystem.TYPE_SYSTEM.RELATIONSHIP() ); - when(value.asRelationship()).thenReturn(relationship); - when(relationship.type()).thenReturn("RELATIONSHIP_TYPE"); - when(relationship.asMap(anyObject())).thenReturn(unmodifiableMap(propertiesAsMap)); + when( value.asRelationship() ).thenReturn( relationship ); + when( relationship.type() ).thenReturn( "RELATIONSHIP_TYPE" ); + when( relationship.asMap( anyObject() ) ).thenReturn( unmodifiableMap( propertiesAsMap ) ); - when(record.keys()).thenReturn(asList("rel")); - when(record.values()).thenReturn(asList(value)); + when( record.keys() ).thenReturn( asList( "rel" ) ); + when( record.values() ).thenReturn( asList( value ) ); - BoltResult result = new ListBoltResult(asList(record), mock(ResultSummary.class)); + BoltResult result = new ListBoltResult( asList( record ), mock( ResultSummary.class ) ); // when - String actual = plainPrinter.format(result); + String actual = plainPrinter.format( result ); // then - assertThat(actual, is("rel" + NEWLINE+ - "[:RELATIONSHIP_TYPE {prop2: prop2_value, prop1: prop1_value}]" + NEWLINE)); + assertThat( actual, is( "rel" + NEWLINE + + "[:RELATIONSHIP_TYPE {prop2: prop2_value, prop1: prop1_value}]" + NEWLINE ) ); } @Test - public void printRelationshipsAndNodesWithEscapingForSpecialCharacters() { + public void printRelationshipsAndNodesWithEscapingForSpecialCharacters() + { // given - Record record = mock(Record.class); - Value relVal = mock(Value.class); - Value nodeVal = mock(Value.class); + Record record = mock( Record.class ); + Value relVal = mock( Value.class ); + Value nodeVal = mock( Value.class ); - Relationship relationship = mock(Relationship.class); + Relationship relationship = mock( Relationship.class ); HashMap relProp = new HashMap<>(); - relProp.put("prop1", "\"prop1, value\""); - relProp.put("prop2", "prop2_value"); + relProp.put( "prop1", "\"prop1, value\"" ); + relProp.put( "prop2", "prop2_value" ); - Node node = mock(Node.class); + Node node = mock( Node.class ); HashMap nodeProp = new HashMap<>(); - nodeProp.put("prop1", "\"prop1:value\""); - nodeProp.put("1prop2", "\"\""); - nodeProp.put("ä", "not-escaped"); + nodeProp.put( "prop1", "\"prop1:value\"" ); + nodeProp.put( "1prop2", "\"\"" ); + nodeProp.put( "ä", "not-escaped" ); - when(relVal.type()).thenReturn(InternalTypeSystem.TYPE_SYSTEM.RELATIONSHIP()); - when(nodeVal.type()).thenReturn(InternalTypeSystem.TYPE_SYSTEM.NODE()); + when( relVal.type() ).thenReturn( InternalTypeSystem.TYPE_SYSTEM.RELATIONSHIP() ); + when( nodeVal.type() ).thenReturn( InternalTypeSystem.TYPE_SYSTEM.NODE() ); - when(relVal.asRelationship()).thenReturn(relationship); - when(relationship.type()).thenReturn("RELATIONSHIP,TYPE"); - when(relationship.asMap(anyObject())).thenReturn(unmodifiableMap(relProp)); + when( relVal.asRelationship() ).thenReturn( relationship ); + when( relationship.type() ).thenReturn( "RELATIONSHIP,TYPE" ); + when( relationship.asMap( anyObject() ) ).thenReturn( unmodifiableMap( relProp ) ); + when( nodeVal.asNode() ).thenReturn( node ); + when( node.labels() ).thenReturn( asList( "label `1", "label2" ) ); + when( node.asMap( anyObject() ) ).thenReturn( unmodifiableMap( nodeProp ) ); - when(nodeVal.asNode()).thenReturn(node); - when(node.labels()).thenReturn(asList("label `1", "label2")); - when(node.asMap(anyObject())).thenReturn(unmodifiableMap(nodeProp)); + when( record.keys() ).thenReturn( asList( "rel", "node" ) ); + when( record.values() ).thenReturn( asList( relVal, nodeVal ) ); - when(record.keys()).thenReturn(asList("rel", "node")); - when(record.values()).thenReturn(asList(relVal, nodeVal)); - - BoltResult result = new ListBoltResult(asList(record), mock(ResultSummary.class)); + BoltResult result = new ListBoltResult( asList( record ), mock( ResultSummary.class ) ); // when - String actual = plainPrinter.format(result); + String actual = plainPrinter.format( result ); // then - assertThat(actual, is( + assertThat( actual, is( "rel, node" + NEWLINE + "[:`RELATIONSHIP,TYPE` {prop2: prop2_value, prop1: \"prop1, value\"}], " + - "(:`label ``1`:label2 {prop1: \"prop1:value\", `1prop2`: \"\", ä: not-escaped})" + NEWLINE)); + "(:`label ``1`:label2 {prop1: \"prop1:value\", `1prop2`: \"\", ä: not-escaped})" + NEWLINE ) ); } @Test - public void prettyPrintPaths() { + public void prettyPrintPaths() + { // given - Record record = mock(Record.class); - Value value = mock(Value.class); + Record record = mock( Record.class ); + Value value = mock( Value.class ); - Node start = mock(Node.class); + Node start = mock( Node.class ); HashMap startProperties = new HashMap<>(); - startProperties.put("prop1", "prop1_value"); - when(start.labels()).thenReturn(asList("start")); - when(start.id()).thenReturn(1L); + startProperties.put( "prop1", "prop1_value" ); + when( start.labels() ).thenReturn( asList( "start" ) ); + when( start.id() ).thenReturn( 1L ); - Node middle = mock(Node.class); - when(middle.labels()).thenReturn(asList("middle")); - when(middle.id()).thenReturn(2L); + Node middle = mock( Node.class ); + when( middle.labels() ).thenReturn( asList( "middle" ) ); + when( middle.id() ).thenReturn( 2L ); - Node end = mock(Node.class); + Node end = mock( Node.class ); HashMap endProperties = new HashMap<>(); - endProperties.put("prop2", "prop2_value"); - when(end.labels()).thenReturn(asList("end")); - when(end.id()).thenReturn(3L); - - Path path = mock(Path.class); - when(path.start()).thenReturn(start); + endProperties.put( "prop2", "prop2_value" ); + when( end.labels() ).thenReturn( asList( "end" ) ); + when( end.id() ).thenReturn( 3L ); - Relationship relationship = mock(Relationship.class); - when(relationship.type()).thenReturn("RELATIONSHIP_TYPE"); - when(relationship.startNodeId()).thenReturn(1L).thenReturn(3L); + Path path = mock( Path.class ); + when( path.start() ).thenReturn( start ); + Relationship relationship = mock( Relationship.class ); + when( relationship.type() ).thenReturn( "RELATIONSHIP_TYPE" ); + when( relationship.startNodeId() ).thenReturn( 1L ).thenReturn( 3L ); - Path.Segment segment1 = mock(Path.Segment.class); - when(segment1.start()).thenReturn(start); - when(segment1.end()).thenReturn(middle); - when(segment1.relationship()).thenReturn(relationship); + Path.Segment segment1 = mock( Path.Segment.class ); + when( segment1.start() ).thenReturn( start ); + when( segment1.end() ).thenReturn( middle ); + when( segment1.relationship() ).thenReturn( relationship ); - Path.Segment segment2 = mock(Path.Segment.class); - when(segment2.start()).thenReturn(middle); - when(segment2.end()).thenReturn(end); - when(segment2.relationship()).thenReturn(relationship); + Path.Segment segment2 = mock( Path.Segment.class ); + when( segment2.start() ).thenReturn( middle ); + when( segment2.end() ).thenReturn( end ); + when( segment2.relationship() ).thenReturn( relationship ); - when(value.type()).thenReturn(InternalTypeSystem.TYPE_SYSTEM.PATH()); - when(value.asPath()).thenReturn(path); - when(path.iterator()).thenReturn(asList(segment1, segment2).iterator()); - when(start.asMap(anyObject())).thenReturn(unmodifiableMap(startProperties)); - when(end.asMap(anyObject())).thenReturn(unmodifiableMap(endProperties)); + when( value.type() ).thenReturn( InternalTypeSystem.TYPE_SYSTEM.PATH() ); + when( value.asPath() ).thenReturn( path ); + when( path.iterator() ).thenReturn( asList( segment1, segment2 ).iterator() ); + when( start.asMap( anyObject() ) ).thenReturn( unmodifiableMap( startProperties ) ); + when( end.asMap( anyObject() ) ).thenReturn( unmodifiableMap( endProperties ) ); - when(record.keys()).thenReturn(asList("path")); - when(record.values()).thenReturn(asList(value)); + when( record.keys() ).thenReturn( asList( "path" ) ); + when( record.values() ).thenReturn( asList( value ) ); - BoltResult result = new ListBoltResult(asList(record), mock(ResultSummary.class)); + BoltResult result = new ListBoltResult( asList( record ), mock( ResultSummary.class ) ); // when - String actual = plainPrinter.format(result); + String actual = plainPrinter.format( result ); // then - assertThat(actual, is("path" + NEWLINE + - "(:start {prop1: prop1_value})-[:RELATIONSHIP_TYPE]->" + - "(:middle)<-[:RELATIONSHIP_TYPE]-(:end {prop2: prop2_value})" + NEWLINE)); + assertThat( actual, is( "path" + NEWLINE + + "(:start {prop1: prop1_value})-[:RELATIONSHIP_TYPE]->" + + "(:middle)<-[:RELATIONSHIP_TYPE]-(:end {prop2: prop2_value})" + NEWLINE ) ); } @Test - public void prettyPrintSingleNodePath() { + public void prettyPrintSingleNodePath() + { // given - Record record = mock(Record.class); - Value value = mock(Value.class); + Record record = mock( Record.class ); + Value value = mock( Value.class ); - Node start = mock(Node.class); - when(start.labels()).thenReturn(asList("start")); - when(start.id()).thenReturn(1L); + Node start = mock( Node.class ); + when( start.labels() ).thenReturn( asList( "start" ) ); + when( start.id() ).thenReturn( 1L ); - Node end = mock(Node.class); - when(end.labels()).thenReturn(asList("end")); - when(end.id()).thenReturn(2L); + Node end = mock( Node.class ); + when( end.labels() ).thenReturn( asList( "end" ) ); + when( end.id() ).thenReturn( 2L ); - Path path = mock(Path.class); - when(path.start()).thenReturn(start); + Path path = mock( Path.class ); + when( path.start() ).thenReturn( start ); - Relationship relationship = mock(Relationship.class); - when(relationship.type()).thenReturn("RELATIONSHIP_TYPE"); - when(relationship.startNodeId()).thenReturn(1L); + Relationship relationship = mock( Relationship.class ); + when( relationship.type() ).thenReturn( "RELATIONSHIP_TYPE" ); + when( relationship.startNodeId() ).thenReturn( 1L ); - Path.Segment segment1 = mock(Path.Segment.class); - when(segment1.start()).thenReturn(start); - when(segment1.end()).thenReturn(end); - when(segment1.relationship()).thenReturn(relationship); + Path.Segment segment1 = mock( Path.Segment.class ); + when( segment1.start() ).thenReturn( start ); + when( segment1.end() ).thenReturn( end ); + when( segment1.relationship() ).thenReturn( relationship ); - when(value.type()).thenReturn(InternalTypeSystem.TYPE_SYSTEM.PATH()); - when(value.asPath()).thenReturn(path); - when(path.iterator()).thenReturn(asList(segment1).iterator()); + when( value.type() ).thenReturn( InternalTypeSystem.TYPE_SYSTEM.PATH() ); + when( value.asPath() ).thenReturn( path ); + when( path.iterator() ).thenReturn( asList( segment1 ).iterator() ); - when(record.keys()).thenReturn(asList("path")); - when(record.values()).thenReturn(asList(value)); + when( record.keys() ).thenReturn( asList( "path" ) ); + when( record.values() ).thenReturn( asList( value ) ); - BoltResult result = new ListBoltResult(asList(record), mock(ResultSummary.class)); + BoltResult result = new ListBoltResult( asList( record ), mock( ResultSummary.class ) ); // when - String actual = plainPrinter.format(result); + String actual = plainPrinter.format( result ); // then - assertThat(actual, is("path" + NEWLINE + "(:start)-[:RELATIONSHIP_TYPE]->(:end)" + NEWLINE)); + assertThat( actual, is( "path" + NEWLINE + "(:start)-[:RELATIONSHIP_TYPE]->(:end)" + NEWLINE ) ); } @Test - public void prettyPrintThreeSegmentPath() { + public void prettyPrintThreeSegmentPath() + { // given - Record record = mock(Record.class); - Value value = mock(Value.class); + Record record = mock( Record.class ); + Value value = mock( Value.class ); - Node start = mock(Node.class); - when(start.labels()).thenReturn(asList("start")); - when(start.id()).thenReturn(1L); + Node start = mock( Node.class ); + when( start.labels() ).thenReturn( asList( "start" ) ); + when( start.id() ).thenReturn( 1L ); - Node second = mock(Node.class); - when(second.labels()).thenReturn(asList("second")); - when(second.id()).thenReturn(2L); + Node second = mock( Node.class ); + when( second.labels() ).thenReturn( asList( "second" ) ); + when( second.id() ).thenReturn( 2L ); - Node third = mock(Node.class); - when(third.labels()).thenReturn(asList("third")); - when(third.id()).thenReturn(3L); + Node third = mock( Node.class ); + when( third.labels() ).thenReturn( asList( "third" ) ); + when( third.id() ).thenReturn( 3L ); - Node end = mock(Node.class); - when(end.labels()).thenReturn(asList("end")); - when(end.id()).thenReturn(4L); + Node end = mock( Node.class ); + when( end.labels() ).thenReturn( asList( "end" ) ); + when( end.id() ).thenReturn( 4L ); - Path path = mock(Path.class); - when(path.start()).thenReturn(start); + Path path = mock( Path.class ); + when( path.start() ).thenReturn( start ); - Relationship relationship = mock(Relationship.class); - when(relationship.type()).thenReturn("RELATIONSHIP_TYPE"); - when(relationship.startNodeId()).thenReturn(1L).thenReturn(3L).thenReturn(3L); + Relationship relationship = mock( Relationship.class ); + when( relationship.type() ).thenReturn( "RELATIONSHIP_TYPE" ); + when( relationship.startNodeId() ).thenReturn( 1L ).thenReturn( 3L ).thenReturn( 3L ); - Path.Segment segment1 = mock(Path.Segment.class); - when(segment1.start()).thenReturn(start); - when(segment1.end()).thenReturn(second); - when(segment1.relationship()).thenReturn(relationship); + Path.Segment segment1 = mock( Path.Segment.class ); + when( segment1.start() ).thenReturn( start ); + when( segment1.end() ).thenReturn( second ); + when( segment1.relationship() ).thenReturn( relationship ); - Path.Segment segment2 = mock(Path.Segment.class); - when(segment2.start()).thenReturn(second); - when(segment2.end()).thenReturn(third); - when(segment2.relationship()).thenReturn(relationship); + Path.Segment segment2 = mock( Path.Segment.class ); + when( segment2.start() ).thenReturn( second ); + when( segment2.end() ).thenReturn( third ); + when( segment2.relationship() ).thenReturn( relationship ); - Path.Segment segment3 = mock(Path.Segment.class); - when(segment3.start()).thenReturn(third); - when(segment3.end()).thenReturn(end); - when(segment3.relationship()).thenReturn(relationship); + Path.Segment segment3 = mock( Path.Segment.class ); + when( segment3.start() ).thenReturn( third ); + when( segment3.end() ).thenReturn( end ); + when( segment3.relationship() ).thenReturn( relationship ); - when(value.type()).thenReturn(InternalTypeSystem.TYPE_SYSTEM.PATH()); - when(value.asPath()).thenReturn(path); - when(path.iterator()).thenReturn(asList(segment1, segment2, segment3).iterator()); + when( value.type() ).thenReturn( InternalTypeSystem.TYPE_SYSTEM.PATH() ); + when( value.asPath() ).thenReturn( path ); + when( path.iterator() ).thenReturn( asList( segment1, segment2, segment3 ).iterator() ); - when(record.keys()).thenReturn(asList("path")); - when(record.values()).thenReturn(asList(value)); + when( record.keys() ).thenReturn( asList( "path" ) ); + when( record.values() ).thenReturn( asList( value ) ); - BoltResult result = new ListBoltResult(singletonList(record), mock(ResultSummary.class)); + BoltResult result = new ListBoltResult( singletonList( record ), mock( ResultSummary.class ) ); // when - String actual = plainPrinter.format(result); + String actual = plainPrinter.format( result ); // then - assertThat(actual, is("path" + NEWLINE + - "(:start)-[:RELATIONSHIP_TYPE]->" + - "(:second)<-[:RELATIONSHIP_TYPE]-(:third)-[:RELATIONSHIP_TYPE]->(:end)" + NEWLINE)); + assertThat( actual, is( "path" + NEWLINE + + "(:start)-[:RELATIONSHIP_TYPE]->" + + "(:second)<-[:RELATIONSHIP_TYPE]-(:third)-[:RELATIONSHIP_TYPE]->(:end)" + NEWLINE ) ); } } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/prettyprint/StatisticsCollectorTest.java b/cypher-shell/src/test/java/org/neo4j/shell/prettyprint/StatisticsCollectorTest.java index 90a990e3..35882944 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/prettyprint/StatisticsCollectorTest.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/prettyprint/StatisticsCollectorTest.java @@ -1,6 +1,26 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.prettyprint; import org.junit.Test; + import org.neo4j.driver.summary.ResultSummary; import org.neo4j.driver.summary.SummaryCounters; import org.neo4j.shell.cli.Format; @@ -10,35 +30,37 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -public class StatisticsCollectorTest { +public class StatisticsCollectorTest +{ @Test - public void returnEmptyStringForPlainFormatting() throws Exception { + public void returnEmptyStringForPlainFormatting() throws Exception + { // given - ResultSummary result = mock(ResultSummary.class); + ResultSummary result = mock( ResultSummary.class ); // when - String actual = new StatisticsCollector(Format.PLAIN).collect(result); + String actual = new StatisticsCollector( Format.PLAIN ).collect( result ); // then - assertThat(actual, is("")); + assertThat( actual, is( "" ) ); } @Test - public void returnStatisticsForDefaultFormatting() throws Exception { + public void returnStatisticsForDefaultFormatting() throws Exception + { // given - ResultSummary resultSummary = mock(ResultSummary.class); - SummaryCounters summaryCounters = mock(SummaryCounters.class); + ResultSummary resultSummary = mock( ResultSummary.class ); + SummaryCounters summaryCounters = mock( SummaryCounters.class ); - when(resultSummary.counters()).thenReturn(summaryCounters); - when(summaryCounters.labelsAdded()).thenReturn(1); - when(summaryCounters.nodesCreated()).thenReturn(10); + when( resultSummary.counters() ).thenReturn( summaryCounters ); + when( summaryCounters.labelsAdded() ).thenReturn( 1 ); + when( summaryCounters.nodesCreated() ).thenReturn( 10 ); // when - String actual = new StatisticsCollector(Format.VERBOSE).collect(resultSummary); + String actual = new StatisticsCollector( Format.VERBOSE ).collect( resultSummary ); // then - assertThat(actual, is("Added 10 nodes, Added 1 labels")); + assertThat( actual, is( "Added 10 nodes, Added 1 labels" ) ); } - } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/prettyprint/TableOutputFormatterTest.java b/cypher-shell/src/test/java/org/neo4j/shell/prettyprint/TableOutputFormatterTest.java index 7533ca53..a2121b91 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/prettyprint/TableOutputFormatterTest.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/prettyprint/TableOutputFormatterTest.java @@ -1,7 +1,28 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.prettyprint; +import org.apache.commons.io.IOUtils; import org.junit.Test; +import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -37,6 +58,7 @@ import org.neo4j.shell.state.BoltResult; import org.neo4j.shell.state.ListBoltResult; +import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.Arrays.asList; import static java.util.Collections.singletonMap; import static org.hamcrest.CoreMatchers.is; @@ -48,311 +70,312 @@ import static org.mockito.Mockito.when; import static org.neo4j.shell.prettyprint.OutputFormatter.NEWLINE; -@SuppressWarnings("ArraysAsListWithZeroOrOneArgument") -public class TableOutputFormatterTest { +@SuppressWarnings( "ArraysAsListWithZeroOrOneArgument" ) +public class TableOutputFormatterTest +{ - private final PrettyPrinter verbosePrinter = new PrettyPrinter(new PrettyConfig(Format.VERBOSE, true, 100)); + private final PrettyPrinter verbosePrinter = new PrettyPrinter( new PrettyConfig( Format.VERBOSE, true, 100 ) ); @Test - public void prettyPrintPlanInformation() { + public void prettyPrintPlanInformation() throws IOException + { // given - ResultSummary resultSummary = mock(ResultSummary.class); - - - Map argumentMap = Values.parameters("Version", "3.1", - "Planner", "COST", - "Runtime", "INTERPRETED", - "GlobalMemory", 10, - "DbHits", 2, - "Rows", 3, - "EstimatedRows", 10, - "Time", 15, - "Order", "a", - "PageCacheHits", 22, - "PageCacheMisses", 2, - "Memory", 5).asMap(v -> v); - - ProfiledPlan plan = mock(ProfiledPlan.class); - when(plan.dbHits()).thenReturn(1000L); - when(plan.records()).thenReturn(20L); - when(plan.arguments()).thenReturn(argumentMap); - when(plan.operatorType()).thenReturn("MyOp"); - when(plan.identifiers()).thenReturn(Arrays.asList( "a", "b" )); - - when(resultSummary.hasPlan()).thenReturn(true); - when(resultSummary.hasProfile()).thenReturn(true); - when(resultSummary.plan()).thenReturn(plan); - when(resultSummary.profile()).thenReturn(plan); - when(resultSummary.resultAvailableAfter(anyObject())).thenReturn(5L); - when(resultSummary.resultConsumedAfter(anyObject())).thenReturn(7L); - when(resultSummary.queryType()).thenReturn(QueryType.READ_ONLY); - when(plan.arguments()).thenReturn(argumentMap); - - BoltResult result = new ListBoltResult(Collections.emptyList(), resultSummary); + ResultSummary resultSummary = mock( ResultSummary.class ); + + Map argumentMap = Values.parameters( "Version", "3.1", + "Planner", "COST", + "Runtime", "INTERPRETED", + "GlobalMemory", 10, + "DbHits", 2, + "Rows", 3, + "EstimatedRows", 10, + "Time", 15, + "Order", "a", + "PageCacheHits", 22, + "PageCacheMisses", 2, + "Memory", 5 ).asMap( v -> v ); + + ProfiledPlan plan = mock( ProfiledPlan.class ); + when( plan.dbHits() ).thenReturn( 1000L ); + when( plan.records() ).thenReturn( 20L ); + when( plan.arguments() ).thenReturn( argumentMap ); + when( plan.operatorType() ).thenReturn( "MyOp" ); + when( plan.identifiers() ).thenReturn( Arrays.asList( "a", "b" ) ); + + when( resultSummary.hasPlan() ).thenReturn( true ); + when( resultSummary.hasProfile() ).thenReturn( true ); + when( resultSummary.plan() ).thenReturn( plan ); + when( resultSummary.profile() ).thenReturn( plan ); + when( resultSummary.resultAvailableAfter( anyObject() ) ).thenReturn( 5L ); + when( resultSummary.resultConsumedAfter( anyObject() ) ).thenReturn( 7L ); + when( resultSummary.queryType() ).thenReturn( QueryType.READ_ONLY ); + when( plan.arguments() ).thenReturn( argumentMap ); + + BoltResult result = new ListBoltResult( Collections.emptyList(), resultSummary ); // when - String actual = verbosePrinter.format(result); + String actual = verbosePrinter.format( result ); // then - assertThat( actual, startsWith( String.join( NEWLINE, - "+-----------------------------------------------------------------------------------------------------+", - "| Plan | Statement | Version | Planner | Runtime | Time | DbHits | Rows | Memory (Bytes) |", - "+-----------------------------------------------------------------------------------------------------+", - "| \"PROFILE\" | \"READ_ONLY\" | \"3.1\" | \"COST\" | \"INTERPRETED\" | 12 | 1000 | 20 | 10 |", - "+-----------------------------------------------------------------------------------------------------+", - NEWLINE, - "+----------+----------------+------+---------+-----------+-----------+----------------+-------------+------------+----------------------------+", - "| Operator | Estimated Rows | Rows | DB Hits | Cache H/M | Time (ms) | Memory (Bytes) | Identifiers | Ordered by | Other |", - "+----------+----------------+------+---------+-----------+-----------+----------------+-------------+------------+----------------------------+", - "| +MyOp | 10 | 3 | 2 | 22/2 | 0.000 | 5 | a, b | a | 15; INTERPRETED; 3.1; COST |", - "+----------+----------------+------+---------+-----------+-----------+----------------+-------------+------------+----------------------------+", - "", - "0 rows available after 5 ms, consumed after another 7 ms" ) )); + String expected = IOUtils.toString( getClass().getResource( "/org/neo4j/shell/prettyprint/expected-pretty-print-plan-information.txt" ), UTF_8 ) + .replace( "\n", NEWLINE ); + + assertThat( actual, startsWith( expected ) ); } @Test - public void prettyPrintPoint() { + public void prettyPrintPoint() + { // given - List keys = asList("p1", "p2"); + List keys = asList( "p1", "p2" ); - Value point2d = new PointValue(new InternalPoint2D(4326, 42.78, 56.7)); - Value point3d = new PointValue(new InternalPoint3D(4326, 1.7, 26.79, 34.23)); - Record record = new InternalRecord(keys, new Value[]{point2d, point3d}); + Value point2d = new PointValue( new InternalPoint2D( 4326, 42.78, 56.7 ) ); + Value point3d = new PointValue( new InternalPoint3D( 4326, 1.7, 26.79, 34.23 ) ); + Record record = new InternalRecord( keys, new Value[] {point2d, point3d} ); // when - String actual = verbosePrinter.format(new ListBoltResult(asList(record), mock(ResultSummary.class))); + String actual = verbosePrinter.format( new ListBoltResult( asList( record ), mock( ResultSummary.class ) ) ); // then - assertThat(actual, containsString("| point({srid:4326, x:42.78, y:56.7}) |")); - assertThat(actual, containsString("| point({srid:4326, x:1.7, y:26.79, z:34.23}) |")); + assertThat( actual, containsString( "| point({srid:4326, x:42.78, y:56.7}) |" ) ); + assertThat( actual, containsString( "| point({srid:4326, x:1.7, y:26.79, z:34.23}) |" ) ); } @Test - public void prettyPrintDuration() { + public void prettyPrintDuration() + { // given - List keys = asList("d"); + List keys = asList( "d" ); - Value duration = new DurationValue(new InternalIsoDuration(1, 2, 3, 4)); - Record record = new InternalRecord(keys, new Value[]{duration}); + Value duration = new DurationValue( new InternalIsoDuration( 1, 2, 3, 4 ) ); + Record record = new InternalRecord( keys, new Value[] {duration} ); // when - String actual = verbosePrinter.format(new ListBoltResult(asList(record), mock(ResultSummary.class))); + String actual = verbosePrinter.format( new ListBoltResult( asList( record ), mock( ResultSummary.class ) ) ); // then - assertThat(actual, containsString("| P1M2DT3.000000004S |")); + assertThat( actual, containsString( "| P1M2DT3.000000004S |" ) ); } @Test - public void prettyPrintDurationWithNoTrailingZeroes() { + public void prettyPrintDurationWithNoTrailingZeroes() + { // given - List keys = asList("d"); + List keys = asList( "d" ); - Value duration = new DurationValue(new InternalIsoDuration(1, 2, 3, 0)); - Record record = new InternalRecord(keys, new Value[]{duration}); + Value duration = new DurationValue( new InternalIsoDuration( 1, 2, 3, 0 ) ); + Record record = new InternalRecord( keys, new Value[] {duration} ); // when - String actual = verbosePrinter.format(new ListBoltResult(asList(record), mock(ResultSummary.class))); + String actual = verbosePrinter.format( new ListBoltResult( asList( record ), mock( ResultSummary.class ) ) ); // then - assertThat(actual, containsString("| P1M2DT3S |")); + assertThat( actual, containsString( "| P1M2DT3S |" ) ); } @Test - public void prettyPrintNode() { + public void prettyPrintNode() + { // given - List labels = asList("label1", "label2"); + List labels = asList( "label1", "label2" ); Map propertiesAsMap = new HashMap<>(); - propertiesAsMap.put("prop1", Values.value("prop1_value")); - propertiesAsMap.put("prop2", Values.value("prop2_value")); - List keys = asList("col1", "col2"); + propertiesAsMap.put( "prop1", Values.value( "prop1_value" ) ); + propertiesAsMap.put( "prop2", Values.value( "prop2_value" ) ); + List keys = asList( "col1", "col2" ); - Value value = new NodeValue(new InternalNode(1, labels, propertiesAsMap)); - Record record = new InternalRecord(keys, new Value[]{value}); + Value value = new NodeValue( new InternalNode( 1, labels, propertiesAsMap ) ); + Record record = new InternalRecord( keys, new Value[] {value} ); // when - String actual = verbosePrinter.format(new ListBoltResult(asList(record), mock(ResultSummary.class))); + String actual = verbosePrinter.format( new ListBoltResult( asList( record ), mock( ResultSummary.class ) ) ); // then - assertThat(actual, containsString("| (:label1:label2 {prop2: \"prop2_value\", prop1: \"prop1_value\"}) |")); + assertThat( actual, containsString( "| (:label1:label2 {prop2: \"prop2_value\", prop1: \"prop1_value\"}) |" ) ); } @Test - public void prettyPrintRelationships() { + public void prettyPrintRelationships() + { // given - List keys = asList("rel"); + List keys = asList( "rel" ); Map propertiesAsMap = new HashMap<>(); - propertiesAsMap.put("prop1", Values.value("prop1_value")); - propertiesAsMap.put("prop2", Values.value("prop2_value")); + propertiesAsMap.put( "prop1", Values.value( "prop1_value" ) ); + propertiesAsMap.put( "prop2", Values.value( "prop2_value" ) ); RelationshipValue relationship = - new RelationshipValue(new InternalRelationship(1, 1, 2, "RELATIONSHIP_TYPE", propertiesAsMap)); + new RelationshipValue( new InternalRelationship( 1, 1, 2, "RELATIONSHIP_TYPE", propertiesAsMap ) ); - Record record = new InternalRecord(keys, new Value[]{relationship}); + Record record = new InternalRecord( keys, new Value[] {relationship} ); // when - String actual = verbosePrinter.format(new ListBoltResult(asList(record), mock(ResultSummary.class))); + String actual = verbosePrinter.format( new ListBoltResult( asList( record ), mock( ResultSummary.class ) ) ); // then - assertThat(actual, containsString("| [:RELATIONSHIP_TYPE {prop2: \"prop2_value\", prop1: \"prop1_value\"}] |")); + assertThat( actual, containsString( "| [:RELATIONSHIP_TYPE {prop2: \"prop2_value\", prop1: \"prop1_value\"}] |" ) ); } @Test - public void prettyPrintPath() { + public void prettyPrintPath() + { // given - List keys = asList("path"); - - Node n1 = mock(Node.class); - when(n1.id()).thenReturn(1L); - List labels = asList("L1"); - when(n1.labels()).thenReturn(labels); - when(n1.asMap(anyObject())).thenReturn(Collections.emptyMap()); - - Relationship r1 = mock(Relationship.class); - when(r1.startNodeId()).thenReturn(2L); - when(r1.type()).thenReturn("R1"); - when(r1.asMap(anyObject())).thenReturn(Collections.emptyMap()); - - Node n2 = mock(Node.class); - when(n2.id()).thenReturn(2L); - when(n2.labels()).thenReturn(asList("L2")); - when(n2.asMap(anyObject())).thenReturn(Collections.emptyMap()); - - Relationship r2 = mock(Relationship.class); - when(r2.startNodeId()).thenReturn(2L); - when(r2.type()).thenReturn("R2"); - when(r2.asMap(anyObject())).thenReturn(Collections.emptyMap()); - - Node n3 = mock(Node.class); - when(n3.id()).thenReturn(3L); - when(n3.labels()).thenReturn(asList("L3")); - when(n3.asMap(anyObject())).thenReturn(Collections.emptyMap()); - - Path.Segment s1 = mock(Path.Segment.class); - when(s1.relationship()).thenReturn(r1); - when(s1.start()).thenReturn(n1); - when(s1.end()).thenReturn(n2); - - Path.Segment s2 = mock(Path.Segment.class); - when(s2.relationship()).thenReturn(r2); - when(s2.start()).thenReturn(n2); - when(s2.end()).thenReturn(n3); - - List segments = asList(s1, s2); - List nodes = asList(n1, n2); - List relationships = asList(r1); - InternalPath internalPath = new InternalPath(segments, nodes, relationships); - Value value = new PathValue(internalPath); - - Record record = new InternalRecord(keys, new Value[]{value}); + List keys = asList( "path" ); + + Node n1 = mock( Node.class ); + when( n1.id() ).thenReturn( 1L ); + List labels = asList( "L1" ); + when( n1.labels() ).thenReturn( labels ); + when( n1.asMap( anyObject() ) ).thenReturn( Collections.emptyMap() ); + + Relationship r1 = mock( Relationship.class ); + when( r1.startNodeId() ).thenReturn( 2L ); + when( r1.type() ).thenReturn( "R1" ); + when( r1.asMap( anyObject() ) ).thenReturn( Collections.emptyMap() ); + + Node n2 = mock( Node.class ); + when( n2.id() ).thenReturn( 2L ); + when( n2.labels() ).thenReturn( asList( "L2" ) ); + when( n2.asMap( anyObject() ) ).thenReturn( Collections.emptyMap() ); + + Relationship r2 = mock( Relationship.class ); + when( r2.startNodeId() ).thenReturn( 2L ); + when( r2.type() ).thenReturn( "R2" ); + when( r2.asMap( anyObject() ) ).thenReturn( Collections.emptyMap() ); + + Node n3 = mock( Node.class ); + when( n3.id() ).thenReturn( 3L ); + when( n3.labels() ).thenReturn( asList( "L3" ) ); + when( n3.asMap( anyObject() ) ).thenReturn( Collections.emptyMap() ); + + Path.Segment s1 = mock( Path.Segment.class ); + when( s1.relationship() ).thenReturn( r1 ); + when( s1.start() ).thenReturn( n1 ); + when( s1.end() ).thenReturn( n2 ); + + Path.Segment s2 = mock( Path.Segment.class ); + when( s2.relationship() ).thenReturn( r2 ); + when( s2.start() ).thenReturn( n2 ); + when( s2.end() ).thenReturn( n3 ); + + List segments = asList( s1, s2 ); + List nodes = asList( n1, n2 ); + List relationships = asList( r1 ); + InternalPath internalPath = new InternalPath( segments, nodes, relationships ); + Value value = new PathValue( internalPath ); + + Record record = new InternalRecord( keys, new Value[] {value} ); // when - String actual = verbosePrinter.format(new ListBoltResult(asList(record), mock(ResultSummary.class))); + String actual = verbosePrinter.format( new ListBoltResult( asList( record ), mock( ResultSummary.class ) ) ); // then - assertThat(actual, containsString("| (:L1)<-[:R1]-(:L2)-[:R2]->(:L3) |")); + assertThat( actual, containsString( "| (:L1)<-[:R1]-(:L2)-[:R2]->(:L3) |" ) ); } @Test - public void printRelationshipsAndNodesWithEscapingForSpecialCharacters() { + public void printRelationshipsAndNodesWithEscapingForSpecialCharacters() + { // given - Record record = mock(Record.class); + Record record = mock( Record.class ); Map propertiesAsMap = new HashMap<>(); - propertiesAsMap.put("prop1", Values.value("prop1, value")); - propertiesAsMap.put("prop2", Values.value(1)); - Value relVal = new RelationshipValue(new InternalRelationship(1, 1, 2, "RELATIONSHIP,TYPE", propertiesAsMap)); + propertiesAsMap.put( "prop1", Values.value( "prop1, value" ) ); + propertiesAsMap.put( "prop2", Values.value( 1 ) ); + Value relVal = new RelationshipValue( new InternalRelationship( 1, 1, 2, "RELATIONSHIP,TYPE", propertiesAsMap ) ); - List labels = asList("label `1", "label2"); + List labels = asList( "label `1", "label2" ); Map nodeProperties = new HashMap<>(); - nodeProperties.put("prop1", Values.value("prop1:value")); + nodeProperties.put( "prop1", Values.value( "prop1:value" ) ); String doubleQuotes = "\"\""; - nodeProperties.put("1prop1", Values.value(doubleQuotes)); - nodeProperties.put("ä", Values.value("not-escaped")); + nodeProperties.put( "1prop1", Values.value( doubleQuotes ) ); + nodeProperties.put( "ä", Values.value( "not-escaped" ) ); - Value nodeVal = new NodeValue(new InternalNode(1, labels, nodeProperties)); + Value nodeVal = new NodeValue( new InternalNode( 1, labels, nodeProperties ) ); Map recordMap = new LinkedHashMap<>(); - recordMap.put("rel", relVal); - recordMap.put("node", nodeVal); - List keys = asList("rel", "node"); - when(record.keys()).thenReturn(keys); - when(record.size()).thenReturn(2); - when(record.get(0)).thenReturn(relVal); - when(record.get(1)).thenReturn(nodeVal); + recordMap.put( "rel", relVal ); + recordMap.put( "node", nodeVal ); + List keys = asList( "rel", "node" ); + when( record.keys() ).thenReturn( keys ); + when( record.size() ).thenReturn( 2 ); + when( record.get( 0 ) ).thenReturn( relVal ); + when( record.get( 1 ) ).thenReturn( nodeVal ); - when(record.asMap(anyObject())).thenReturn(recordMap); + when( record.asMap( anyObject() ) ).thenReturn( recordMap ); - when(record.values()).thenReturn(asList(relVal, nodeVal)); + when( record.values() ).thenReturn( asList( relVal, nodeVal ) ); // when - String actual = verbosePrinter.format(new ListBoltResult(asList(record), mock(ResultSummary.class))); + String actual = verbosePrinter.format( new ListBoltResult( asList( record ), mock( ResultSummary.class ) ) ); // then - assertThat(actual, containsString("| [:`RELATIONSHIP,TYPE` {prop2: 1, prop1: \"prop1, value\"}] |")); - assertThat(actual, containsString("| (:`label ``1`:label2 {`1prop1`: \"\\\"\\\"\", " + - "prop1: \"prop1:value\", ä: \"not-escaped\"}) |")); + assertThat( actual, containsString( "| [:`RELATIONSHIP,TYPE` {prop2: 1, prop1: \"prop1, value\"}] |" ) ); + assertThat( actual, containsString( "| (:`label ``1`:label2 {`1prop1`: \"\\\"\\\"\", " + + "prop1: \"prop1:value\", ä: \"not-escaped\"}) |" ) ); } @Test - public void basicTable() { + public void basicTable() + { // GIVEN - Result result = mockResult(asList("c1", "c2"), "a", 42); + Result result = mockResult( asList( "c1", "c2" ), "a", 42 ); // WHEN - String table = formatResult(result); + String table = formatResult( result ); // THEN - assertThat(table, containsString("| c1 | c2 |")); - assertThat(table, containsString("| \"a\" | 42 |")); + assertThat( table, containsString( "| c1 | c2 |" ) ); + assertThat( table, containsString( "| \"a\" | 42 |" ) ); } @Test - public void twoRowsWithNumbersAllSampled() { + public void twoRowsWithNumbersAllSampled() + { // GIVEN - Result result = mockResult(asList("c1", "c2"), "a", 42, "b", 43); + Result result = mockResult( asList( "c1", "c2" ), "a", 42, "b", 43 ); // WHEN - String table = formatResult(result); + String table = formatResult( result ); // THEN - assertThat(table, containsString("| \"a\" | 42 |")); - assertThat(table, containsString("| \"b\" | 43 |")); + assertThat( table, containsString( "| \"a\" | 42 |" ) ); + assertThat( table, containsString( "| \"b\" | 43 |" ) ); } @Test - public void fiveRowsWithNumbersNotAllSampled() { + public void fiveRowsWithNumbersNotAllSampled() + { // GIVEN - Result result = mockResult(asList("c1", "c2"), "a", 42, "b", 43, "c", 44, "d", 45, "e", 46); + Result result = mockResult( asList( "c1", "c2" ), "a", 42, "b", 43, "c", 44, "d", 45, "e", 46 ); // WHEN - String table = formatResult(result); + String table = formatResult( result ); // THEN - assertThat(table, containsString("| \"a\" | 42 |")); - assertThat(table, containsString("| \"b\" | 43 |")); - assertThat(table, containsString("| \"c\" | 44 |")); - assertThat(table, containsString("| \"d\" | 45 |")); - assertThat(table, containsString("| \"e\" | 46 |")); + assertThat( table, containsString( "| \"a\" | 42 |" ) ); + assertThat( table, containsString( "| \"b\" | 43 |" ) ); + assertThat( table, containsString( "| \"c\" | 44 |" ) ); + assertThat( table, containsString( "| \"d\" | 45 |" ) ); + assertThat( table, containsString( "| \"e\" | 46 |" ) ); } @Test public void wrapStringContent() { // GIVEN - Result result = mockResult( asList( "c1"), "a", "bb","ccc","dddd","eeeee" ); + Result result = mockResult( asList( "c1" ), "a", "bb", "ccc", "dddd", "eeeee" ); // WHEN ToStringLinePrinter printer = new ToStringLinePrinter(); - new TableOutputFormatter(true, 2).formatAndCount(new ListBoltResult(result.list(), result.consume()), printer); + new TableOutputFormatter( true, 2 ).formatAndCount( new ListBoltResult( result.list(), result.consume() ), printer ); String table = printer.result(); // THEN - assertThat(table, is(String.join(NEWLINE, - "+------+", - "| c1 |", - "+------+", - "| \"a\" |", - "| \"bb\" |", - "| \"ccc |", - "\\ \" |", - "| \"ddd |", - "\\ d\" |", - "| \"eee |", - "\\ ee\" |", - "+------+", - NEWLINE))); + assertThat( table, is( String.join( NEWLINE, + "+------+", + "| c1 |", + "+------+", + "| \"a\" |", + "| \"bb\" |", + "| \"ccc |", + "\\ \" |", + "| \"ddd |", + "\\ d\" |", + "| \"eee |", + "\\ ee\" |", + "+------+", + NEWLINE ) ) ); } @Test @@ -360,141 +383,147 @@ public void wrapStringContentWithTwoColumns() { // GIVEN Result result = mockResult( asList( "c1", "c2" ), "a", "b", - "aa", "bb", - "aaa", "b", - "a", "bbb", - "aaaa", "bb", - "aa", "bbbb", - "aaaaa", "bbbbb" ); + "aa", "bb", + "aaa", "b", + "a", "bbb", + "aaaa", "bb", + "aa", "bbbb", + "aaaaa", "bbbbb" ); // WHEN ToStringLinePrinter printer = new ToStringLinePrinter(); - new TableOutputFormatter(true, 2).formatAndCount(new ListBoltResult(result.list(), result.consume()), printer); + new TableOutputFormatter( true, 2 ).formatAndCount( new ListBoltResult( result.list(), result.consume() ), printer ); String table = printer.result(); // THEN - assertThat(table, is(String.join(NEWLINE, - "+-------------+", - "| c1 | c2 |", - "+-------------+", - "| \"a\" | \"b\" |", - "| \"aa\" | \"bb\" |", - "| \"aaa | \"b\" |", - "\\ \" | |", - "| \"a\" | \"bbb |", - "| \\ \" |", - "| \"aaa | \"bb\" |", - "\\ a\" | |", - "| \"aa\" | \"bbb |", - "| \\ b\" |", - "| \"aaa | \"bbb |", - "\\ aa\" \\ bb\" |", - "+-------------+", - NEWLINE))); + assertThat( table, is( String.join( NEWLINE, + "+-------------+", + "| c1 | c2 |", + "+-------------+", + "| \"a\" | \"b\" |", + "| \"aa\" | \"bb\" |", + "| \"aaa | \"b\" |", + "\\ \" | |", + "| \"a\" | \"bbb |", + "| \\ \" |", + "| \"aaa | \"bb\" |", + "\\ a\" | |", + "| \"aa\" | \"bbb |", + "| \\ b\" |", + "| \"aaa | \"bbb |", + "\\ aa\" \\ bb\" |", + "+-------------+", + NEWLINE ) ) ); } @Test public void wrapNumberContentWithLongSize() { // GIVEN - Result result = mockResult( asList( "c1"), 345, 12, 978623, 132456798, 9223372036854775807L ); - result = mockResult( asList( "c1"), 345, 12, 978623, 132456798, 9223372036854775807L ); + Result result = mockResult( asList( "c1" ), 345, 12, 978623, 132456798, 9223372036854775807L ); + result = mockResult( asList( "c1" ), 345, 12, 978623, 132456798, 9223372036854775807L ); // WHEN ToStringLinePrinter printer = new ToStringLinePrinter(); - new TableOutputFormatter(true, 2).formatAndCount(new ListBoltResult(result.list(), result.consume()), printer); + new TableOutputFormatter( true, 2 ).formatAndCount( new ListBoltResult( result.list(), result.consume() ), printer ); String table = printer.result(); // THEN - assertThat(table, is(String.join(NEWLINE, - "+---------------------+", - "| c1 |", - "+---------------------+", - "| 345 |", - "| 12 |", - "| 978623 |", - "| 132456798 |", - "| 9223372036854775807 |", - "+---------------------+", - NEWLINE))); + assertThat( table, is( String.join( NEWLINE, + "+---------------------+", + "| c1 |", + "+---------------------+", + "| 345 |", + "| 12 |", + "| 978623 |", + "| 132456798 |", + "| 9223372036854775807 |", + "+---------------------+", + NEWLINE ) ) ); } @Test public void truncateContent() { // GIVEN - Result result = mockResult( asList( "c1"), "a", "bb","ccc","dddd","eeeee" ); + Result result = mockResult( asList( "c1" ), "a", "bb", "ccc", "dddd", "eeeee" ); // WHEN ToStringLinePrinter printer = new ToStringLinePrinter(); - new TableOutputFormatter(false, 2).formatAndCount(new ListBoltResult(result.list(), result.consume()), printer); + new TableOutputFormatter( false, 2 ).formatAndCount( new ListBoltResult( result.list(), result.consume() ), printer ); String table = printer.result(); // THEN - assertThat(table, is(String.join(NEWLINE, - "+------+", - "| c1 |", - "+------+", - "| \"a\" |", - "| \"bb\" |", - "| \"cc… |", - "| \"dd… |", - "| \"ee… |", - "+------+", - NEWLINE))); + assertThat( table, is( String.join( NEWLINE, + "+------+", + "| c1 |", + "+------+", + "| \"a\" |", + "| \"bb\" |", + "| \"cc… |", + "| \"dd… |", + "| \"ee… |", + "+------+", + NEWLINE ) ) ); } @Test - public void formatCollections() { + public void formatCollections() + { // GIVEN - Result result = mockResult(asList("a", "b", "c"), singletonMap("a", 42), asList(12, 13), - singletonMap("a", asList(14, 15))); + Result result = mockResult( asList( "a", "b", "c" ), singletonMap( "a", 42 ), asList( 12, 13 ), + singletonMap( "a", asList( 14, 15 ) ) ); // WHEN - String table = formatResult(result); + String table = formatResult( result ); // THEN - assertThat(table, containsString("| {a: 42} | [12, 13] | {a: [14, 15]} |")); + assertThat( table, containsString( "| {a: 42} | [12, 13] | {a: [14, 15]} |" ) ); } @Test - public void formatEntities() { + public void formatEntities() + { // GIVEN - Map properties = singletonMap("name", Values.value("Mark")); - Map relProperties = singletonMap("since", Values.value(2016)); - InternalNode node = new InternalNode(12, asList("Person"), properties); - InternalRelationship relationship = new InternalRelationship(24, 12, 12, "TEST", relProperties); + Map properties = singletonMap( "name", Values.value( "Mark" ) ); + Map relProperties = singletonMap( "since", Values.value( 2016 ) ); + InternalNode node = new InternalNode( 12, asList( "Person" ), properties ); + InternalRelationship relationship = new InternalRelationship( 24, 12, 12, "TEST", relProperties ); Result result = - mockResult(asList("a", "b", "c"), node, relationship, new InternalPath(node, relationship, node)); + mockResult( asList( "a", "b", "c" ), node, relationship, new InternalPath( node, relationship, node ) ); // WHEN - String table = formatResult(result); + String table = formatResult( result ); // THEN - assertThat(table, containsString("| (:Person {name: \"Mark\"}) | [:TEST {since: 2016}] |")); - assertThat(table, containsString( - "| (:Person {name: \"Mark\"})-[:TEST {since: 2016}]->(:Person {name: \"Mark\"}) |")); + assertThat( table, containsString( "| (:Person {name: \"Mark\"}) | [:TEST {since: 2016}] |" ) ); + assertThat( table, containsString( + "| (:Person {name: \"Mark\"})-[:TEST {since: 2016}]->(:Person {name: \"Mark\"}) |" ) ); } - private String formatResult(Result result) { + private String formatResult( Result result ) + { ToStringLinePrinter printer = new ToStringLinePrinter(); - new TableOutputFormatter(true, 1000).formatAndCount(new ListBoltResult(result.list(), result.consume()), printer); + new TableOutputFormatter( true, 1000 ).formatAndCount( new ListBoltResult( result.list(), result.consume() ), printer ); return printer.result(); } - private Result mockResult(List cols, Object... data) { - Result result = mock(Result.class); - Query query = mock(Query.class); - ResultSummary summary = mock(ResultSummary.class); - when(summary.query()).thenReturn(query); - when(result.keys()).thenReturn(cols); + private Result mockResult( List cols, Object... data ) + { + Result result = mock( Result.class ); + Query query = mock( Query.class ); + ResultSummary summary = mock( ResultSummary.class ); + when( summary.query() ).thenReturn( query ); + when( result.keys() ).thenReturn( cols ); List records = new ArrayList<>(); - List input = asList(data); + List input = asList( data ); int width = cols.size(); - for (int row = 0; row < input.size() / width; row++) { - records.add(record(cols, input.subList(row * width, (row + 1) * width))); + for ( int row = 0; row < input.size() / width; row++ ) + { + records.add( record( cols, input.subList( row * width, (row + 1) * width ) ) ); } - when(result.list()).thenReturn(records); - when(result.consume()).thenReturn(summary); - when(result.consume()).thenReturn(summary); + when( result.list() ).thenReturn( records ); + when( result.consume() ).thenReturn( summary ); + when( result.consume() ).thenReturn( summary ); return result; } - private Record record(List cols, List data) { + private Record record( List cols, List data ) + { assert cols.size() == data.size(); Value[] values = data.stream() - .map(Values::value) - .toArray(Value[]::new); - return new InternalRecord(cols, values); + .map( Values::value ) + .toArray( Value[]::new ); + return new InternalRecord( cols, values ); } } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/prettyprint/TablePlanFormatterTest.java b/cypher-shell/src/test/java/org/neo4j/shell/prettyprint/TablePlanFormatterTest.java index dffc4932..f5ea4e66 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/prettyprint/TablePlanFormatterTest.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/prettyprint/TablePlanFormatterTest.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.prettyprint; import org.junit.Test; @@ -25,110 +44,131 @@ public class TablePlanFormatterTest TablePlanFormatter tablePlanFormatter = new TablePlanFormatter(); @Test - public void withNoDetails() { - Plan plan = mock(Plan.class); - Map args = Collections.singletonMap( "EstimatedRows", new FloatValue(55)); - when(plan.arguments()).thenReturn(args); - when(plan.operatorType()).thenReturn("Projection"); - - assertThat(tablePlanFormatter.formatPlan( plan ), is(String.join(NEWLINE, - "+-------------+----------------+", - "| Operator | Estimated Rows |", - "+-------------+----------------+", - "| +Projection | 55 |", - "+-------------+----------------+", ""))); + public void withNoDetails() + { + Plan plan = mock( Plan.class ); + Map args = Collections.singletonMap( "EstimatedRows", new FloatValue( 55 ) ); + when( plan.arguments() ).thenReturn( args ); + when( plan.operatorType() ).thenReturn( "Projection" ); + + assertThat( tablePlanFormatter.formatPlan( plan ), is( String.join( NEWLINE, + "+-------------+----------------+", + "| Operator | Estimated Rows |", + "+-------------+----------------+", + "| +Projection | 55 |", + "+-------------+----------------+", "" ) ) ); } @Test - public void withEmptyDetails() { - Plan plan = mock(Plan.class); - Map args = new HashMap(2){{put("EstimatedRows", new FloatValue(55));put("Details", new StringValue(""));}}; - when(plan.arguments()).thenReturn(args); - when(plan.operatorType()).thenReturn("Projection"); - - assertThat(tablePlanFormatter.formatPlan( plan ), is(String.join(NEWLINE, - "+-------------+---------+----------------+", - "| Operator | Details | Estimated Rows |", - "+-------------+---------+----------------+", - "| +Projection | | 55 |", - "+-------------+---------+----------------+", ""))); + public void withEmptyDetails() + { + Plan plan = mock( Plan.class ); + Map args = new HashMap( 2 ) + {{ + put( "EstimatedRows", new FloatValue( 55 ) ); + put( "Details", new StringValue( "" ) ); + }}; + when( plan.arguments() ).thenReturn( args ); + when( plan.operatorType() ).thenReturn( "Projection" ); + + assertThat( tablePlanFormatter.formatPlan( plan ), is( String.join( NEWLINE, + "+-------------+---------+----------------+", + "| Operator | Details | Estimated Rows |", + "+-------------+---------+----------------+", + "| +Projection | | 55 |", + "+-------------+---------+----------------+", "" ) ) ); } @Test - public void renderShortDetails() { - Plan plan = mock(Plan.class); - Map args = Collections.singletonMap("Details", new StringValue("x.prop AS prop")); - when(plan.arguments()).thenReturn(args); - when(plan.operatorType()).thenReturn("Projection"); - - assertThat(tablePlanFormatter.formatPlan( plan ), is(String.join(NEWLINE, - "+-------------+----------------+", - "| Operator | Details |", - "+-------------+----------------+", - "| +Projection | x.prop AS prop |", - "+-------------+----------------+", ""))); + public void renderShortDetails() + { + Plan plan = mock( Plan.class ); + Map args = Collections.singletonMap( "Details", new StringValue( "x.prop AS prop" ) ); + when( plan.arguments() ).thenReturn( args ); + when( plan.operatorType() ).thenReturn( "Projection" ); + + assertThat( tablePlanFormatter.formatPlan( plan ), is( String.join( NEWLINE, + "+-------------+----------------+", + "| Operator | Details |", + "+-------------+----------------+", + "| +Projection | x.prop AS prop |", + "+-------------+----------------+", "" ) ) ); } @Test - public void renderExactMaxLengthDetails() { - Plan plan = mock(Plan.class); - String details = stringOfLength(TablePlanFormatter.MAX_DETAILS_COLUMN_WIDTH); - Map args = Collections.singletonMap("Details", new StringValue(details)); - when(plan.arguments()).thenReturn(args); - when(plan.operatorType()).thenReturn("Projection"); - - assertThat(tablePlanFormatter.formatPlan( plan ), containsString("| +Projection | " + details + " |")); + public void renderExactMaxLengthDetails() + { + Plan plan = mock( Plan.class ); + String details = stringOfLength( TablePlanFormatter.MAX_DETAILS_COLUMN_WIDTH ); + Map args = Collections.singletonMap( "Details", new StringValue( details ) ); + when( plan.arguments() ).thenReturn( args ); + when( plan.operatorType() ).thenReturn( "Projection" ); + + assertThat( tablePlanFormatter.formatPlan( plan ), containsString( "| +Projection | " + details + " |" ) ); } @Test - public void multiLineDetails() { - Plan argumentPlan = mock(Plan.class); - when(argumentPlan.arguments()).thenReturn(Collections.emptyMap()); - when(argumentPlan.operatorType()).thenReturn("Argument"); - - Plan childPlan = mock(Plan.class); - Map args = Collections.singletonMap("Details", new StringValue(stringOfLength(TablePlanFormatter.MAX_DETAILS_COLUMN_WIDTH + 5))); - when(childPlan.arguments()).thenReturn(args); - when(childPlan.operatorType()).thenReturn("Expand"); - doReturn(new ArrayList(){{add( argumentPlan);add( argumentPlan);}}).when(childPlan).children(); - - Plan plan = mock(Plan.class); - String details = stringOfLength(TablePlanFormatter.MAX_DETAILS_COLUMN_WIDTH + 1); - args = Collections.singletonMap("Details", new StringValue(details)); - when(plan.arguments()).thenReturn(args); - when(plan.operatorType()).thenReturn("Projection"); - doReturn(new ArrayList(){{add( childPlan);add( childPlan);}}).when(plan).children(); - - assertThat(tablePlanFormatter.formatPlan( plan ), is(String.join(NEWLINE, - "+---------------+------------------------------------------------------------------------------------------------------+", - "| Operator | Details |", - "+---------------+------------------------------------------------------------------------------------------------------+", - "| +Projection | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |", - "| | | a |", - "| |\\ +------------------------------------------------------------------------------------------------------+", - "| | +Expand | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |", - "| | | | aaaaa |", - "| | |\\ +------------------------------------------------------------------------------------------------------+", - "| | | +Argument | |", - "| | | +------------------------------------------------------------------------------------------------------+", - "| | +Argument | |", - "| | +------------------------------------------------------------------------------------------------------+", - "| +Expand | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |", - "| | | aaaaa |", - "| |\\ +------------------------------------------------------------------------------------------------------+", - "| | +Argument | |", - "| | +------------------------------------------------------------------------------------------------------+", - "| +Argument | |", - "+---------------+------------------------------------------------------------------------------------------------------+", ""))); + public void multiLineDetails() + { + Plan argumentPlan = mock( Plan.class ); + when( argumentPlan.arguments() ).thenReturn( Collections.emptyMap() ); + when( argumentPlan.operatorType() ).thenReturn( "Argument" ); + + Plan childPlan = mock( Plan.class ); + Map args = Collections.singletonMap( "Details", new StringValue( stringOfLength( TablePlanFormatter.MAX_DETAILS_COLUMN_WIDTH + 5 ) ) ); + when( childPlan.arguments() ).thenReturn( args ); + when( childPlan.operatorType() ).thenReturn( "Expand" ); + doReturn( new ArrayList() + {{ + add( argumentPlan ); + add( argumentPlan ); + }} ).when( childPlan ).children(); + + Plan plan = mock( Plan.class ); + String details = stringOfLength( TablePlanFormatter.MAX_DETAILS_COLUMN_WIDTH + 1 ); + args = Collections.singletonMap( "Details", new StringValue( details ) ); + when( plan.arguments() ).thenReturn( args ); + when( plan.operatorType() ).thenReturn( "Projection" ); + doReturn( new ArrayList() + {{ + add( childPlan ); + add( childPlan ); + }} ).when( plan ).children(); + + assertThat( tablePlanFormatter.formatPlan( plan ), is( String.join( + NEWLINE, + "+---------------+------------------------------------------------------------------------------------------------------+", + "| Operator | Details |", + "+---------------+------------------------------------------------------------------------------------------------------+", + "| +Projection | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |", + "| | | a |", + "| |\\ +------------------------------------------------------------------------------------------------------+", + "| | +Expand | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |", + "| | | | aaaaa |", + "| | |\\ +------------------------------------------------------------------------------------------------------+", + "| | | +Argument | |", + "| | | +------------------------------------------------------------------------------------------------------+", + "| | +Argument | |", + "| | +------------------------------------------------------------------------------------------------------+", + "| +Expand | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |", + "| | | aaaaa |", + "| |\\ +------------------------------------------------------------------------------------------------------+", + "| | +Argument | |", + "| | +------------------------------------------------------------------------------------------------------+", + "| +Argument | |", + "+---------------+------------------------------------------------------------------------------------------------------+", + "" ) ) ); } - private String stringOfLength(int length) { + private String stringOfLength( int length ) + { StringBuilder strBuilder = new StringBuilder(); - for(int i=0; i. + */ package org.neo4j.shell.prettyprint; import javax.annotation.Nonnull; -public class ToStringLinePrinter implements LinePrinter { +public class ToStringLinePrinter implements LinePrinter +{ final StringBuilder sb; - public ToStringLinePrinter() { + public ToStringLinePrinter() + { this.sb = new StringBuilder(); } @Override - public void printOut(String line) { - sb.append(line); - sb.append(OutputFormatter.NEWLINE); + public void printOut( String line ) + { + sb.append( line ); + sb.append( OutputFormatter.NEWLINE ); } @Nonnull - public String result() { + public String result() + { return sb.toString(); } } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/state/BoltStateHandlerTest.java b/cypher-shell/src/test/java/org/neo4j/shell/state/BoltStateHandlerTest.java index 4dd817a5..adee8899 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/state/BoltStateHandlerTest.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/state/BoltStateHandlerTest.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.state; import org.junit.Before; @@ -57,294 +76,326 @@ import static org.neo4j.shell.DatabaseManager.DEFAULT_DEFAULT_DB_NAME; import static org.neo4j.shell.DatabaseManager.SYSTEM_DB_NAME; -public class BoltStateHandlerTest { +public class BoltStateHandlerTest +{ @Rule public final ExpectedException thrown = ExpectedException.none(); - private final Logger logger = mock(Logger.class); - private final Driver mockDriver = mock(Driver.class); - private final OfflineBoltStateHandler boltStateHandler = new OfflineBoltStateHandler(mockDriver); - private final ConnectionConfig config = new ConnectionConfig("bolt", "", -1, "", "", Encryption.DEFAULT, ABSENT_DB_NAME); + private final Logger logger = mock( Logger.class ); + private final Driver mockDriver = mock( Driver.class ); + private final OfflineBoltStateHandler boltStateHandler = new OfflineBoltStateHandler( mockDriver ); + private final ConnectionConfig config = new ConnectionConfig( "bolt", "", -1, "", "", Encryption.DEFAULT, ABSENT_DB_NAME ); @Before - public void setup() { - when(mockDriver.session(any())).thenReturn(new FakeSession()); - doReturn(System.out).when(logger).getOutputStream(); + public void setup() + { + when( mockDriver.session( any() ) ).thenReturn( new FakeSession() ); + doReturn( System.out ).when( logger ).getOutputStream(); } @Test - public void versionIsEmptyBeforeConnect() { - assertFalse(boltStateHandler.isConnected()); - assertEquals("", boltStateHandler.getServerVersion()); + public void versionIsEmptyBeforeConnect() + { + assertFalse( boltStateHandler.isConnected() ); + assertEquals( "", boltStateHandler.getServerVersion() ); } @Test - public void versionIsEmptyIfDriverReturnsNull() throws CommandException { - RecordingDriverProvider provider = new RecordingDriverProvider() { + public void versionIsEmptyIfDriverReturnsNull() throws CommandException + { + RecordingDriverProvider provider = new RecordingDriverProvider() + { @Override - public Driver apply(String uri, AuthToken authToken, Config config) { - super.apply(uri, authToken, config); + public Driver apply( String uri, AuthToken authToken, Config config ) + { + super.apply( uri, authToken, config ); return new FakeDriver(); } }; - BoltStateHandler handler = new BoltStateHandler(provider, false); - handler.connect(config); + BoltStateHandler handler = new BoltStateHandler( provider, false ); + handler.connect( config ); - assertEquals("", handler.getServerVersion()); + assertEquals( "", handler.getServerVersion() ); } @Test - public void versionIsNotEmptyAfterConnect() throws CommandException { - Driver driverMock = stubResultSummaryInAnOpenSession(mock(Result.class), mock(Session.class), "Neo4j/9.4.1-ALPHA"); + public void versionIsNotEmptyAfterConnect() throws CommandException + { + Driver driverMock = stubResultSummaryInAnOpenSession( mock( Result.class ), mock( Session.class ), "Neo4j/9.4.1-ALPHA" ); - BoltStateHandler handler = new BoltStateHandler((s, authToken, config) -> driverMock, false); - handler.connect(config); + BoltStateHandler handler = new BoltStateHandler( ( s, authToken, config ) -> driverMock, false ); + handler.connect( config ); - assertEquals("9.4.1-ALPHA", handler.getServerVersion()); + assertEquals( "9.4.1-ALPHA", handler.getServerVersion() ); } @Test - public void actualDatabaseNameIsNotEmptyAfterConnect() throws CommandException { + public void actualDatabaseNameIsNotEmptyAfterConnect() throws CommandException + { Driver driverMock = - stubResultSummaryInAnOpenSession(mock(Result.class), mock(Session.class), "Neo4j/9.4.1-ALPHA", "my_default_db"); + stubResultSummaryInAnOpenSession( mock( Result.class ), mock( Session.class ), "Neo4j/9.4.1-ALPHA", "my_default_db" ); - BoltStateHandler handler = new BoltStateHandler((s, authToken, config) -> driverMock, false); - handler.connect(config); + BoltStateHandler handler = new BoltStateHandler( ( s, authToken, config ) -> driverMock, false ); + handler.connect( config ); - assertEquals("my_default_db", handler.getActualDatabaseAsReportedByServer()); + assertEquals( "my_default_db", handler.getActualDatabaseAsReportedByServer() ); } @Test - public void exceptionFromRunQueryDoesNotResetActualDatabaseNameToUnresolved() throws CommandException { - Session sessionMock = mock(Session.class); - Result resultMock = mock(Result.class); + public void exceptionFromRunQueryDoesNotResetActualDatabaseNameToUnresolved() throws CommandException + { + Session sessionMock = mock( Session.class ); + Result resultMock = mock( Result.class ); Driver driverMock = - stubResultSummaryInAnOpenSession(resultMock, sessionMock, "Neo4j/9.4.1-ALPHA", "my_default_db"); + stubResultSummaryInAnOpenSession( resultMock, sessionMock, "Neo4j/9.4.1-ALPHA", "my_default_db" ); - ClientException databaseNotFound = new ClientException("Neo.ClientError.Database.DatabaseNotFound", "blah"); + ClientException databaseNotFound = new ClientException( "Neo.ClientError.Database.DatabaseNotFound", "blah" ); - when(sessionMock.run(any(Query.class))) - .thenThrow(databaseNotFound) - .thenReturn(resultMock); + when( sessionMock.run( any( Query.class ) ) ) + .thenThrow( databaseNotFound ) + .thenReturn( resultMock ); - BoltStateHandler handler = new BoltStateHandler((s, authToken, config) -> driverMock, false); - handler.connect(config); + BoltStateHandler handler = new BoltStateHandler( ( s, authToken, config ) -> driverMock, false ); + handler.connect( config ); - try { - handler.runCypher("RETURN \"hello\"", Collections.emptyMap()); - fail("should fail on runCypher"); - } catch (Exception e) { - assertThat(e, is(databaseNotFound)); - assertEquals("my_default_db", handler.getActualDatabaseAsReportedByServer()); + try + { + handler.runCypher( "RETURN \"hello\"", Collections.emptyMap() ); + fail( "should fail on runCypher" ); + } + catch ( Exception e ) + { + assertThat( e, is( databaseNotFound ) ); + assertEquals( "my_default_db", handler.getActualDatabaseAsReportedByServer() ); } } @Test - public void closeTransactionAfterRollback() throws CommandException { + public void closeTransactionAfterRollback() throws CommandException + { boltStateHandler.connect(); boltStateHandler.beginTransaction(); - assertTrue(boltStateHandler.isTransactionOpen()); + assertTrue( boltStateHandler.isTransactionOpen() ); boltStateHandler.rollbackTransaction(); - assertFalse(boltStateHandler.isTransactionOpen()); + assertFalse( boltStateHandler.isTransactionOpen() ); } @Test - public void exceptionsFromSilentDisconnectAreSuppressedToReportOriginalErrors() { - Session session = mock(Session.class); - Result resultMock = mock(Result.class); + public void exceptionsFromSilentDisconnectAreSuppressedToReportOriginalErrors() + { + Session session = mock( Session.class ); + Result resultMock = mock( Result.class ); - RuntimeException originalException = new RuntimeException("original exception"); - RuntimeException thrownFromSilentDisconnect = new RuntimeException("exception from silent disconnect"); + RuntimeException originalException = new RuntimeException( "original exception" ); + RuntimeException thrownFromSilentDisconnect = new RuntimeException( "exception from silent disconnect" ); - Driver mockedDriver = stubResultSummaryInAnOpenSession(resultMock, session, "neo4j-version"); - OfflineBoltStateHandler boltStateHandler = new OfflineBoltStateHandler(mockedDriver); + Driver mockedDriver = stubResultSummaryInAnOpenSession( resultMock, session, "neo4j-version" ); + OfflineBoltStateHandler boltStateHandler = new OfflineBoltStateHandler( mockedDriver ); - when(resultMock.consume()).thenThrow(originalException); - doThrow(thrownFromSilentDisconnect).when(session).close(); + when( resultMock.consume() ).thenThrow( originalException ); + doThrow( thrownFromSilentDisconnect ).when( session ).close(); - try { + try + { boltStateHandler.connect(); - fail("should fail on silent disconnect"); - } catch (Exception e) { - assertThat(e.getSuppressed()[0], is(thrownFromSilentDisconnect)); - assertThat(e, is(originalException)); + fail( "should fail on silent disconnect" ); + } + catch ( Exception e ) + { + assertThat( e.getSuppressed()[0], is( thrownFromSilentDisconnect ) ); + assertThat( e, is( originalException ) ); } } @Test - public void closeTransactionAfterCommit() throws CommandException { + public void closeTransactionAfterCommit() throws CommandException + { boltStateHandler.connect(); boltStateHandler.beginTransaction(); - assertTrue(boltStateHandler.isTransactionOpen()); + assertTrue( boltStateHandler.isTransactionOpen() ); boltStateHandler.commitTransaction(); - assertFalse(boltStateHandler.isTransactionOpen()); + assertFalse( boltStateHandler.isTransactionOpen() ); } @Test - public void beginNeedsToBeConnected() throws CommandException { - thrown.expect(CommandException.class); - thrown.expectMessage("Not connected to Neo4j"); + public void beginNeedsToBeConnected() throws CommandException + { + thrown.expect( CommandException.class ); + thrown.expectMessage( "Not connected to Neo4j" ); - assertFalse(boltStateHandler.isConnected()); + assertFalse( boltStateHandler.isConnected() ); boltStateHandler.beginTransaction(); } @Test - public void commitNeedsToBeConnected() throws CommandException { - thrown.expect(CommandException.class); - thrown.expectMessage("Not connected to Neo4j"); + public void commitNeedsToBeConnected() throws CommandException + { + thrown.expect( CommandException.class ); + thrown.expectMessage( "Not connected to Neo4j" ); - assertFalse(boltStateHandler.isConnected()); + assertFalse( boltStateHandler.isConnected() ); boltStateHandler.commitTransaction(); } @Test - public void beginNeedsToInitialiseTransactionStatements() throws CommandException { + public void beginNeedsToInitialiseTransactionStatements() throws CommandException + { boltStateHandler.connect(); boltStateHandler.beginTransaction(); - assertTrue(boltStateHandler.isTransactionOpen()); + assertTrue( boltStateHandler.isTransactionOpen() ); } @Test - public void whenInTransactionHandlerLetsTransactionDoTheWork() throws CommandException { - Transaction transactionMock = mock(Transaction.class); - Session sessionMock = mock(Session.class); - when(sessionMock.beginTransaction()).thenReturn(transactionMock); - Driver driverMock = stubResultSummaryInAnOpenSession(mock(Result.class), sessionMock, "neo4j-version"); + public void whenInTransactionHandlerLetsTransactionDoTheWork() throws CommandException + { + Transaction transactionMock = mock( Transaction.class ); + Session sessionMock = mock( Session.class ); + when( sessionMock.beginTransaction() ).thenReturn( transactionMock ); + Driver driverMock = stubResultSummaryInAnOpenSession( mock( Result.class ), sessionMock, "neo4j-version" ); - Result result = mock(Result.class); + Result result = mock( Result.class ); - when(transactionMock.run((Query)anyObject())).thenReturn(result); + when( transactionMock.run( (Query) anyObject() ) ).thenReturn( result ); - OfflineBoltStateHandler boltStateHandler = new OfflineBoltStateHandler(driverMock); + OfflineBoltStateHandler boltStateHandler = new OfflineBoltStateHandler( driverMock ); boltStateHandler.connect(); boltStateHandler.beginTransaction(); - BoltResult boltResult = boltStateHandler.runCypher("UNWIND [1,2] as num RETURN *", Collections.emptyMap()).get(); - assertEquals(result, boltResult.iterate()); + BoltResult boltResult = boltStateHandler.runCypher( "UNWIND [1,2] as num RETURN *", Collections.emptyMap() ).get(); + assertEquals( result, boltResult.iterate() ); boltStateHandler.commitTransaction(); - assertFalse(boltStateHandler.isTransactionOpen()); - + assertFalse( boltStateHandler.isTransactionOpen() ); } @Test - public void rollbackNeedsToBeConnected() throws CommandException { - thrown.expect(CommandException.class); - thrown.expectMessage("Not connected to Neo4j"); + public void rollbackNeedsToBeConnected() throws CommandException + { + thrown.expect( CommandException.class ); + thrown.expectMessage( "Not connected to Neo4j" ); - assertFalse(boltStateHandler.isConnected()); + assertFalse( boltStateHandler.isConnected() ); boltStateHandler.rollbackTransaction(); } @Test - public void executeNeedsToBeConnected() throws CommandException { - thrown.expect(CommandException.class); - thrown.expectMessage("Not connected to Neo4j"); + public void executeNeedsToBeConnected() throws CommandException + { + thrown.expect( CommandException.class ); + thrown.expectMessage( "Not connected to Neo4j" ); - boltStateHandler.runCypher("", Collections.emptyMap()); + boltStateHandler.runCypher( "", Collections.emptyMap() ); } @Test - public void shouldExecuteInTransactionIfOpen() throws CommandException { + public void shouldExecuteInTransactionIfOpen() throws CommandException + { boltStateHandler.connect(); boltStateHandler.beginTransaction(); - assertTrue("Expected a transaction", boltStateHandler.isTransactionOpen()); + assertTrue( "Expected a transaction", boltStateHandler.isTransactionOpen() ); } @Test - public void shouldRunCypherQuery() throws CommandException { - Session sessionMock = mock(Session.class); - Result resultMock = mock(Result.class); - Record recordMock = mock(Record.class); - Value valueMock = mock(Value.class); + public void shouldRunCypherQuery() throws CommandException + { + Session sessionMock = mock( Session.class ); + Result resultMock = mock( Result.class ); + Record recordMock = mock( Record.class ); + Value valueMock = mock( Value.class ); - Driver driverMock = stubResultSummaryInAnOpenSession(resultMock, sessionMock, "neo4j-version"); + Driver driverMock = stubResultSummaryInAnOpenSession( resultMock, sessionMock, "neo4j-version" ); - when(resultMock.list()).thenReturn(singletonList(recordMock)); + when( resultMock.list() ).thenReturn( singletonList( recordMock ) ); - when(valueMock.toString()).thenReturn("999"); - when(recordMock.get(0)).thenReturn(valueMock); - when(sessionMock.run(any(Query.class))).thenReturn(resultMock); + when( valueMock.toString() ).thenReturn( "999" ); + when( recordMock.get( 0 ) ).thenReturn( valueMock ); + when( sessionMock.run( any( Query.class ) ) ).thenReturn( resultMock ); - OfflineBoltStateHandler boltStateHandler = new OfflineBoltStateHandler(driverMock); + OfflineBoltStateHandler boltStateHandler = new OfflineBoltStateHandler( driverMock ); boltStateHandler.connect(); - BoltResult boltResult = boltStateHandler.runCypher("RETURN 999", - new HashMap<>()).get(); - verify(sessionMock).run(any(Query.class)); + BoltResult boltResult = boltStateHandler.runCypher( "RETURN 999", + new HashMap<>() ).get(); + verify( sessionMock ).run( any( Query.class ) ); - assertEquals("999", boltResult.getRecords().get(0).get(0).toString()); + assertEquals( "999", boltResult.getRecords().get( 0 ).get( 0 ).toString() ); } @Test - public void triesAgainOnSessionExpired() throws Exception { - Session sessionMock = mock(Session.class); - Result resultMock = mock(Result.class); - Record recordMock = mock(Record.class); - Value valueMock = mock(Value.class); + public void triesAgainOnSessionExpired() throws Exception + { + Session sessionMock = mock( Session.class ); + Result resultMock = mock( Result.class ); + Record recordMock = mock( Record.class ); + Value valueMock = mock( Value.class ); - Driver driverMock = stubResultSummaryInAnOpenSession(resultMock, sessionMock, "neo4j-version"); + Driver driverMock = stubResultSummaryInAnOpenSession( resultMock, sessionMock, "neo4j-version" ); - when(resultMock.list()).thenReturn(singletonList(recordMock)); + when( resultMock.list() ).thenReturn( singletonList( recordMock ) ); - when(valueMock.toString()).thenReturn("999"); - when(recordMock.get(0)).thenReturn(valueMock); - when(sessionMock.run(any(Query.class))) - .thenThrow(new SessionExpiredException("leaderswitch")) - .thenReturn(resultMock); + when( valueMock.toString() ).thenReturn( "999" ); + when( recordMock.get( 0 ) ).thenReturn( valueMock ); + when( sessionMock.run( any( Query.class ) ) ) + .thenThrow( new SessionExpiredException( "leaderswitch" ) ) + .thenReturn( resultMock ); - OfflineBoltStateHandler boltStateHandler = new OfflineBoltStateHandler(driverMock); + OfflineBoltStateHandler boltStateHandler = new OfflineBoltStateHandler( driverMock ); boltStateHandler.connect(); - BoltResult boltResult = boltStateHandler.runCypher("RETURN 999", - new HashMap<>()).get(); + BoltResult boltResult = boltStateHandler.runCypher( "RETURN 999", + new HashMap<>() ).get(); - verify(driverMock, times(2)).session(any()); - verify(sessionMock, times(2)).run(any(Query.class)); + verify( driverMock, times( 2 ) ).session( any() ); + verify( sessionMock, times( 2 ) ).run( any( Query.class ) ); - assertEquals("999", boltResult.getRecords().get(0).get(0).toString()); + assertEquals( "999", boltResult.getRecords().get( 0 ).get( 0 ).toString() ); } @Test - public void shouldExecuteInSessionByDefault() throws CommandException { + public void shouldExecuteInSessionByDefault() throws CommandException + { boltStateHandler.connect(); - assertFalse("Did not expect a transaction", boltStateHandler.isTransactionOpen()); + assertFalse( "Did not expect a transaction", boltStateHandler.isTransactionOpen() ); } @Test - public void canOnlyConnectOnce() throws CommandException { - thrown.expect(CommandException.class); - thrown.expectMessage("Already connected"); + public void canOnlyConnectOnce() throws CommandException + { + thrown.expect( CommandException.class ); + thrown.expectMessage( "Already connected" ); - try { + try + { boltStateHandler.connect(); - } catch (Throwable e) { - fail("Should not throw here: " + e); + } + catch ( Throwable e ) + { + fail( "Should not throw here: " + e ); } boltStateHandler.connect(); } @Test - public void resetSessionOnReset() throws Exception { + public void resetSessionOnReset() throws Exception + { // given - Session sessionMock = mock(Session.class); - Driver driverMock = stubResultSummaryInAnOpenSession(mock(Result.class), sessionMock, "neo4j-version"); + Session sessionMock = mock( Session.class ); + Driver driverMock = stubResultSummaryInAnOpenSession( mock( Result.class ), sessionMock, "neo4j-version" ); - OfflineBoltStateHandler boltStateHandler = new OfflineBoltStateHandler(driverMock); + OfflineBoltStateHandler boltStateHandler = new OfflineBoltStateHandler( driverMock ); boltStateHandler.connect(); boltStateHandler.beginTransaction(); @@ -353,274 +404,295 @@ public void resetSessionOnReset() throws Exception { boltStateHandler.reset(); // then - verify(sessionMock).reset(); + verify( sessionMock ).reset(); } @Test - public void silentDisconnectCleansUp() throws Exception { + public void silentDisconnectCleansUp() throws Exception + { // given boltStateHandler.connect(); Session session = boltStateHandler.session; - assertNotNull(session); - assertNotNull(boltStateHandler.driver); + assertNotNull( session ); + assertNotNull( boltStateHandler.driver ); - assertTrue(boltStateHandler.session.isOpen()); + assertTrue( boltStateHandler.session.isOpen() ); // when boltStateHandler.silentDisconnect(); // then - assertFalse(session.isOpen()); + assertFalse( session.isOpen() ); } @Test - public void turnOffEncryptionIfRequested() throws CommandException { + public void turnOffEncryptionIfRequested() throws CommandException + { RecordingDriverProvider provider = new RecordingDriverProvider(); - BoltStateHandler handler = new BoltStateHandler(provider, false); + BoltStateHandler handler = new BoltStateHandler( provider, false ); - handler.connect(config); - assertFalse(provider.config.encrypted()); + handler.connect( config ); + assertFalse( provider.config.encrypted() ); } @Test - public void turnOnEncryptionIfRequested() throws CommandException { + public void turnOnEncryptionIfRequested() throws CommandException + { RecordingDriverProvider provider = new RecordingDriverProvider(); - BoltStateHandler handler = new BoltStateHandler(provider, false); - ConnectionConfig config = new ConnectionConfig("bolt", "", -1, "", "", Encryption.TRUE, ABSENT_DB_NAME); - handler.connect(config); - assertTrue(provider.config.encrypted()); + BoltStateHandler handler = new BoltStateHandler( provider, false ); + ConnectionConfig config = new ConnectionConfig( "bolt", "", -1, "", "", Encryption.TRUE, ABSENT_DB_NAME ); + handler.connect( config ); + assertTrue( provider.config.encrypted() ); } @Test - public void fallbackToBolt() throws CommandException { + public void fallbackToBolt() throws CommandException + { final String[] uriScheme = new String[1]; - RecordingDriverProvider provider = new RecordingDriverProvider() { + RecordingDriverProvider provider = new RecordingDriverProvider() + { @Override - public Driver apply(String uri, AuthToken authToken, Config config) { - uriScheme[0] = uri.substring(0, uri.indexOf(':')); - if (uriScheme[0].equals("neo4j")) { - throw new org.neo4j.driver.exceptions.ServiceUnavailableException("Please fall back"); + public Driver apply( String uri, AuthToken authToken, Config config ) + { + uriScheme[0] = uri.substring( 0, uri.indexOf( ':' ) ); + if ( uriScheme[0].equals( "neo4j" ) ) + { + throw new org.neo4j.driver.exceptions.ServiceUnavailableException( "Please fall back" ); } - super.apply(uri, authToken, config); + super.apply( uri, authToken, config ); return new FakeDriver(); } }; - BoltStateHandler handler = new BoltStateHandler(provider, false); - ConnectionConfig config = new ConnectionConfig("neo4j", "", -1, "", "", Encryption.DEFAULT, ABSENT_DB_NAME); - handler.connect(config); + BoltStateHandler handler = new BoltStateHandler( provider, false ); + ConnectionConfig config = new ConnectionConfig( "neo4j", "", -1, "", "", Encryption.DEFAULT, ABSENT_DB_NAME ); + handler.connect( config ); - assertEquals("bolt", uriScheme[0]); + assertEquals( "bolt", uriScheme[0] ); } @Test - public void fallbackToLegacyPing() throws CommandException { + public void fallbackToLegacyPing() throws CommandException + { //given - Session sessionMock = mock(Session.class); - Result resultMock = mock(Result.class); - Record recordMock = mock(Record.class); - Value valueMock = mock(Value.class); - Result failing = mock(Result.class); - Result other = mock(Result.class, RETURNS_DEEP_STUBS); - when(failing.consume()).thenThrow( new ClientException( "Neo.ClientError.Procedure.ProcedureNotFound", "No procedure CALL db.ping(()" ) ); - when(sessionMock.run( "CALL db.ping()")).thenReturn( failing ); - when(sessionMock.run( "RETURN 1")).thenReturn( other ); - Driver driverMock = mock(Driver.class); - when(driverMock.session(any())).thenReturn(sessionMock); - OfflineBoltStateHandler boltStateHandler = new OfflineBoltStateHandler(driverMock); + Session sessionMock = mock( Session.class ); + Result resultMock = mock( Result.class ); + Record recordMock = mock( Record.class ); + Value valueMock = mock( Value.class ); + Result failing = mock( Result.class ); + Result other = mock( Result.class, RETURNS_DEEP_STUBS ); + when( failing.consume() ).thenThrow( new ClientException( "Neo.ClientError.Procedure.ProcedureNotFound", "No procedure CALL db.ping(()" ) ); + when( sessionMock.run( "CALL db.ping()" ) ).thenReturn( failing ); + when( sessionMock.run( "RETURN 1" ) ).thenReturn( other ); + Driver driverMock = mock( Driver.class ); + when( driverMock.session( any() ) ).thenReturn( sessionMock ); + OfflineBoltStateHandler boltStateHandler = new OfflineBoltStateHandler( driverMock ); //when boltStateHandler.connect(); //then - verify(sessionMock).run( "RETURN 1"); + verify( sessionMock ).run( "RETURN 1" ); } @Test - public void fallbackToBoltSSC() throws CommandException { + public void fallbackToBoltSSC() throws CommandException + { final String[] uriScheme = new String[1]; - RecordingDriverProvider provider = new RecordingDriverProvider() { + RecordingDriverProvider provider = new RecordingDriverProvider() + { @Override - public Driver apply(String uri, AuthToken authToken, Config config) { - uriScheme[0] = uri.substring(0, uri.indexOf(':')); - if (uriScheme[0].equals("neo4j+ssc")) { - throw new org.neo4j.driver.exceptions.ServiceUnavailableException("Please fall back"); + public Driver apply( String uri, AuthToken authToken, Config config ) + { + uriScheme[0] = uri.substring( 0, uri.indexOf( ':' ) ); + if ( uriScheme[0].equals( "neo4j+ssc" ) ) + { + throw new org.neo4j.driver.exceptions.ServiceUnavailableException( "Please fall back" ); } - super.apply(uri, authToken, config); + super.apply( uri, authToken, config ); return new FakeDriver(); } }; - BoltStateHandler handler = new BoltStateHandler(provider, false); - ConnectionConfig config = new ConnectionConfig("neo4j+ssc", "", -1, "", "", Encryption.DEFAULT, ABSENT_DB_NAME); - handler.connect(config); + BoltStateHandler handler = new BoltStateHandler( provider, false ); + ConnectionConfig config = new ConnectionConfig( "neo4j+ssc", "", -1, "", "", Encryption.DEFAULT, ABSENT_DB_NAME ); + handler.connect( config ); - assertEquals("bolt+ssc", uriScheme[0]); + assertEquals( "bolt+ssc", uriScheme[0] ); } @Test public void shouldChangePasswordAndKeepSystemDbBookmark() throws CommandException { // Given - ConnectionConfig config = new ConnectionConfig("bolt", "", -1, "", "", Encryption.DEFAULT, ABSENT_DB_NAME); - config.setNewPassword("newPW"); - Bookmark bookmark = InternalBookmark.parse("myBookmark"); + ConnectionConfig config = new ConnectionConfig( "bolt", "", -1, "", "", Encryption.DEFAULT, ABSENT_DB_NAME ); + config.setNewPassword( "newPW" ); + Bookmark bookmark = InternalBookmark.parse( "myBookmark" ); - Session sessionMock = mock(Session.class); - Result resultMock = mock(Result.class); - Driver driverMock = stubResultSummaryInAnOpenSession(resultMock, sessionMock, "Neo4j/9.4.1-ALPHA", "my_default_db"); - when(sessionMock.run("CALL dbms.security.changePassword($n)", Values.parameters( "n", config.newPassword()))).thenReturn(resultMock); - when(sessionMock.lastBookmark()).thenReturn(bookmark); - BoltStateHandler handler = new OfflineBoltStateHandler(driverMock); + Session sessionMock = mock( Session.class ); + Result resultMock = mock( Result.class ); + Driver driverMock = stubResultSummaryInAnOpenSession( resultMock, sessionMock, "Neo4j/9.4.1-ALPHA", "my_default_db" ); + when( sessionMock.run( "CALL dbms.security.changePassword($n)", Values.parameters( "n", config.newPassword() ) ) ).thenReturn( resultMock ); + when( sessionMock.lastBookmark() ).thenReturn( bookmark ); + BoltStateHandler handler = new OfflineBoltStateHandler( driverMock ); // When - handler.changePassword(config); + handler.changePassword( config ); // Then - assertEquals("newPW", config.password()); - assertNull(config.newPassword()); - assertNull(handler.session); + assertEquals( "newPW", config.password() ); + assertNull( config.newPassword() ); + assertNull( handler.session ); // When connecting to system db again - handler.connect( new ConnectionConfig("bolt", "", -1, "", "", Encryption.DEFAULT, SYSTEM_DB_NAME) ); + handler.connect( new ConnectionConfig( "bolt", "", -1, "", "", Encryption.DEFAULT, SYSTEM_DB_NAME ) ); // Then use bookmark for system DB - verify( driverMock ).session(SessionConfig.builder() - .withDefaultAccessMode( AccessMode.WRITE ) - .withDatabase( SYSTEM_DB_NAME ) - .withBookmarks( bookmark ) - .build()); + verify( driverMock ).session( SessionConfig.builder() + .withDefaultAccessMode( AccessMode.WRITE ) + .withDatabase( SYSTEM_DB_NAME ) + .withBookmarks( bookmark ) + .build() ); } @SuppressWarnings( "OptionalGetWithoutIsPresent" ) @Test public void shouldKeepOneBookmarkPerDatabase() throws CommandException { - ConnectionConfig config = new ConnectionConfig("bolt", "", -1, "", "", Encryption.DEFAULT, "database1"); - Bookmark db1Bookmark = InternalBookmark.parse("db1"); - Bookmark db2Bookmark = InternalBookmark.parse("db2"); + ConnectionConfig config = new ConnectionConfig( "bolt", "", -1, "", "", Encryption.DEFAULT, "database1" ); + Bookmark db1Bookmark = InternalBookmark.parse( "db1" ); + Bookmark db2Bookmark = InternalBookmark.parse( "db2" ); // A couple of these mock calls are now redundant with what is called in stubResultSummaryInAnOpenSession - Result resultMock = mock(Result.class); - Session db1SessionMock = mock(Session.class); - when(db1SessionMock.isOpen()).thenReturn(true); - when(db1SessionMock.lastBookmark()).thenReturn(db1Bookmark); - when(db1SessionMock.run("CALL db.ping()")).thenReturn(resultMock); - Session db2SessionMock = mock(Session.class); - when(db2SessionMock.isOpen()).thenReturn(true); - when(db2SessionMock.lastBookmark()).thenReturn(db2Bookmark); - when(db2SessionMock.run("CALL db.ping()")).thenReturn(resultMock); - - - Driver driverMock = stubResultSummaryInAnOpenSession(resultMock, db1SessionMock, "Neo4j/9.4.1-ALPHA", "database1"); - when(driverMock.session(any())).thenAnswer(arg -> { - SessionConfig sc = (SessionConfig) arg.getArguments()[0]; - switch ( sc.database().get() ) - { - case "database1": - return db1SessionMock; - case "database2": - return db2SessionMock; - } - return null; - }); - - - BoltStateHandler handler = new OfflineBoltStateHandler(driverMock); + Result resultMock = mock( Result.class ); + Session db1SessionMock = mock( Session.class ); + when( db1SessionMock.isOpen() ).thenReturn( true ); + when( db1SessionMock.lastBookmark() ).thenReturn( db1Bookmark ); + when( db1SessionMock.run( "CALL db.ping()" ) ).thenReturn( resultMock ); + Session db2SessionMock = mock( Session.class ); + when( db2SessionMock.isOpen() ).thenReturn( true ); + when( db2SessionMock.lastBookmark() ).thenReturn( db2Bookmark ); + when( db2SessionMock.run( "CALL db.ping()" ) ).thenReturn( resultMock ); + + Driver driverMock = stubResultSummaryInAnOpenSession( resultMock, db1SessionMock, "Neo4j/9.4.1-ALPHA", "database1" ); + when( driverMock.session( any() ) ).thenAnswer( arg -> + { + SessionConfig sc = (SessionConfig) arg.getArguments()[0]; + switch ( sc.database().get() ) + { + case "database1": + return db1SessionMock; + case "database2": + return db2SessionMock; + default: + return null; + } + } ); + + BoltStateHandler handler = new OfflineBoltStateHandler( driverMock ); // When handler.connect( config ); // Then no bookmark yet for db1 - verify( driverMock ).session(SessionConfig.builder() - .withDefaultAccessMode( AccessMode.WRITE ) - .withDatabase( "database1" ) - .build()); + verify( driverMock ).session( SessionConfig.builder() + .withDefaultAccessMode( AccessMode.WRITE ) + .withDatabase( "database1" ) + .build() ); // When handler.setActiveDatabase( "database2" ); // Then no bookmark yet for db2 - verify( driverMock ).session(SessionConfig.builder() - .withDefaultAccessMode( AccessMode.WRITE ) - .withDatabase( "database2" ) - .build()); + verify( driverMock ).session( SessionConfig.builder() + .withDefaultAccessMode( AccessMode.WRITE ) + .withDatabase( "database2" ) + .build() ); // When handler.setActiveDatabase( "database1" ); // Then use bookmark for db1 - verify( driverMock ).session(SessionConfig.builder() - .withDefaultAccessMode( AccessMode.WRITE ) - .withDatabase( "database1" ) - .withBookmarks( db1Bookmark ) - .build()); + verify( driverMock ).session( SessionConfig.builder() + .withDefaultAccessMode( AccessMode.WRITE ) + .withDatabase( "database1" ) + .withBookmarks( db1Bookmark ) + .build() ); // When handler.setActiveDatabase( "database2" ); // Then use bookmark for db2 - verify( driverMock ).session(SessionConfig.builder() - .withDefaultAccessMode( AccessMode.WRITE ) - .withDatabase( "database2" ) - .withBookmarks( db2Bookmark ) - .build()); + verify( driverMock ).session( SessionConfig.builder() + .withDefaultAccessMode( AccessMode.WRITE ) + .withDatabase( "database2" ) + .withBookmarks( db2Bookmark ) + .build() ); } @Test - public void fallbackToBoltS() throws CommandException { + public void fallbackToBoltS() throws CommandException + { final String[] uriScheme = new String[1]; - RecordingDriverProvider provider = new RecordingDriverProvider() { + RecordingDriverProvider provider = new RecordingDriverProvider() + { @Override - public Driver apply(String uri, AuthToken authToken, Config config) { - uriScheme[0] = uri.substring(0, uri.indexOf(':')); - if (uriScheme[0].equals("neo4j+s")) { - throw new org.neo4j.driver.exceptions.ServiceUnavailableException("Please fall back"); + public Driver apply( String uri, AuthToken authToken, Config config ) + { + uriScheme[0] = uri.substring( 0, uri.indexOf( ':' ) ); + if ( uriScheme[0].equals( "neo4j+s" ) ) + { + throw new org.neo4j.driver.exceptions.ServiceUnavailableException( "Please fall back" ); } - super.apply(uri, authToken, config); + super.apply( uri, authToken, config ); return new FakeDriver(); } }; - BoltStateHandler handler = new BoltStateHandler(provider, false); - ConnectionConfig config = new ConnectionConfig("neo4j+s", "", -1, "", "", Encryption.DEFAULT, ABSENT_DB_NAME); - handler.connect(config); + BoltStateHandler handler = new BoltStateHandler( provider, false ); + ConnectionConfig config = new ConnectionConfig( "neo4j+s", "", -1, "", "", Encryption.DEFAULT, ABSENT_DB_NAME ); + handler.connect( config ); - assertEquals("bolt+s", uriScheme[0]); + assertEquals( "bolt+s", uriScheme[0] ); } @Test - public void provideUserAgentstring() throws CommandException { - RecordingDriverProvider provider = new RecordingDriverProvider() { + public void provideUserAgentstring() throws CommandException + { + RecordingDriverProvider provider = new RecordingDriverProvider() + { @Override - public Driver apply(String uri, AuthToken authToken, Config config) { - super.apply(uri, authToken, config); + public Driver apply( String uri, AuthToken authToken, Config config ) + { + super.apply( uri, authToken, config ); return new FakeDriver(); } }; - BoltStateHandler handler = new BoltStateHandler(provider, false); - handler.connect(config); + BoltStateHandler handler = new BoltStateHandler( provider, false ); + handler.connect( config ); - assertTrue(provider.config.userAgent().startsWith( "neo4j-cypher-shell/v4.1" )); + assertTrue( provider.config.userAgent().startsWith( "neo4j-cypher-shell/v4.1" ) ); } - private Driver stubResultSummaryInAnOpenSession(Result resultMock, Session sessionMock, String version) { - return stubResultSummaryInAnOpenSession(resultMock, sessionMock, version, DEFAULT_DEFAULT_DB_NAME); + private Driver stubResultSummaryInAnOpenSession( Result resultMock, Session sessionMock, String version ) + { + return stubResultSummaryInAnOpenSession( resultMock, sessionMock, version, DEFAULT_DEFAULT_DB_NAME ); } - private Driver stubResultSummaryInAnOpenSession(Result resultMock, Session sessionMock, String version, String databaseName) { - Driver driverMock = mock(Driver.class); - ResultSummary resultSummary = mock(ResultSummary.class); - ServerInfo serverInfo = mock(ServerInfo.class); - DatabaseInfo databaseInfo = mock(DatabaseInfo.class); + private Driver stubResultSummaryInAnOpenSession( Result resultMock, Session sessionMock, String version, String databaseName ) + { + Driver driverMock = mock( Driver.class ); + ResultSummary resultSummary = mock( ResultSummary.class ); + ServerInfo serverInfo = mock( ServerInfo.class ); + DatabaseInfo databaseInfo = mock( DatabaseInfo.class ); - when(resultSummary.server()).thenReturn(serverInfo); - when(serverInfo.version()).thenReturn(version); - when(resultMock.consume()).thenReturn(resultSummary); - when(resultSummary.database()).thenReturn(databaseInfo); - when(databaseInfo.name()).thenReturn(databaseName); + when( resultSummary.server() ).thenReturn( serverInfo ); + when( serverInfo.version() ).thenReturn( version ); + when( resultMock.consume() ).thenReturn( resultSummary ); + when( resultSummary.database() ).thenReturn( databaseInfo ); + when( databaseInfo.name() ).thenReturn( databaseName ); - when(sessionMock.isOpen()).thenReturn(true); - when(sessionMock.run("CALL db.ping()")).thenReturn(resultMock); - when(driverMock.session(any())).thenReturn(sessionMock); + when( sessionMock.isOpen() ).thenReturn( true ); + when( sessionMock.run( "CALL db.ping()" ) ).thenReturn( resultMock ); + when( driverMock.session( any() ) ).thenReturn( sessionMock ); return driverMock; } @@ -628,22 +700,27 @@ private Driver stubResultSummaryInAnOpenSession(Result resultMock, Session sessi /** * Bolt state with faked bolt interactions */ - private static class OfflineBoltStateHandler extends BoltStateHandler { + private static class OfflineBoltStateHandler extends BoltStateHandler + { - public OfflineBoltStateHandler(Driver driver) { - super((uri, authToken, config) -> driver, false); + OfflineBoltStateHandler( Driver driver ) + { + super( ( uri, authToken, config ) -> driver, false ); } - public void connect() throws CommandException { - connect(new ConnectionConfig("bolt", "", 1, "", "", Encryption.DEFAULT, ABSENT_DB_NAME)); + public void connect() throws CommandException + { + connect( new ConnectionConfig( "bolt", "", 1, "", "", Encryption.DEFAULT, ABSENT_DB_NAME ) ); } } - private static class RecordingDriverProvider implements TriFunction { + private static class RecordingDriverProvider implements TriFunction + { public Config config; @Override - public Driver apply(String uri, AuthToken authToken, Config config) { + public Driver apply( String uri, AuthToken authToken, Config config ) + { this.config = config; return new FakeDriver(); } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/test/Util.java b/cypher-shell/src/test/java/org/neo4j/shell/test/Util.java index 758e5c59..8e1a8c67 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/test/Util.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/test/Util.java @@ -1,31 +1,55 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.test; -public class Util { - public static String[] asArray(String... arguments) { +public class Util +{ + public static String[] asArray( String... arguments ) + { return arguments; } - public static class NotImplementedYetException extends RuntimeException { - public NotImplementedYetException(String message) { - super(message); - } - } - /** - * Generate the control code for the specified character. For example, give this method 'C', and it will return - * the code for `Ctrl-C`, which you can append to an inputbuffer for example, in order to simulate the user - * pressing Ctrl-C. + * Generate the control code for the specified character. For example, give this method 'C', and it will return the code for `Ctrl-C`, which you can append + * to an inputbuffer for example, in order to simulate the user pressing Ctrl-C. * * @param let character to generate code for, must be between A and Z * @return control code for given character */ - public static char ctrl(final char let) { - if (let < 'A' || let > 'Z') { - throw new IllegalArgumentException("Cannot generate CTRL code for " - + "char '" + let + "' (" + ((int) let) + ")"); + public static char ctrl( final char let ) + { + if ( let < 'A' || let > 'Z' ) + { + throw new IllegalArgumentException( "Cannot generate CTRL code for " + + "char '" + let + "' (" + ((int) let) + ")" ); } int result = ((int) let) - 'A' + 1; return (char) result; } + + public static class NotImplementedYetException extends RuntimeException + { + public NotImplementedYetException( String message ) + { + super( message ); + } + } } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/test/bolt/FakeDriver.java b/cypher-shell/src/test/java/org/neo4j/shell/test/bolt/FakeDriver.java index 845df647..025f9dfc 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/test/bolt/FakeDriver.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/test/bolt/FakeDriver.java @@ -1,5 +1,26 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.test.bolt; +import java.util.concurrent.CompletionStage; + import org.neo4j.driver.Driver; import org.neo4j.driver.Metrics; import org.neo4j.driver.Session; @@ -9,76 +30,89 @@ import org.neo4j.driver.reactive.RxSession; import org.neo4j.driver.types.TypeSystem; -import java.util.concurrent.CompletionStage; - import static java.util.concurrent.CompletableFuture.completedFuture; -public class FakeDriver implements Driver { +public class FakeDriver implements Driver +{ @Override - public boolean isEncrypted() { + public boolean isEncrypted() + { return false; } @Override - public Session session() { + public Session session() + { return new FakeSession(); } @Override - public Session session( SessionConfig sessionConfig) { + public Session session( SessionConfig sessionConfig ) + { return new FakeSession(); } @Override - public void close() throws Neo4jException { + public void close() throws Neo4jException + { } @Override - public CompletionStage closeAsync() { + public CompletionStage closeAsync() + { return null; } @Override - public Metrics metrics() { + public Metrics metrics() + { return null; } @Override - public boolean isMetricsEnabled() { + public boolean isMetricsEnabled() + { return false; } @Override - public RxSession rxSession() { + public RxSession rxSession() + { return null; } @Override - public RxSession rxSession( SessionConfig sessionConfig ) { + public RxSession rxSession( SessionConfig sessionConfig ) + { return null; } @Override - public AsyncSession asyncSession() { + public AsyncSession asyncSession() + { return null; } @Override - public AsyncSession asyncSession( SessionConfig sessionConfig ) { + public AsyncSession asyncSession( SessionConfig sessionConfig ) + { return null; } @Override - public TypeSystem defaultTypeSystem() { + public TypeSystem defaultTypeSystem() + { return null; } @Override - public void verifyConnectivity() { + public void verifyConnectivity() + { } @Override - public CompletionStage verifyConnectivityAsync() { + public CompletionStage verifyConnectivityAsync() + { return null; } @@ -91,6 +125,6 @@ public boolean supportsMultiDb() @Override public CompletionStage supportsMultiDbAsync() { - return completedFuture(true); + return completedFuture( true ); } } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/test/bolt/FakeRecord.java b/cypher-shell/src/test/java/org/neo4j/shell/test/bolt/FakeRecord.java index 7e61deab..578c47eb 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/test/bolt/FakeRecord.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/test/bolt/FakeRecord.java @@ -1,5 +1,31 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.test.bolt; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.function.Function; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; + import org.neo4j.driver.Record; import org.neo4j.driver.Value; import org.neo4j.driver.types.Entity; @@ -9,251 +35,293 @@ import org.neo4j.driver.util.Pair; import org.neo4j.shell.test.Util; -import javax.annotation.Nonnull; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; -import java.util.function.Function; -import java.util.stream.Collectors; - /** * A fake record of fake values */ -class FakeRecord implements Record { +class FakeRecord implements Record +{ private final TreeMap valueMap = new TreeMap<>(); - private FakeRecord() { + private FakeRecord() + { } - @Override - public List keys() { - return valueMap.keySet().stream().collect(Collectors.toList()); - } - - @Override - public List values() { - return valueMap.values().stream().collect(Collectors.toList()); - } - - @Override - public boolean containsKey(String key) { - return valueMap.containsKey(key); - } - - @Override - public int index(String key) { - return keys().indexOf(key); - } - - @Override - public Value get(String key) { - return valueMap.get(key); - } - - @Override - public Value get(int index) { - return valueMap.get(keys().get(index)); - } - - @Override - public int size() { - return valueMap.size(); - } - - @Override - public Map asMap() { - throw new Util.NotImplementedYetException("Not implemented as no test has required it yet"); - } - - @Override - public Map asMap(Function mapper) { - throw new Util.NotImplementedYetException("Not implemented as no test has required it yet"); - } - - @Override - public List> fields() { - throw new Util.NotImplementedYetException("Not implemented as no test has required it yet"); - } - - public static FakeRecord of(@Nonnull String key, @Nonnull String value) { - return of(key, new FakeValue() { + public static FakeRecord of( @Nonnull String key, @Nonnull String value ) + { + return of( key, new FakeValue() + { @Override - public Value get(String key, Value defaultValue) { + public Value get( String key, Value defaultValue ) + { return null; } @Override - public Object get(String key, Object defaultValue) { + public Object get( String key, Object defaultValue ) + { return null; } @Override - public Number get(String key, Number defaultValue) { + public Number get( String key, Number defaultValue ) + { return null; } @Override - public Entity get(String key, Entity defaultValue) { + public Entity get( String key, Entity defaultValue ) + { return null; } @Override - public Node get(String key, Node defaultValue) { + public Node get( String key, Node defaultValue ) + { return null; } @Override - public Path get(String key, Path defaultValue) { + public Path get( String key, Path defaultValue ) + { return null; } @Override - public Relationship get(String key, Relationship defaultValue) { + public Relationship get( String key, Relationship defaultValue ) + { return null; } @Override - public List get(String key, List defaultValue) { + public List get( String key, List defaultValue ) + { return null; } @Override - public Map get(String key, Map defaultValue) { + public Map get( String key, Map defaultValue ) + { return null; } @Override - public int get(String key, int defaultValue) { + public int get( String key, int defaultValue ) + { return 0; } @Override - public long get(String key, long defaultValue) { + public long get( String key, long defaultValue ) + { return 0; } @Override - public boolean get(String key, boolean defaultValue) { + public boolean get( String key, boolean defaultValue ) + { return false; } @Override - public String get(String key, String defaultValue) { + public String get( String key, String defaultValue ) + { return null; } @Override - public float get(String key, float defaultValue) { + public float get( String key, float defaultValue ) + { return 0; } @Override - public double get(String key, double defaultValue) { + public double get( String key, double defaultValue ) + { return 0; } @Override - public Object asObject() { + public Object asObject() + { return value; } @Override - public String asString() { + public String asString() + { return value; } - }); + } ); } - public static FakeRecord of(@Nonnull String key, @Nonnull Value value) { + public static FakeRecord of( @Nonnull String key, @Nonnull Value value ) + { FakeRecord record = new FakeRecord(); - record.valueMap.put(key, value); + record.valueMap.put( key, value ); return record; } @Override - public Value get(String key, Value defaultValue) { + public List keys() + { + return valueMap.keySet().stream().collect( Collectors.toList() ); + } + + @Override + public List values() + { + return valueMap.values().stream().collect( Collectors.toList() ); + } + + @Override + public boolean containsKey( String key ) + { + return valueMap.containsKey( key ); + } + + @Override + public int index( String key ) + { + return keys().indexOf( key ); + } + + @Override + public Value get( String key ) + { + return valueMap.get( key ); + } + + @Override + public Value get( int index ) + { + return valueMap.get( keys().get( index ) ); + } + + @Override + public int size() + { + return valueMap.size(); + } + + @Override + public Map asMap() + { + throw new Util.NotImplementedYetException( "Not implemented as no test has required it yet" ); + } + + @Override + public Map asMap( Function mapper ) + { + throw new Util.NotImplementedYetException( "Not implemented as no test has required it yet" ); + } + + @Override + public List> fields() + { + throw new Util.NotImplementedYetException( "Not implemented as no test has required it yet" ); + } + + @Override + public Value get( String key, Value defaultValue ) + { return null; } @Override - public Object get(String key, Object defaultValue) { + public Object get( String key, Object defaultValue ) + { return null; } @Override - public Number get(String key, Number defaultValue) { + public Number get( String key, Number defaultValue ) + { return null; } @Override - public Entity get(String key, Entity defaultValue) { + public Entity get( String key, Entity defaultValue ) + { return null; } @Override - public Node get(String key, Node defaultValue) { + public Node get( String key, Node defaultValue ) + { return null; } @Override - public Path get(String key, Path defaultValue) { + public Path get( String key, Path defaultValue ) + { return null; } @Override - public Relationship get(String key, Relationship defaultValue) { + public Relationship get( String key, Relationship defaultValue ) + { return null; } @Override - public List get(String key, List defaultValue) { + public List get( String key, List defaultValue ) + { return null; } @Override - public List get(String key, List defaultValue, Function mapFunc) { + public List get( String key, List defaultValue, Function mapFunc ) + { return null; } @Override - public Map get(String key, Map defaultValue) { + public Map get( String key, Map defaultValue ) + { return null; } @Override - public Map get(String key, Map defaultValue, Function mapFunc) { + public Map get( String key, Map defaultValue, Function mapFunc ) + { return null; } @Override - public int get(String key, int defaultValue) { + public int get( String key, int defaultValue ) + { return 0; } @Override - public long get(String key, long defaultValue) { + public long get( String key, long defaultValue ) + { return 0; } @Override - public boolean get(String key, boolean defaultValue) { + public boolean get( String key, boolean defaultValue ) + { return false; } @Override - public String get(String key, String defaultValue) { + public String get( String key, String defaultValue ) + { return null; } @Override - public float get(String key, float defaultValue) { + public float get( String key, float defaultValue ) + { return 0; } @Override - public double get(String key, double defaultValue) { + public double get( String key, double defaultValue ) + { return 0; } } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/test/bolt/FakeResult.java b/cypher-shell/src/test/java/org/neo4j/shell/test/bolt/FakeResult.java index e8dae9ea..f3dbef20 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/test/bolt/FakeResult.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/test/bolt/FakeResult.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.test.bolt; import java.util.ArrayList; @@ -28,41 +47,88 @@ class FakeResult implements Result private final List records; private int currentRecord = -1; - FakeResult() { - this(new ArrayList<>()); + FakeResult() + { + this( new ArrayList<>() ); } - FakeResult(List records) { + FakeResult( List records ) + { this.records = records; } + /** + * Supports fake parsing of very limited cypher statements, only for basic test purposes + */ + static FakeResult parseStatement( @Nonnull final String statement ) + { + + if ( isPing( statement ) ) + { + return PING_SUCCESS; + } + + Pattern returnAsPattern = Pattern.compile( "^return (.*) as (.*)$", Pattern.CASE_INSENSITIVE ); + Pattern returnPattern = Pattern.compile( "^return (.*)$", Pattern.CASE_INSENSITIVE ); + + // Be careful with order here + for ( Pattern p : Arrays.asList( returnAsPattern, returnPattern ) ) + { + Matcher m = p.matcher( statement ); + if ( m.find() ) + { + String value = m.group( 1 ); + String key = value; + if ( m.groupCount() > 1 ) + { + key = m.group( 2 ); + } + FakeResult statementResult = new FakeResult(); + statementResult.records.add( FakeRecord.of( key, value ) ); + return statementResult; + } + } + throw new IllegalArgumentException( "No idea how to parse this statement: " + statement ); + } + + private static boolean isPing( @Nonnull String statement ) + { + return statement.trim().equalsIgnoreCase( "CALL db.ping()" ); + } + @Override - public List keys() { - return records.stream().map(r -> r.keys().get(0)).collect(Collectors.toList()); + public List keys() + { + return records.stream().map( r -> r.keys().get( 0 ) ).collect( Collectors.toList() ); } @Override - public boolean hasNext() { + public boolean hasNext() + { return currentRecord + 1 < records.size(); } @Override - public Record next() { + public Record next() + { currentRecord += 1; - return records.get(currentRecord); + return records.get( currentRecord ); } @Override - public Record single() throws NoSuchRecordException { - if (records.size() == 1) { - return records.get(0); + public Record single() throws NoSuchRecordException + { + if ( records.size() == 1 ) + { + return records.get( 0 ); } - throw new NoSuchRecordException("There are more than records"); + throw new NoSuchRecordException( "There are more than records" ); } @Override - public Record peek() { - throw new Util.NotImplementedYetException("Not implemented yet"); + public Record peek() + { + throw new Util.NotImplementedYetException( "Not implemented yet" ); } @Override @@ -72,51 +138,20 @@ public Stream stream() } @Override - public List list() { + public List list() + { return records; } @Override - public List list(Function mapFunction) { - throw new Util.NotImplementedYetException("Not implemented yet"); + public List list( Function mapFunction ) + { + throw new Util.NotImplementedYetException( "Not implemented yet" ); } @Override - public ResultSummary consume() { - return new FakeResultSummary(); - } - - /** - * Supports fake parsing of very limited cypher statements, only for basic test purposes - */ - static FakeResult parseStatement(@Nonnull final String statement) { - - if ( isPing( statement ) ) { - return PING_SUCCESS; - } - - Pattern returnAsPattern = Pattern.compile("^return (.*) as (.*)$", Pattern.CASE_INSENSITIVE); - Pattern returnPattern = Pattern.compile("^return (.*)$", Pattern.CASE_INSENSITIVE); - - // Be careful with order here - for (Pattern p: Arrays.asList(returnAsPattern, returnPattern)) { - Matcher m = p.matcher(statement); - if (m.find()) { - String value = m.group(1); - String key = value; - if (m.groupCount() > 1) { - key = m.group(2); - } - FakeResult statementResult = new FakeResult(); - statementResult.records.add(FakeRecord.of(key, value)); - return statementResult; - } - } - throw new IllegalArgumentException("No idea how to parse this statement: " + statement); - } - - private static boolean isPing( @Nonnull String statement ) + public ResultSummary consume() { - return statement.trim().equalsIgnoreCase( "CALL db.ping()" ); + return new FakeResultSummary(); } } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/test/bolt/FakeResultSummary.java b/cypher-shell/src/test/java/org/neo4j/shell/test/bolt/FakeResultSummary.java index 6e89b3f4..2a3bea74 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/test/bolt/FakeResultSummary.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/test/bolt/FakeResultSummary.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.test.bolt; import java.util.List; @@ -18,54 +37,65 @@ /** * A fake result summary */ -class FakeResultSummary implements ResultSummary { +class FakeResultSummary implements ResultSummary +{ @Override - public Query query() { - throw new Util.NotImplementedYetException("Not implemented yet"); + public Query query() + { + throw new Util.NotImplementedYetException( "Not implemented yet" ); } @Override - public SummaryCounters counters() { + public SummaryCounters counters() + { return InternalSummaryCounters.EMPTY_STATS; } @Override - public QueryType queryType() { - throw new Util.NotImplementedYetException("Not implemented yet"); + public QueryType queryType() + { + throw new Util.NotImplementedYetException( "Not implemented yet" ); } @Override - public boolean hasPlan() { - throw new Util.NotImplementedYetException("Not implemented yet"); + public boolean hasPlan() + { + throw new Util.NotImplementedYetException( "Not implemented yet" ); } @Override - public boolean hasProfile() { - throw new Util.NotImplementedYetException("Not implemented yet"); + public boolean hasProfile() + { + throw new Util.NotImplementedYetException( "Not implemented yet" ); } @Override - public Plan plan() { - throw new Util.NotImplementedYetException("Not implemented yet"); + public Plan plan() + { + throw new Util.NotImplementedYetException( "Not implemented yet" ); } @Override - public ProfiledPlan profile() { - throw new Util.NotImplementedYetException("Not implemented yet"); + public ProfiledPlan profile() + { + throw new Util.NotImplementedYetException( "Not implemented yet" ); } @Override - public List notifications() { - throw new Util.NotImplementedYetException("Not implemented yet"); + public List notifications() + { + throw new Util.NotImplementedYetException( "Not implemented yet" ); } @Override - public long resultAvailableAfter(TimeUnit unit) { + public long resultAvailableAfter( TimeUnit unit ) + { return 0; } @Override - public long resultConsumedAfter(TimeUnit unit) { + public long resultConsumedAfter( TimeUnit unit ) + { return 0; } @@ -77,7 +107,7 @@ public ServerInfo server() @Override public String address() { - throw new Util.NotImplementedYetException("Not implemented yet"); + throw new Util.NotImplementedYetException( "Not implemented yet" ); } @Override diff --git a/cypher-shell/src/test/java/org/neo4j/shell/test/bolt/FakeSession.java b/cypher-shell/src/test/java/org/neo4j/shell/test/bolt/FakeSession.java index 3908044f..5f3b0116 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/test/bolt/FakeSession.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/test/bolt/FakeSession.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.test.bolt; import java.util.Map; @@ -15,95 +34,114 @@ /** * A fake session which returns fake StatementResults */ -public class FakeSession implements Session { +public class FakeSession implements Session +{ private boolean open = true; @Override - public Transaction beginTransaction() { + public Transaction beginTransaction() + { return new FakeTransaction(); } @Override - public Transaction beginTransaction(TransactionConfig config) { + public Transaction beginTransaction( TransactionConfig config ) + { return new FakeTransaction(); } @Override - public T readTransaction(TransactionWork work) { + public T readTransaction( TransactionWork work ) + { return null; } @Override - public T readTransaction(TransactionWork work, TransactionConfig config ) { + public T readTransaction( TransactionWork work, TransactionConfig config ) + { return null; } @Override - public T writeTransaction(TransactionWork work) { + public T writeTransaction( TransactionWork work ) + { return null; } @Override - public T writeTransaction(TransactionWork work, TransactionConfig config) { + public T writeTransaction( TransactionWork work, TransactionConfig config ) + { return null; } @Override - public Result run(String statement, TransactionConfig config) { - return FakeResult.parseStatement(statement); + public Result run( String statement, TransactionConfig config ) + { + return FakeResult.parseStatement( statement ); } @Override - public Result run(String statement, Map parameters, TransactionConfig config) { - return FakeResult.parseStatement(statement); + public Result run( String statement, Map parameters, TransactionConfig config ) + { + return FakeResult.parseStatement( statement ); } @Override - public Result run(Query statement, TransactionConfig config) { + public Result run( Query statement, TransactionConfig config ) + { return new FakeResult(); } @Override - public Bookmark lastBookmark() { + public Bookmark lastBookmark() + { return null; } @Override - public void reset() { + public void reset() + { } @Override - public boolean isOpen() { + public boolean isOpen() + { return open; } @Override - public void close() { + public void close() + { open = false; } @Override - public Result run(String statementTemplate, Value parameters) { - return FakeResult.parseStatement(statementTemplate); + public Result run( String statementTemplate, Value parameters ) + { + return FakeResult.parseStatement( statementTemplate ); } @Override - public Result run(String statementTemplate, Map statementParameters) { - return FakeResult.parseStatement(statementTemplate); + public Result run( String statementTemplate, Map statementParameters ) + { + return FakeResult.parseStatement( statementTemplate ); } @Override - public Result run(String statementTemplate, Record statementParameters) { - return FakeResult.parseStatement(statementTemplate); + public Result run( String statementTemplate, Record statementParameters ) + { + return FakeResult.parseStatement( statementTemplate ); } @Override - public Result run(String statementTemplate) { - return FakeResult.parseStatement(statementTemplate); + public Result run( String statementTemplate ) + { + return FakeResult.parseStatement( statementTemplate ); } @Override - public Result run(Query statement) { + public Result run( Query statement ) + { return new FakeResult(); } } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/test/bolt/FakeTransaction.java b/cypher-shell/src/test/java/org/neo4j/shell/test/bolt/FakeTransaction.java index 5caee34e..53f1b253 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/test/bolt/FakeTransaction.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/test/bolt/FakeTransaction.java @@ -1,56 +1,85 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.test.bolt; +import java.util.Map; + import org.neo4j.driver.Query; import org.neo4j.driver.Record; import org.neo4j.driver.Result; import org.neo4j.driver.Transaction; import org.neo4j.driver.Value; -import java.util.Map; - -public class FakeTransaction implements Transaction { +public class FakeTransaction implements Transaction +{ @Override - public void commit() { + public void commit() + { } @Override - public void rollback() { + public void rollback() + { } @Override - public boolean isOpen() { + public boolean isOpen() + { return true; } @Override - public void close() { + public void close() + { } @Override - public Result run(String query, Value parameters) { + public Result run( String query, Value parameters ) + { return null; } @Override - public Result run(String query, Map parameters) { + public Result run( String query, Map parameters ) + { return null; } @Override - public Result run(String query, Record parameters) { + public Result run( String query, Record parameters ) + { return null; } @Override - public Result run(String query) { + public Result run( String query ) + { return null; } @Override - public Result run(Query query) { + public Result run( Query query ) + { return null; } } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/test/bolt/FakeValue.java b/cypher-shell/src/test/java/org/neo4j/shell/test/bolt/FakeValue.java index b272bc92..2ef4fe84 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/test/bolt/FakeValue.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/test/bolt/FakeValue.java @@ -1,5 +1,34 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.test.bolt; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.OffsetDateTime; +import java.time.OffsetTime; +import java.time.ZonedDateTime; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + import org.neo4j.driver.Value; import org.neo4j.driver.exceptions.value.Uncoercible; import org.neo4j.driver.types.Entity; @@ -10,400 +39,465 @@ import org.neo4j.driver.types.Relationship; import org.neo4j.driver.types.Type; -import java.time.OffsetDateTime; -import java.time.ZonedDateTime; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.time.OffsetTime; -import java.util.List; -import java.util.Map; -import java.util.function.Function; - /** * A fake value */ -class FakeValue implements Value { +class FakeValue implements Value +{ @Override - public String toString() { + public String toString() + { return asString(); } @Override - public int size() { + public int size() + { return 0; } @Override - public Iterable values() { + public Iterable values() + { return null; } @Override - public Iterable values(Function mapFunction) { + public Iterable values( Function mapFunction ) + { return null; } @Override - public Map asMap() { + public Map asMap() + { return null; } @Override - public Map asMap(Function mapFunction) { - throw new Uncoercible(getClass().getSimpleName(), "Map"); + public Map asMap( Function mapFunction ) + { + throw new Uncoercible( getClass().getSimpleName(), "Map" ); } @Override - public boolean isEmpty() { + public boolean isEmpty() + { return false; } @Override - public Iterable keys() { + public Iterable keys() + { return null; } @Override - public boolean containsKey(String key) { + public boolean containsKey( String key ) + { return false; } @Override - public Value get(String key) { + public Value get( String key ) + { return null; } @Override - public Value get(int index) { + public Value get( int index ) + { return null; } @Override - public Type type() { + public Type type() + { return null; } @Override - public boolean hasType(Type type) { + public boolean hasType( Type type ) + { return false; } @Override - public boolean isTrue() { + public boolean isTrue() + { return false; } @Override - public boolean isFalse() { + public boolean isFalse() + { return false; } @Override - public boolean isNull() { + public boolean isNull() + { return false; } @Override - public Object asObject() { - throw new Uncoercible(getClass().getSimpleName(), "Object"); + public Object asObject() + { + throw new Uncoercible( getClass().getSimpleName(), "Object" ); } @Override - public T computeOrDefault(Function mapper, T defaultValue) { - throw new UnsupportedOperationException("No implementation"); + public T computeOrDefault( Function mapper, T defaultValue ) + { + throw new UnsupportedOperationException( "No implementation" ); } @Override - public boolean asBoolean() { - throw new Uncoercible(getClass().getSimpleName(), "Bool"); + public boolean asBoolean() + { + throw new Uncoercible( getClass().getSimpleName(), "Bool" ); } @Override - public boolean asBoolean(boolean defaultValue) { - throw new Uncoercible(getClass().getSimpleName(), "Bool"); + public boolean asBoolean( boolean defaultValue ) + { + throw new Uncoercible( getClass().getSimpleName(), "Bool" ); } @Override - public byte[] asByteArray() { - throw new Uncoercible(getClass().getSimpleName(), "Byte[]"); + public byte[] asByteArray() + { + throw new Uncoercible( getClass().getSimpleName(), "Byte[]" ); } @Override - public byte[] asByteArray(byte[] defaultValue) { - throw new Uncoercible(getClass().getSimpleName(), "Byte[]"); + public byte[] asByteArray( byte[] defaultValue ) + { + throw new Uncoercible( getClass().getSimpleName(), "Byte[]" ); } @Override - public String asString() { - throw new Uncoercible(getClass().getSimpleName(), "String"); + public String asString() + { + throw new Uncoercible( getClass().getSimpleName(), "String" ); } @Override - public String asString(String defaultValue) { - throw new Uncoercible(getClass().getSimpleName(), "String"); + public String asString( String defaultValue ) + { + throw new Uncoercible( getClass().getSimpleName(), "String" ); } @Override - public Number asNumber() { - throw new Uncoercible(getClass().getSimpleName(), "Number"); + public Number asNumber() + { + throw new Uncoercible( getClass().getSimpleName(), "Number" ); } @Override - public long asLong() { - throw new Uncoercible(getClass().getSimpleName(), "Long"); + public long asLong() + { + throw new Uncoercible( getClass().getSimpleName(), "Long" ); } @Override - public long asLong(long defaultValue) { - throw new Uncoercible(getClass().getSimpleName(), "Long"); + public long asLong( long defaultValue ) + { + throw new Uncoercible( getClass().getSimpleName(), "Long" ); } @Override - public int asInt() { - throw new Uncoercible(getClass().getSimpleName(), "Int"); + public int asInt() + { + throw new Uncoercible( getClass().getSimpleName(), "Int" ); } @Override - public int asInt(int defaultValue) { - throw new Uncoercible(getClass().getSimpleName(), "Int"); + public int asInt( int defaultValue ) + { + throw new Uncoercible( getClass().getSimpleName(), "Int" ); } @Override - public double asDouble() { - throw new Uncoercible(getClass().getSimpleName(), "Double"); + public double asDouble() + { + throw new Uncoercible( getClass().getSimpleName(), "Double" ); } @Override - public double asDouble(double defaultValue) { - throw new Uncoercible(getClass().getSimpleName(), "Double"); + public double asDouble( double defaultValue ) + { + throw new Uncoercible( getClass().getSimpleName(), "Double" ); } @Override - public float asFloat() { - throw new Uncoercible(getClass().getSimpleName(), "Float"); + public float asFloat() + { + throw new Uncoercible( getClass().getSimpleName(), "Float" ); } @Override - public float asFloat(float defaultValue) { - throw new Uncoercible(getClass().getSimpleName(), "Float"); + public float asFloat( float defaultValue ) + { + throw new Uncoercible( getClass().getSimpleName(), "Float" ); } @Override - public List asList() { - throw new Uncoercible(getClass().getSimpleName(), "List"); + public List asList() + { + throw new Uncoercible( getClass().getSimpleName(), "List" ); } @Override - public List asList(List defaultValue) { - throw new Uncoercible(getClass().getSimpleName(), "List"); + public List asList( List defaultValue ) + { + throw new Uncoercible( getClass().getSimpleName(), "List" ); } @Override - public List asList(Function mapFunction) { - throw new Uncoercible(getClass().getSimpleName(), "List"); + public List asList( Function mapFunction ) + { + throw new Uncoercible( getClass().getSimpleName(), "List" ); } @Override - public List asList(Function mapFunction, List defaultValue) { - throw new Uncoercible(getClass().getSimpleName(), "List"); + public List asList( Function mapFunction, List defaultValue ) + { + throw new Uncoercible( getClass().getSimpleName(), "List" ); } @Override - public Entity asEntity() { - throw new Uncoercible(getClass().getSimpleName(), "Entity"); + public Entity asEntity() + { + throw new Uncoercible( getClass().getSimpleName(), "Entity" ); } @Override - public Node asNode() { - throw new Uncoercible(getClass().getSimpleName(), "Node"); + public Node asNode() + { + throw new Uncoercible( getClass().getSimpleName(), "Node" ); } @Override - public Relationship asRelationship() { - throw new Uncoercible(getClass().getSimpleName(), "Relationship"); + public Relationship asRelationship() + { + throw new Uncoercible( getClass().getSimpleName(), "Relationship" ); } @Override - public Path asPath() { - throw new Uncoercible(getClass().getSimpleName(), "Path"); + public Path asPath() + { + throw new Uncoercible( getClass().getSimpleName(), "Path" ); } @Override - public LocalDate asLocalDate() { - throw new Uncoercible(getClass().getSimpleName(), "LocalDate"); + public LocalDate asLocalDate() + { + throw new Uncoercible( getClass().getSimpleName(), "LocalDate" ); } @Override - public OffsetTime asOffsetTime() { - throw new Uncoercible(getClass().getSimpleName(), "OffsetTime"); + public OffsetTime asOffsetTime() + { + throw new Uncoercible( getClass().getSimpleName(), "OffsetTime" ); } @Override - public LocalTime asLocalTime() { - throw new Uncoercible(getClass().getSimpleName(), "LocalTime"); + public LocalTime asLocalTime() + { + throw new Uncoercible( getClass().getSimpleName(), "LocalTime" ); } @Override - public LocalDateTime asLocalDateTime() { - throw new Uncoercible(getClass().getSimpleName(), "LocalDateTime"); + public LocalDateTime asLocalDateTime() + { + throw new Uncoercible( getClass().getSimpleName(), "LocalDateTime" ); } @Override public OffsetDateTime asOffsetDateTime() { - throw new Uncoercible(getClass().getSimpleName(), "OffsetDateTime"); + throw new Uncoercible( getClass().getSimpleName(), "OffsetDateTime" ); } @Override - public ZonedDateTime asZonedDateTime() { - throw new Uncoercible(getClass().getSimpleName(), "ZonedDateTime"); + public ZonedDateTime asZonedDateTime() + { + throw new Uncoercible( getClass().getSimpleName(), "ZonedDateTime" ); } @Override - public IsoDuration asIsoDuration() { - throw new Uncoercible(getClass().getSimpleName(), "IsoDuration"); + public IsoDuration asIsoDuration() + { + throw new Uncoercible( getClass().getSimpleName(), "IsoDuration" ); } @Override - public Point asPoint() { - throw new Uncoercible(getClass().getSimpleName(), "Point"); + public Point asPoint() + { + throw new Uncoercible( getClass().getSimpleName(), "Point" ); } @Override - public LocalDate asLocalDate(LocalDate defaultValue) { - throw new Uncoercible(getClass().getSimpleName(), "LocalDate"); + public LocalDate asLocalDate( LocalDate defaultValue ) + { + throw new Uncoercible( getClass().getSimpleName(), "LocalDate" ); } @Override - public OffsetTime asOffsetTime(OffsetTime defaultValue) { - throw new Uncoercible(getClass().getSimpleName(), "OffsetTime"); + public OffsetTime asOffsetTime( OffsetTime defaultValue ) + { + throw new Uncoercible( getClass().getSimpleName(), "OffsetTime" ); } @Override - public LocalTime asLocalTime(LocalTime defaultValue) { - throw new Uncoercible(getClass().getSimpleName(), "LocalTime"); + public LocalTime asLocalTime( LocalTime defaultValue ) + { + throw new Uncoercible( getClass().getSimpleName(), "LocalTime" ); } @Override - public LocalDateTime asLocalDateTime(LocalDateTime defaultValue) { - throw new Uncoercible(getClass().getSimpleName(), "LocalDateTime"); + public LocalDateTime asLocalDateTime( LocalDateTime defaultValue ) + { + throw new Uncoercible( getClass().getSimpleName(), "LocalDateTime" ); } @Override public OffsetDateTime asOffsetDateTime( OffsetDateTime defaultValue ) { - throw new Uncoercible(getClass().getSimpleName(), "OffsetDateTime"); + throw new Uncoercible( getClass().getSimpleName(), "OffsetDateTime" ); } @Override - public ZonedDateTime asZonedDateTime(ZonedDateTime defaultValue) { - throw new Uncoercible(getClass().getSimpleName(), "ZonedDateTime"); + public ZonedDateTime asZonedDateTime( ZonedDateTime defaultValue ) + { + throw new Uncoercible( getClass().getSimpleName(), "ZonedDateTime" ); } @Override - public IsoDuration asIsoDuration(IsoDuration defaultValue) { - throw new Uncoercible(getClass().getSimpleName(), "IsoDuration"); + public IsoDuration asIsoDuration( IsoDuration defaultValue ) + { + throw new Uncoercible( getClass().getSimpleName(), "IsoDuration" ); } @Override - public Point asPoint(Point defaultValue) { - throw new Uncoercible(getClass().getSimpleName(), "Point"); + public Point asPoint( Point defaultValue ) + { + throw new Uncoercible( getClass().getSimpleName(), "Point" ); } @Override - public Map asMap(Map defaultValue) { - throw new Uncoercible(getClass().getSimpleName(), "Map"); + public Map asMap( Map defaultValue ) + { + throw new Uncoercible( getClass().getSimpleName(), "Map" ); } @Override - public Map asMap(Function mapFunction, Map defaultValue) { - throw new Uncoercible(getClass().getSimpleName(), "Map"); + public Map asMap( Function mapFunction, Map defaultValue ) + { + throw new Uncoercible( getClass().getSimpleName(), "Map" ); } @Override - public Value get(String key, Value defaultValue) { + public Value get( String key, Value defaultValue ) + { return null; } @Override - public Object get(String key, Object defaultValue) { + public Object get( String key, Object defaultValue ) + { return null; } @Override - public Number get(String key, Number defaultValue) { + public Number get( String key, Number defaultValue ) + { return null; } @Override - public Entity get(String key, Entity defaultValue) { + public Entity get( String key, Entity defaultValue ) + { return null; } @Override - public Node get(String key, Node defaultValue) { + public Node get( String key, Node defaultValue ) + { return null; } @Override - public Path get(String key, Path defaultValue) { + public Path get( String key, Path defaultValue ) + { return null; } @Override - public Relationship get(String key, Relationship defaultValue) { + public Relationship get( String key, Relationship defaultValue ) + { return null; } @Override - public List get(String key, List defaultValue) { + public List get( String key, List defaultValue ) + { return null; } @Override - public List get(String key, List defaultValue, Function mapFunc) { + public List get( String key, List defaultValue, Function mapFunc ) + { return null; } @Override - public Map get(String key, Map defaultValue) { + public Map get( String key, Map defaultValue ) + { return null; } @Override - public Map get(String key, Map defaultValue, Function mapFunc) { + public Map get( String key, Map defaultValue, Function mapFunc ) + { return null; } @Override - public int get(String key, int defaultValue) { + public int get( String key, int defaultValue ) + { return 0; } @Override - public long get(String key, long defaultValue) { + public long get( String key, long defaultValue ) + { return 0; } @Override - public boolean get(String key, boolean defaultValue) { + public boolean get( String key, boolean defaultValue ) + { return false; } @Override - public String get(String key, String defaultValue) { + public String get( String key, String defaultValue ) + { return null; } @Override - public float get(String key, float defaultValue) { + public float get( String key, float defaultValue ) + { return 0; } @Override - public double get(String key, double defaultValue) { + public double get( String key, double defaultValue ) + { return 0; } } diff --git a/cypher-shell/src/test/java/org/neo4j/shell/util/VersionsTest.java b/cypher-shell/src/test/java/org/neo4j/shell/util/VersionsTest.java index 6463f64c..06fed2da 100644 --- a/cypher-shell/src/test/java/org/neo4j/shell/util/VersionsTest.java +++ b/cypher-shell/src/test/java/org/neo4j/shell/util/VersionsTest.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2002-2020 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.neo4j.shell.util; import org.junit.Test; @@ -7,28 +26,31 @@ public class VersionsTest { @Test - public void shouldWorkForEmptyString() throws Exception { - assertEquals(0, Versions.version("").compareTo(Versions.version("0.0.0"))); - assertEquals(0, Versions.majorVersion("")); - assertEquals(0, Versions.minorVersion("")); - assertEquals(0, Versions.patch("")); + public void shouldWorkForEmptyString() throws Exception + { + assertEquals( 0, Versions.version( "" ).compareTo( Versions.version( "0.0.0" ) ) ); + assertEquals( 0, Versions.majorVersion( "" ) ); + assertEquals( 0, Versions.minorVersion( "" ) ); + assertEquals( 0, Versions.patch( "" ) ); } @Test - public void shouldWorkForReleaseVersion() throws Exception { + public void shouldWorkForReleaseVersion() throws Exception + { String versionString = "3.4.5"; - assertEquals(0, Versions.version(versionString).compareTo(Versions.version("3.4.5"))); - assertEquals(3, Versions.majorVersion(versionString)); - assertEquals(4, Versions.minorVersion(versionString)); - assertEquals(5, Versions.patch(versionString)); + assertEquals( 0, Versions.version( versionString ).compareTo( Versions.version( "3.4.5" ) ) ); + assertEquals( 3, Versions.majorVersion( versionString ) ); + assertEquals( 4, Versions.minorVersion( versionString ) ); + assertEquals( 5, Versions.patch( versionString ) ); } @Test - public void shouldWorkForPreReleaseVersion() throws Exception { + public void shouldWorkForPreReleaseVersion() throws Exception + { String versionString = "3.4.55-beta99"; - assertEquals(0, Versions.version(versionString).compareTo(Versions.version("3.4.55"))); - assertEquals(3, Versions.majorVersion(versionString)); - assertEquals(4, Versions.minorVersion(versionString)); - assertEquals(55, Versions.patch(versionString)); + assertEquals( 0, Versions.version( versionString ).compareTo( Versions.version( "3.4.55" ) ) ); + assertEquals( 3, Versions.majorVersion( versionString ) ); + assertEquals( 4, Versions.minorVersion( versionString ) ); + assertEquals( 55, Versions.patch( versionString ) ); } } diff --git a/cypher-shell/src/test/resources/org/neo4j/shell/prettyprint/expected-pretty-print-plan-information.txt b/cypher-shell/src/test/resources/org/neo4j/shell/prettyprint/expected-pretty-print-plan-information.txt new file mode 100644 index 00000000..7b907c06 --- /dev/null +++ b/cypher-shell/src/test/resources/org/neo4j/shell/prettyprint/expected-pretty-print-plan-information.txt @@ -0,0 +1,14 @@ ++-----------------------------------------------------------------------------------------------------+ +| Plan | Statement | Version | Planner | Runtime | Time | DbHits | Rows | Memory (Bytes) | ++-----------------------------------------------------------------------------------------------------+ +| "PROFILE" | "READ_ONLY" | "3.1" | "COST" | "INTERPRETED" | 12 | 1000 | 20 | 10 | ++-----------------------------------------------------------------------------------------------------+ + + ++----------+----------------+------+---------+-----------+-----------+----------------+-------------+------------+----------------------------+ +| Operator | Estimated Rows | Rows | DB Hits | Cache H/M | Time (ms) | Memory (Bytes) | Identifiers | Ordered by | Other | ++----------+----------------+------+---------+-----------+-----------+----------------+-------------+------------+----------------------------+ +| +MyOp | 10 | 3 | 2 | 22/2 | 0.000 | 5 | a, b | a | 15; INTERPRETED; 3.1; COST | ++----------+----------------+------+---------+-----------+-----------+----------------+-------------+------------+----------------------------+ + +0 rows available after 5 ms, consumed after another 7 ms \ No newline at end of file