From 4564633257c442212024d2d42805dd61503beab1 Mon Sep 17 00:00:00 2001 From: vasyoid Date: Sat, 16 Feb 2019 14:44:54 +0300 Subject: [PATCH 1/8] Fix issues with outer commands and cat --- .../hse/nedikov/bash/logic/commands/Cat.kt | 2 +- .../bash/logic/commands/OuterCommand.kt | 19 +++++-------------- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/Cat.kt b/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/Cat.kt index f117f99..77b455b 100644 --- a/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/Cat.kt +++ b/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/Cat.kt @@ -22,7 +22,7 @@ class Cat(private val arguments: ArrayList) : Command() { override fun execute(output: PipedWriter) { for (arg in arguments) { try { - FileReader(arg).forEachLine { output.write(arg) } + FileReader(arg).forEachLine { output.write(it + System.lineSeparator()) } } catch (e: Exception) { output.write("cat: ${e.message}") } diff --git a/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/OuterCommand.kt b/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/OuterCommand.kt index ec44fd5..b4620bc 100644 --- a/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/OuterCommand.kt +++ b/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/OuterCommand.kt @@ -22,7 +22,7 @@ class OuterCommand(private val name: String, private val arguments: ArrayList output.write("$s\n") } - val errorGobbler = StreamGobbler(process.errorStream) { s -> output.write("$s\n") } - val executor = Executors.newSingleThreadExecutor() - executor.submit(streamGobbler) - executor.submit(errorGobbler) - process.waitFor(10, TimeUnit.SECONDS) + process.inputStream.bufferedReader().copyTo(output) + process.errorStream.bufferedReader().copyTo(output) + process.waitFor() } override fun execute(output: PipedWriter) { @@ -46,17 +43,11 @@ class OuterCommand(private val name: String, private val arguments: ArrayList arguments.forEach { joiner.add(it) } }.toString() return Runtime.getRuntime().exec("$environmentStart $command") } - private class StreamGobbler(private val inputStream: InputStream, private val consumer: (String) -> Unit) : Runnable { - override fun run() { - BufferedReader(InputStreamReader(inputStream)).lines().forEach(consumer) - } - } - companion object { val isWindows = System.getProperty("os.name").toLowerCase().startsWith("windows") } From b9d811ee3cb99a36d78893e9c00b4f4657f419cc Mon Sep 17 00:00:00 2001 From: vasyoid Date: Sat, 16 Feb 2019 18:12:17 +0300 Subject: [PATCH 2/8] Implement cd command --- .../kotlin/hse/nedikov/bash/Environment.kt | 26 +++++++++++++++ .../kotlin/hse/nedikov/bash/logic/Command.kt | 11 ++++--- .../hse/nedikov/bash/logic/commands/Cat.kt | 7 ++-- .../hse/nedikov/bash/logic/commands/Cd.kt | 32 +++++++++++++++++++ .../hse/nedikov/bash/logic/commands/Grep.kt | 16 ++++++---- .../bash/logic/commands/OuterCommand.kt | 13 ++++---- .../hse/nedikov/bash/logic/commands/Pwd.kt | 7 ++-- .../nedikov/bash/logic/commands/WordCount.kt | 7 ++-- 8 files changed, 91 insertions(+), 28 deletions(-) create mode 100644 bash/src/main/kotlin/hse/nedikov/bash/logic/commands/Cd.kt diff --git a/bash/src/main/kotlin/hse/nedikov/bash/Environment.kt b/bash/src/main/kotlin/hse/nedikov/bash/Environment.kt index 7176d9c..298e985 100644 --- a/bash/src/main/kotlin/hse/nedikov/bash/Environment.kt +++ b/bash/src/main/kotlin/hse/nedikov/bash/Environment.kt @@ -1,6 +1,7 @@ package hse.nedikov.bash import hse.nedikov.bash.Environment.State.* +import java.io.File /** * Environment of the interpreter @@ -12,6 +13,7 @@ class Environment { private val varMap = HashMap() private var state: State = Working + private var workingDirectory = File("./") /** * Map of the local variables @@ -38,4 +40,28 @@ class Environment { * Returns true iff interpreter is still working */ fun isWorking(): Boolean = state == Working + + fun changeDirectory(newPath: String): Boolean { + val newDirectory = getCanonicalFile(newPath) + if (newDirectory.isDirectory) { + workingDirectory = newDirectory + } + return newDirectory.isDirectory + } + + fun getCanonicalPath(path: String): String { + return getCanonicalFile(path).canonicalPath + } + + fun getCanonicalFile(path: String): File { + return if (isAbsolutePath(path)) { + File(path) + } else { + File(workingDirectory, path) + } + } + + private fun isAbsolutePath(path: String): Boolean { + return File.listRoots().fold(false) { res, file -> res || path.startsWith(file.canonicalPath) } + } } \ No newline at end of file diff --git a/bash/src/main/kotlin/hse/nedikov/bash/logic/Command.kt b/bash/src/main/kotlin/hse/nedikov/bash/logic/Command.kt index 8954b4f..8fd0942 100644 --- a/bash/src/main/kotlin/hse/nedikov/bash/logic/Command.kt +++ b/bash/src/main/kotlin/hse/nedikov/bash/logic/Command.kt @@ -47,12 +47,13 @@ abstract class Command { } return when (name) { "echo" -> Echo(args) - "wc" -> WordCount(args) - "pwd" -> Pwd() + "wc" -> WordCount(args, env) + "pwd" -> Pwd(env) "exit" -> Exit(env) - "cat" -> Cat(args) - "grep" -> Grep(args) - else -> OuterCommand(name, args) + "cat" -> Cat(args, env) + "grep" -> Grep(args, env) + "cd" -> Cd(args, env) + else -> OuterCommand(name, args, env) } } } diff --git a/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/Cat.kt b/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/Cat.kt index 77b455b..8ec1833 100644 --- a/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/Cat.kt +++ b/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/Cat.kt @@ -1,13 +1,14 @@ package hse.nedikov.bash.logic.commands -import hse.nedikov.bash.logic.Command +import hse.nedikov.bash.Environment +import hse.nedikov.bash.logic.EnvironmentCommand import java.io.* import java.lang.Exception /** * cat command which prints files entries to the output stream */ -class Cat(private val arguments: ArrayList) : Command() { +class Cat(private val arguments: ArrayList, override val env: Environment) : EnvironmentCommand(env) { /** * Prints input to the output if has no arguments and prints entries of files from arguments otherwise */ @@ -22,7 +23,7 @@ class Cat(private val arguments: ArrayList) : Command() { override fun execute(output: PipedWriter) { for (arg in arguments) { try { - FileReader(arg).forEachLine { output.write(it + System.lineSeparator()) } + FileReader(env.getCanonicalPath(arg)).forEachLine { output.write(it + System.lineSeparator()) } } catch (e: Exception) { output.write("cat: ${e.message}") } diff --git a/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/Cd.kt b/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/Cd.kt new file mode 100644 index 0000000..11607a8 --- /dev/null +++ b/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/Cd.kt @@ -0,0 +1,32 @@ +package hse.nedikov.bash.logic.commands + +import hse.nedikov.bash.Environment +import hse.nedikov.bash.logic.Command +import java.io.PipedReader +import java.io.PipedWriter + +/** + * cd command which changes the working directory + */ +class Cd(private val arguments: ArrayList, private val env: Environment) : Command() { + /** + * Changes the working directory + */ + override fun execute(input: PipedReader, output: PipedWriter) { + return execute(output) + } + + /** + * Changes the working directory + */ + override fun execute(output: PipedWriter) { + if (arguments.size > 1) { + output.write("cd: too many arguments") + return + } + if (!env.changeDirectory(arguments.getOrElse(0) { "./" })) { + output.write("cd: directory not found") + return + } + } +} \ No newline at end of file diff --git a/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/Grep.kt b/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/Grep.kt index 6cc6ade..3983751 100644 --- a/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/Grep.kt +++ b/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/Grep.kt @@ -3,7 +3,8 @@ package hse.nedikov.bash.logic.commands import com.xenomachina.argparser.ArgParser import com.xenomachina.argparser.ShowHelpException import com.xenomachina.argparser.default -import hse.nedikov.bash.logic.Command +import hse.nedikov.bash.Environment +import hse.nedikov.bash.logic.EnvironmentCommand import java.io.* import java.lang.IllegalArgumentException import java.util.ArrayList @@ -11,7 +12,7 @@ import java.util.ArrayList /** * grep command which prints all lines with pattern matched substring */ -class Grep(private val arguments: ArrayList) : Command() { +class Grep(private val arguments: ArrayList, override val env: Environment) : EnvironmentCommand(env) { /** * Takes lines for grep from input */ @@ -25,7 +26,8 @@ class Grep(private val arguments: ArrayList) : Command() { */ override fun execute(output: PipedWriter) { val args = parseArguments(::GrepArgs, output) ?: return - grep(args.file, output, args) + val input = FileReader(env.getCanonicalPath(args.file)) + grep(input, output, args) } private fun parseArguments(constructor: (ArgParser) -> T, output: Writer): T? { @@ -35,11 +37,11 @@ class Grep(private val arguments: ArrayList) : Command() { } catch (e: ShowHelpException) { println(e.printUserMessage(output, "grep", 80)) } - return null; + return null } private fun grep(input: Reader, output: PipedWriter, args: PipedGrepArgs) { - var linesToWrite = 0; + var linesToWrite = 0 input.forEachLine { val matchString = if (args.ignoreCase) it.toLowerCase() else it val matchPattern = if (args.ignoreCase) args.pattern.toLowerCase() else args.pattern @@ -47,7 +49,7 @@ class Grep(private val arguments: ArrayList) : Command() { val regex = Regex(".*?$wordEnd$matchPattern$wordEnd.*") if (matchString.matches(regex)) { output.write("$it\n") - linesToWrite = args.afterContext; + linesToWrite = args.afterContext } else if (linesToWrite > 0) { output.write("$it\n") linesToWrite-- @@ -67,5 +69,5 @@ private open class PipedGrepArgs(parser: ArgParser) { } private class GrepArgs(parser: ArgParser) : PipedGrepArgs(parser) { - val file by parser.positional("FILE") { FileReader(this) } + val file by parser.positional("FILE") { this } } \ No newline at end of file diff --git a/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/OuterCommand.kt b/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/OuterCommand.kt index b4620bc..3442a16 100644 --- a/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/OuterCommand.kt +++ b/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/OuterCommand.kt @@ -1,18 +1,17 @@ package hse.nedikov.bash.logic.commands -import hse.nedikov.bash.logic.Command +import hse.nedikov.bash.Environment +import hse.nedikov.bash.logic.EnvironmentCommand import java.io.* -import java.util.concurrent.Executors -import java.io.InputStreamReader -import java.io.BufferedReader import java.util.* -import java.util.concurrent.TimeUnit /** * Class for calling commands in outer interpreter * @param name name of the command */ -class OuterCommand(private val name: String, private val arguments: ArrayList) : Command() { +class OuterCommand(private val name: String, + private val arguments: ArrayList, + override val env: Environment) : EnvironmentCommand(env) { /** * Calls the command in outer interpreter and print theirs output or error to the output * in case when the command is executed in less than 10 seconds @@ -45,7 +44,7 @@ class OuterCommand(private val name: String, private val arguments: ArrayList arguments.forEach { joiner.add(it) } }.toString() - return Runtime.getRuntime().exec("$environmentStart $command") + return Runtime.getRuntime().exec("$environmentStart $command", null, env.getCanonicalFile("./")) } companion object { diff --git a/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/Pwd.kt b/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/Pwd.kt index 3084c17..cbd7c29 100644 --- a/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/Pwd.kt +++ b/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/Pwd.kt @@ -1,12 +1,13 @@ package hse.nedikov.bash.logic.commands -import hse.nedikov.bash.logic.Command +import hse.nedikov.bash.Environment +import hse.nedikov.bash.logic.EnvironmentCommand import java.io.* /** * pwd command which prints current working directory */ -class Pwd : Command() { +class Pwd(override val env: Environment) : EnvironmentCommand(env) { /** * Prints current working directory to the output */ @@ -19,7 +20,7 @@ class Pwd : Command() { * Prints current working directory to the output */ override fun execute(output: PipedWriter) { - output.write(System.getProperty("user.dir") + "\n") + output.write(env.getCanonicalPath("./") + System.lineSeparator()) } } \ No newline at end of file diff --git a/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/WordCount.kt b/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/WordCount.kt index a51069f..66c0da1 100644 --- a/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/WordCount.kt +++ b/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/WordCount.kt @@ -1,13 +1,14 @@ package hse.nedikov.bash.logic.commands -import hse.nedikov.bash.logic.Command +import hse.nedikov.bash.Environment +import hse.nedikov.bash.logic.EnvironmentCommand import java.io.* import java.lang.Exception /** * wc command which calculates count of lines, words and bytes in files or input */ -class WordCount(private val arguments: ArrayList) : Command() { +class WordCount(private val arguments: ArrayList, override val env: Environment) : EnvironmentCommand(env) { /** * Calculates count of lines, words and bytes in input if arguments is empty and in files otherwise */ @@ -27,7 +28,7 @@ class WordCount(private val arguments: ArrayList) : Command() { val result = WCResult() for (arg in arguments) { try { - val r = calcInput(FileReader(arg)) + val r = calcInput(FileReader(env.getCanonicalPath(arg))) output.write("${r.lines} ${r.words} ${r.bytes} $arg\n") } catch (e: Exception) { output.write("wc: ${e.message}\n") From 3109e3b2587606bc7bd3ab4ae36d50a170f8faa7 Mon Sep 17 00:00:00 2001 From: vasyoid Date: Sat, 16 Feb 2019 18:42:00 +0300 Subject: [PATCH 3/8] Implement ls command --- .../kotlin/hse/nedikov/bash/Environment.kt | 4 +- .../kotlin/hse/nedikov/bash/logic/Command.kt | 1 + .../hse/nedikov/bash/logic/commands/Ls.kt | 38 +++++++++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 bash/src/main/kotlin/hse/nedikov/bash/logic/commands/Ls.kt diff --git a/bash/src/main/kotlin/hse/nedikov/bash/Environment.kt b/bash/src/main/kotlin/hse/nedikov/bash/Environment.kt index 298e985..9a0d354 100644 --- a/bash/src/main/kotlin/hse/nedikov/bash/Environment.kt +++ b/bash/src/main/kotlin/hse/nedikov/bash/Environment.kt @@ -55,9 +55,9 @@ class Environment { fun getCanonicalFile(path: String): File { return if (isAbsolutePath(path)) { - File(path) + File(path).canonicalFile } else { - File(workingDirectory, path) + File(workingDirectory, path).canonicalFile } } diff --git a/bash/src/main/kotlin/hse/nedikov/bash/logic/Command.kt b/bash/src/main/kotlin/hse/nedikov/bash/logic/Command.kt index 8fd0942..7af92d7 100644 --- a/bash/src/main/kotlin/hse/nedikov/bash/logic/Command.kt +++ b/bash/src/main/kotlin/hse/nedikov/bash/logic/Command.kt @@ -53,6 +53,7 @@ abstract class Command { "cat" -> Cat(args, env) "grep" -> Grep(args, env) "cd" -> Cd(args, env) + "ls" -> Ls(args, env) else -> OuterCommand(name, args, env) } } diff --git a/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/Ls.kt b/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/Ls.kt new file mode 100644 index 0000000..7caad08 --- /dev/null +++ b/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/Ls.kt @@ -0,0 +1,38 @@ +package hse.nedikov.bash.logic.commands + +import hse.nedikov.bash.Environment +import hse.nedikov.bash.logic.Command +import java.io.File +import java.io.PipedReader +import java.io.PipedWriter + +/** + * ls command which prints all files in current directory + */ +class Ls(private val arguments: ArrayList, private val env: Environment) : Command() { + /** + * Prints current directory + */ + override fun execute(input: PipedReader, output: PipedWriter) { + return execute(output) + } + + /** + * Prints current directory + */ + override fun execute(output: PipedWriter) { + if (arguments.size > 1) { + output.write("ls: too many arguments") + return + } + printFile(env.getCanonicalFile(arguments.getOrElse(0) { "./" }), output) + } + + private fun printFile(file: File, output: PipedWriter) { + when { + file.isFile -> output.write(file.name + System.lineSeparator()) + file.isDirectory -> file.listFiles().forEach { output.write(it.name + System.lineSeparator()) } + else -> output.write("ls: file or directory not found" + System.lineSeparator()) + } + } +} \ No newline at end of file From 74ed798fcb3ebd727aafd791343fb9c528aea18b Mon Sep 17 00:00:00 2001 From: vasyoid Date: Sat, 16 Feb 2019 18:45:32 +0300 Subject: [PATCH 4/8] Refactor command tests --- .../bash/logic/commands/CommandsTest.kt | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/bash/src/test/kotlin/hse/nedikov/bash/logic/commands/CommandsTest.kt b/bash/src/test/kotlin/hse/nedikov/bash/logic/commands/CommandsTest.kt index 0723522..6fe28b9 100644 --- a/bash/src/test/kotlin/hse/nedikov/bash/logic/commands/CommandsTest.kt +++ b/bash/src/test/kotlin/hse/nedikov/bash/logic/commands/CommandsTest.kt @@ -1,5 +1,6 @@ package hse.nedikov.bash.logic.commands +import hse.nedikov.bash.Environment import org.junit.Test import java.io.PipedReader import java.io.PipedWriter @@ -35,31 +36,31 @@ class CommandsTest { @Test fun catInputStream() { - val reader = Cat(list()).execute(readerFromString("kekes leles")) + val reader = Cat(list(), Environment()).execute(readerFromString("kekes leles")) assertEquals("kekes leles", stringFromReader(reader)) } @Test fun pwdSimple() { - val reader = Pwd().execute() + val reader = Pwd(Environment()).execute() assertTrue(stringFromReader(reader).isNotEmpty()) } @Test fun pwdSimpleWithInputStream() { - val reader = Pwd().execute(readerFromString("kekes leles")) + val reader = Pwd(Environment()).execute(readerFromString("kekes leles")) assertTrue(stringFromReader(reader).isNotEmpty()) } @Test fun wordCountSimple() { - val reader = WordCount(list()).execute(readerFromString("lol kek cheburek")) + val reader = WordCount(list(), Environment()).execute(readerFromString("lol kek cheburek")) assertEquals("1 3 16", stringFromReader(reader)) } @Test fun grepTest() { - val reader = Grep(list("lol")).execute(readerFromString(keklolString)) + val reader = Grep(list("lol"), Environment()).execute(readerFromString(keklolString)) assertEquals(""" lol kek kek lol @@ -71,7 +72,7 @@ class CommandsTest { @Test fun grepWordRegexpTest() { - val reader = Grep(list("lol", "-w")).execute(readerFromString(keklolString)) + val reader = Grep(list("lol", "-w"), Environment()).execute(readerFromString(keklolString)) assertEquals(""" lol kek kek lol @@ -81,7 +82,7 @@ class CommandsTest { @Test fun grepIgnoreCaseTest() { - val reader = Grep(list("LoL", "-i")).execute(readerFromString(keklolString)) + val reader = Grep(list("LoL", "-i"), Environment()).execute(readerFromString(keklolString)) assertEquals(""" lol kek kek lol @@ -94,9 +95,9 @@ class CommandsTest { @Test fun grepAfterContextTest() { - var reader = Grep(list("lol", "-A", "5")).execute(readerFromString(keklolString)) + var reader = Grep(list("lol", "-A", "5"), Environment()).execute(readerFromString(keklolString)) assertEquals(keklolString, stringFromReader(reader)) - reader = Grep(list("lol", "-A", "1")).execute(readerFromString(keklolString)) + reader = Grep(list("lol", "-A", "1"), Environment()).execute(readerFromString(keklolString)) assertEquals(""" lol kek kek lol From 11e9aaa180eb2865d2f7832ffdc961bb08c54abb Mon Sep 17 00:00:00 2001 From: vasyoid Date: Sat, 16 Feb 2019 19:19:03 +0300 Subject: [PATCH 5/8] Add tests --- .../bash/logic/commands/CommandsTest.kt | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/bash/src/test/kotlin/hse/nedikov/bash/logic/commands/CommandsTest.kt b/bash/src/test/kotlin/hse/nedikov/bash/logic/commands/CommandsTest.kt index 6fe28b9..701c372 100644 --- a/bash/src/test/kotlin/hse/nedikov/bash/logic/commands/CommandsTest.kt +++ b/bash/src/test/kotlin/hse/nedikov/bash/logic/commands/CommandsTest.kt @@ -8,8 +8,92 @@ import java.util.* import hse.nedikov.bash.list import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue +import org.junit.Rule +import org.junit.rules.TemporaryFolder +import java.io.File class CommandsTest { + + @Rule + @JvmField + val tmpFolder = TemporaryFolder() + + @Test + fun lsNoArgumentsTest() { + tmpFolder.newFile("file") + tmpFolder.newFile("oneMoreFile") + tmpFolder.newFolder("folder") + tmpFolder.newFolder("oneMoreFolder") + val env = Environment() + env.changeDirectory(tmpFolder.root.canonicalPath) + val reader = Ls(list(), env).execute() + assertEquals(""" + folder + oneMoreFile + oneMoreFolder + file + """.trimIndent(), stringFromReader(reader)) + tmpFolder.delete() + } + + @Test + fun lsOneArgumentTest() { + tmpFolder.newFolder("folder", "oneMoreFolder") + tmpFolder.newFile("folder/file") + tmpFolder.newFile("folder/oneMoreFile") + val env = Environment() + env.changeDirectory(tmpFolder.root.canonicalPath) + val reader = Ls(list("folder"), env).execute() + assertEquals(""" + oneMoreFile + oneMoreFolder + file + """.trimIndent(), stringFromReader(reader)) + tmpFolder.delete() + } + + @Test + fun lsFileTest() { + tmpFolder.newFile("file") + val env = Environment() + env.changeDirectory(tmpFolder.root.canonicalPath) + val reader = Ls(list("file"), env).execute() + assertEquals("file", stringFromReader(reader)) + tmpFolder.delete() + } + + @Test + fun cdAndThenLsTest() { + tmpFolder.newFolder("folder", "oneMoreFolder") + val env = Environment() + Cd(list(tmpFolder.root.canonicalPath), env).execute() + val reader = Ls(list("folder"), env).execute() + assertEquals("oneMoreFolder", stringFromReader(reader)) + tmpFolder.delete() + } + + @Test + fun cdRelativePathTest() { + val env = Environment() + Cd(list("../"), env).execute() + assertEquals(File("../").canonicalPath, env.getCanonicalPath("./")) + } + + @Test + fun cdAbsoluteTest() { + val env = Environment() + Cd(list(File("../").canonicalPath), env).execute() + assertEquals(File("../").canonicalPath, env.getCanonicalPath("./")) + } + + @Test + fun cdAndThenPwdTest() { + val env = Environment() + Cd(list("../"), env).execute() + val reader = Pwd(env).execute() + assertEquals(File("../").canonicalPath, stringFromReader(reader)) + } + @Test fun echoSimple() { val reader = Echo(list("lol")).execute() From 0d151191e81b3faa703f36e930433b355c9989ec Mon Sep 17 00:00:00 2001 From: vasyoid Date: Sat, 16 Feb 2019 19:28:24 +0300 Subject: [PATCH 6/8] Fix ls ordering --- bash/src/main/kotlin/hse/nedikov/bash/logic/commands/Ls.kt | 2 +- .../kotlin/hse/nedikov/bash/logic/commands/CommandsTest.kt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/Ls.kt b/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/Ls.kt index 7caad08..02bf2bd 100644 --- a/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/Ls.kt +++ b/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/Ls.kt @@ -31,7 +31,7 @@ class Ls(private val arguments: ArrayList, private val env: Environment) private fun printFile(file: File, output: PipedWriter) { when { file.isFile -> output.write(file.name + System.lineSeparator()) - file.isDirectory -> file.listFiles().forEach { output.write(it.name + System.lineSeparator()) } + file.isDirectory -> file.listFiles().sorted().forEach { output.write(it.name + System.lineSeparator()) } else -> output.write("ls: file or directory not found" + System.lineSeparator()) } } diff --git a/bash/src/test/kotlin/hse/nedikov/bash/logic/commands/CommandsTest.kt b/bash/src/test/kotlin/hse/nedikov/bash/logic/commands/CommandsTest.kt index 701c372..b4e38cf 100644 --- a/bash/src/test/kotlin/hse/nedikov/bash/logic/commands/CommandsTest.kt +++ b/bash/src/test/kotlin/hse/nedikov/bash/logic/commands/CommandsTest.kt @@ -28,10 +28,10 @@ class CommandsTest { env.changeDirectory(tmpFolder.root.canonicalPath) val reader = Ls(list(), env).execute() assertEquals(""" + file folder oneMoreFile oneMoreFolder - file """.trimIndent(), stringFromReader(reader)) tmpFolder.delete() } @@ -45,9 +45,9 @@ class CommandsTest { env.changeDirectory(tmpFolder.root.canonicalPath) val reader = Ls(list("folder"), env).execute() assertEquals(""" + file oneMoreFile oneMoreFolder - file """.trimIndent(), stringFromReader(reader)) tmpFolder.delete() } From f3089285d862a3cce92bdc758264f5110b415798 Mon Sep 17 00:00:00 2001 From: vasyoid Date: Tue, 19 Feb 2019 20:44:30 +0300 Subject: [PATCH 7/8] Fix review issues --- .../kotlin/hse/nedikov/bash/Environment.kt | 10 +--------- .../hse/nedikov/bash/logic/commands/Cd.kt | 11 +++++------ .../bash/logic/commands/CommandsTest.kt | 18 ++++++++++++++++++ 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/bash/src/main/kotlin/hse/nedikov/bash/Environment.kt b/bash/src/main/kotlin/hse/nedikov/bash/Environment.kt index 9a0d354..89cb3b8 100644 --- a/bash/src/main/kotlin/hse/nedikov/bash/Environment.kt +++ b/bash/src/main/kotlin/hse/nedikov/bash/Environment.kt @@ -54,14 +54,6 @@ class Environment { } fun getCanonicalFile(path: String): File { - return if (isAbsolutePath(path)) { - File(path).canonicalFile - } else { - File(workingDirectory, path).canonicalFile - } - } - - private fun isAbsolutePath(path: String): Boolean { - return File.listRoots().fold(false) { res, file -> res || path.startsWith(file.canonicalPath) } + return workingDirectory.resolve(path) } } \ No newline at end of file diff --git a/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/Cd.kt b/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/Cd.kt index 11607a8..8b2606e 100644 --- a/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/Cd.kt +++ b/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/Cd.kt @@ -4,6 +4,7 @@ import hse.nedikov.bash.Environment import hse.nedikov.bash.logic.Command import java.io.PipedReader import java.io.PipedWriter +import java.lang.RuntimeException /** * cd command which changes the working directory @@ -13,7 +14,7 @@ class Cd(private val arguments: ArrayList, private val env: Environment) * Changes the working directory */ override fun execute(input: PipedReader, output: PipedWriter) { - return execute(output) + return execute(output) } /** @@ -21,12 +22,10 @@ class Cd(private val arguments: ArrayList, private val env: Environment) */ override fun execute(output: PipedWriter) { if (arguments.size > 1) { - output.write("cd: too many arguments") - return + throw RuntimeException("cd: too many arguments") } - if (!env.changeDirectory(arguments.getOrElse(0) { "./" })) { - output.write("cd: directory not found") - return + if (!env.changeDirectory(arguments.getOrElse(0) { System.getProperty("user.home") })) { + throw RuntimeException("cd: directory not found") } } } \ No newline at end of file diff --git a/bash/src/test/kotlin/hse/nedikov/bash/logic/commands/CommandsTest.kt b/bash/src/test/kotlin/hse/nedikov/bash/logic/commands/CommandsTest.kt index b4e38cf..59765cd 100644 --- a/bash/src/test/kotlin/hse/nedikov/bash/logic/commands/CommandsTest.kt +++ b/bash/src/test/kotlin/hse/nedikov/bash/logic/commands/CommandsTest.kt @@ -62,6 +62,24 @@ class CommandsTest { tmpFolder.delete() } + @Test(expected = RuntimeException::class) + fun cdTooManyArgumentsTest() { + Cd(list("arg1", "arg2"), Environment()).execute() + } + + @Test + fun cdNoArgumentsTest() { + val env = Environment() + Cd(list(), env).execute() + assertEquals(System.getProperty("user.home"), env.getCanonicalPath("./")) + } + + + @Test(expected = RuntimeException::class) + fun cdDirectoryNotFoundTest() { + Cd(list("baddirectoryyyyyy"), Environment()).execute() + } + @Test fun cdAndThenLsTest() { tmpFolder.newFolder("folder", "oneMoreFolder") From e002fc08364053f5e96aa122c0f39c288f944c08 Mon Sep 17 00:00:00 2001 From: vasyoid Date: Sat, 23 Mar 2019 22:35:59 +0300 Subject: [PATCH 8/8] Add throw exceptions in Ls class --- .../kotlin/hse/nedikov/bash/logic/commands/Ls.kt | 5 ++--- .../hse/nedikov/bash/logic/commands/CommandsTest.kt | 12 +++++++++++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/Ls.kt b/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/Ls.kt index 02bf2bd..b728e76 100644 --- a/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/Ls.kt +++ b/bash/src/main/kotlin/hse/nedikov/bash/logic/commands/Ls.kt @@ -22,8 +22,7 @@ class Ls(private val arguments: ArrayList, private val env: Environment) */ override fun execute(output: PipedWriter) { if (arguments.size > 1) { - output.write("ls: too many arguments") - return + throw RuntimeException("ls: too many arguments") } printFile(env.getCanonicalFile(arguments.getOrElse(0) { "./" }), output) } @@ -32,7 +31,7 @@ class Ls(private val arguments: ArrayList, private val env: Environment) when { file.isFile -> output.write(file.name + System.lineSeparator()) file.isDirectory -> file.listFiles().sorted().forEach { output.write(it.name + System.lineSeparator()) } - else -> output.write("ls: file or directory not found" + System.lineSeparator()) + else -> throw RuntimeException("ls: file or directory not found" + System.lineSeparator()) } } } \ No newline at end of file diff --git a/bash/src/test/kotlin/hse/nedikov/bash/logic/commands/CommandsTest.kt b/bash/src/test/kotlin/hse/nedikov/bash/logic/commands/CommandsTest.kt index 59765cd..0963e74 100644 --- a/bash/src/test/kotlin/hse/nedikov/bash/logic/commands/CommandsTest.kt +++ b/bash/src/test/kotlin/hse/nedikov/bash/logic/commands/CommandsTest.kt @@ -18,6 +18,16 @@ class CommandsTest { @JvmField val tmpFolder = TemporaryFolder() + @Test(expected = RuntimeException::class) + fun lsTooManyArgumentsTest() { + Ls(list("arg1", "arg2"), Environment()).execute() + } + + @Test(expected = RuntimeException::class) + fun lsDirectoryNotFoundTest() { + Ls(list("baddirectoryyyyyy"), Environment()).execute() + } + @Test fun lsNoArgumentsTest() { tmpFolder.newFile("file") @@ -75,7 +85,7 @@ class CommandsTest { } - @Test(expected = RuntimeException::class) + @Test(expected = RuntimeException::class) fun cdDirectoryNotFoundTest() { Cd(list("baddirectoryyyyyy"), Environment()).execute() }