Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ object ApplicationEntry {
val commandRegistry = CommandRegistry()
commandRegistry.register("cat", CatCommand())
commandRegistry.register("pwd", PrintWorkingDirectoryCommand())
commandRegistry.register("cd", ChangeDirectoryCommand())
commandRegistry.register("cd", CdCommand())
commandRegistry.register("ls", LsCommand())
commandRegistry.register("echo", EchoCommand())
commandRegistry.register("wc", WcCommand())
commandRegistry.register("exit", ExitCommand())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import java.io.OutputStream
import kotlin.io.path.exists
import kotlin.io.path.isDirectory


/**
* Change working directory command.
*
Expand All @@ -20,22 +21,24 @@ import kotlin.io.path.isDirectory
* 2. Passed path is not found
* 3. Passed path is not a directory
*
* @author sibmaks
* @author mk17ru
* @since 0.0.1
*/
class ChangeDirectoryCommand : Command {
class CdCommand : Command {
private val HOME_DIR = System.getProperty("user.home");

override fun execute(
@Nonnull environment: Environment,
@Nonnull inputStream: InputStream,
@Nonnull outputStream: OutputStream,
@Nonnull errorStream: OutputStream,
@Nonnull arguments: List<String>
): CommandResult {
if (arguments.size != 1) {
errorStream.writeLineUTF8("Change directory command except expect 1 argument")
if (arguments.size > 1) {
errorStream.writeLineUTF8("Change directory command except <= 1 argument")
return ErrorResult(1)
}
val move = arguments[0]
val move = if (arguments.isEmpty()) HOME_DIR else arguments[0]
val newWorkingDirectory = environment.workingDirectory
.resolve(move)
.normalize()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.github.itmosoftwaredesign.cli.command.impl

import com.github.itmosoftwaredesign.cli.Environment
import com.github.itmosoftwaredesign.cli.command.Command
import com.github.itmosoftwaredesign.cli.command.CommandResult
import com.github.itmosoftwaredesign.cli.command.ErrorResult
import com.github.itmosoftwaredesign.cli.command.SuccessResult
import com.github.itmosoftwaredesign.cli.writeLineUTF8
import jakarta.annotation.Nonnull
import java.io.File
import java.io.InputStream
import java.io.OutputStream
import kotlin.io.path.exists
import kotlin.io.path.isDirectory
import kotlin.io.path.listDirectoryEntries
import kotlin.io.path.name

private const val CURRENT_DIR = "."

/**
* `LsCommand` - команда для отображения содержимого каталога.
*
* Если аргументы отсутствуют, выводится содержимое текущего рабочего каталога.
* Если указан каталог в аргументах, выводится его содержимое.
*
* @author mk17ru
* @since 0.0.3
*/
class LsCommand : Command {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Не уверен, нужна ли обработка флагов команды? -l, -b, -c…
Если нет, то все отлично.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

По заданию кажется не обязательным, а так согласен, всё отлично.

override fun execute(
@Nonnull environment: Environment,
@Nonnull inputStream: InputStream,
@Nonnull outputStream: OutputStream,
@Nonnull errorStream: OutputStream,
@Nonnull arguments: List<String>
): CommandResult {
val move = if (arguments.isEmpty()) CURRENT_DIR else arguments[0]
val directory = environment.workingDirectory
.resolve(move)
.normalize()
.toAbsolutePath()
if (!directory.exists()) {
errorStream.writeLineUTF8("Directory '$directory' does not exist")
return ErrorResult(2)
}
if (!directory.isDirectory()) {
outputStream.writeLineUTF8(directory.name)
return SuccessResult()
}
try {
val files = directory.listDirectoryEntries()
files.sortedBy { it.name }.forEach { file ->
outputStream.writeLineUTF8(file.name)
}
} catch (e : Exception) {
errorStream.writeLineUTF8("ls: cannot read directory '${directory.toAbsolutePath()}'")
return ErrorResult(4)
}
return SuccessResult()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,86 @@ class InterpreterTest {
}
}

@Test
fun `should execute several cd ls`() {
val cdCommandMock = mockk<Command>(relaxed = true)
val lsCommandMock = mockk<Command>(relaxed = true)
val cdParsedCommand = mockk<ParsedCommand>(relaxed = true)
val lsParsedCommand = mockk<ParsedCommand>(relaxed = true)
val parsedCommands = listOf(cdParsedCommand, lsParsedCommand)
val cdCommandTokens = listOf("cd", "..")
val lsCommandTokens = listOf("ls")

inputStream = ByteArrayInputStream("cd .. | ls\nexit\n".toByteArray())
every { cdParsedCommand.commandTokens } returns cdCommandTokens
every { lsParsedCommand.commandTokens } returns lsCommandTokens
every { commandsParser.parse("cd .. | ls") } returns parsedCommands
every { commandRegistry["cd"] } returns cdCommandMock
every { commandRegistry["ls"] } returns lsCommandMock
every { cdCommandMock.execute(any(), any(), any(), any(), any()) } returns SuccessResult()

interpreter = Interpreter(environment, commandsParser, commandRegistry, inputStream)
interpreter.run()

verify {
cdCommandMock.execute(
environment,
parsedCommands.first().inputStream,
parsedCommands.first().outputStream,
parsedCommands.first().errorStream,
listOf("..")
)

lsCommandMock.execute(
environment,
parsedCommands.last().inputStream,
parsedCommands.last().outputStream,
parsedCommands.last().errorStream,
listOf()
)
}
}

@Test
fun `should execute several cd git status`() {
val cdCommandMock = mockk<Command>(relaxed = true)
val lsCommandMock = mockk<Command>(relaxed = true)
val cdParsedCommand = mockk<ParsedCommand>(relaxed = true)
val lsParsedCommand = mockk<ParsedCommand>(relaxed = true)
val parsedCommands = listOf(cdParsedCommand, lsParsedCommand)
val cdCommandTokens = listOf("cd", "..")
val lsCommandTokens = listOf("git", "status")

inputStream = ByteArrayInputStream("cd .. | git status\nexit\n".toByteArray())
every { cdParsedCommand.commandTokens } returns cdCommandTokens
every { lsParsedCommand.commandTokens } returns lsCommandTokens
every { commandsParser.parse("cd .. | git status") } returns parsedCommands
every { commandRegistry["cd"] } returns cdCommandMock
every { commandRegistry["git"] } returns lsCommandMock
every { cdCommandMock.execute(any(), any(), any(), any(), any()) } returns SuccessResult()

interpreter = Interpreter(environment, commandsParser, commandRegistry, inputStream)
interpreter.run()

verify {
cdCommandMock.execute(
environment,
parsedCommands.first().inputStream,
parsedCommands.first().outputStream,
parsedCommands.first().errorStream,
listOf("..")
)

lsCommandMock.execute(
environment,
parsedCommands.last().inputStream,
parsedCommands.last().outputStream,
parsedCommands.last().errorStream,
listOf("status")
)
}
}

@Test
fun `should run external process on unknown command`() {
inputStream = ByteArrayInputStream("ls\n".toByteArray())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,19 @@ import java.util.*
import kotlin.io.path.createDirectory
import kotlin.io.path.createFile

class ChangeDirectoryCommandTest {
class CdCommandTest {

private lateinit var environment: Environment
private lateinit var changeDirectoryCommand: ChangeDirectoryCommand
private lateinit var changeDirectoryCommand: CdCommand
private lateinit var outputStream: ByteArrayOutputStream
private lateinit var errorStream: ByteArrayOutputStream
private val HOME_DIR = System.getProperty("user.home");


@BeforeEach
fun setUp() {
environment = mockk(relaxed = true)
changeDirectoryCommand = ChangeDirectoryCommand()
changeDirectoryCommand = CdCommand()
outputStream = ByteArrayOutputStream()
errorStream = ByteArrayOutputStream()
}
Expand Down Expand Up @@ -69,18 +71,49 @@ class ChangeDirectoryCommandTest {
}

@Test
fun `should write error when no arguments provided`() {
changeDirectoryCommand.execute(environment, System.`in`, outputStream, errorStream, emptyList())
fun `should change upper directory when not directory provided`() {
val currentDir = Files.createTempDirectory("current")

val errorMessage = "Change directory command except expect 1 argument"
assertEquals(errorMessage, errorStream.toString().trim())
every { environment.workingDirectory } returns currentDir.toAbsolutePath()

changeDirectoryCommand.execute(environment, System.`in`, outputStream, errorStream, listOf())

verify { environment.workingDirectory = Path.of(HOME_DIR) }
}

@Test
fun `should change upper two dirs`() {
val currentDir = Files.createTempDirectory("current")

val parentSecond = currentDir.parent.parent

every { environment.workingDirectory } returns currentDir.toAbsolutePath()

changeDirectoryCommand.execute(environment, System.`in`, outputStream, errorStream, listOf("../.."))

verify { environment.workingDirectory = parentSecond }
}

@Test
fun `should change upper directory when two points provided`() {
val currentDir = Files.createTempDirectory("current")

every { environment.workingDirectory } returns currentDir.toAbsolutePath()

val parent = currentDir.parent

changeDirectoryCommand.execute(environment, System.`in`, outputStream, errorStream, listOf(".."))

verify { environment.workingDirectory = parent }
}

@Test
fun `should write error when too many arguments provided`() {
changeDirectoryCommand.execute(environment, System.`in`, outputStream, errorStream, listOf("dir1", "dir2"))

val errorMessage = "Change directory command except expect 1 argument"
val errorMessage = "Change directory command except <= 1 argument"
assertEquals(errorMessage, errorStream.toString().trim())
}


}
Loading