-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #59 from aivanovski/feature/add-xwayland-compatibi…
…lity Add XWayland compatibility
- Loading branch information
Showing
7 changed files
with
261 additions
and
3 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
110 changes: 110 additions & 0 deletions
110
src/main/java/com/github/ai/autokpass/domain/usecases/DetermineDesktopUseCase.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
package com.github.ai.autokpass.domain.usecases | ||
|
||
import com.github.ai.autokpass.model.DesktopType | ||
import com.github.ai.autokpass.model.Result | ||
import com.github.ai.autokpass.presentation.process.ProcessExecutor | ||
import com.github.ai.autokpass.util.StringUtils.NEW_LINE | ||
|
||
class DetermineDesktopUseCase( | ||
private val processExecutor: ProcessExecutor | ||
) { | ||
|
||
fun getDesktopType(): Result<DesktopType> { | ||
val environmentOutputResult = processExecutor.execute(COMMAND) | ||
if (environmentOutputResult.isFailed()) { | ||
return environmentOutputResult.asErrorOrThrow() | ||
} | ||
|
||
val environment = environmentOutputResult.getDataOrThrow() | ||
.parseEnvironmentOutput() | ||
|
||
return Result.Success(classifyDesktopEnvironment(environment)) | ||
} | ||
|
||
private fun String.parseEnvironmentOutput(): Map<String, String> { | ||
return this.split(NEW_LINE) | ||
.map { line -> line.trim() } | ||
.filter { line -> line.isNotEmpty() && line.contains("=") } | ||
.mapNotNull { line -> | ||
val values = line.split("=") | ||
if (values.size == 2) { | ||
values[0] to values[1] | ||
} else { | ||
null | ||
} | ||
} | ||
.toMap() | ||
} | ||
|
||
private fun classifyDesktopEnvironment( | ||
environment: Map<String, String> | ||
): DesktopType { | ||
val typeByXdgSession = classifyByXdgSessionTypeVariable(environment) | ||
if (typeByXdgSession != null) { | ||
return typeByXdgSession | ||
} | ||
|
||
val typeByDesktopSession = classifyByDesktopSessionVariable(environment) | ||
if (typeByDesktopSession != null) { | ||
return typeByDesktopSession | ||
} | ||
|
||
return classifyByOthers(environment) | ||
} | ||
|
||
private fun classifyByXdgSessionTypeVariable( | ||
environment: Map<String, String> | ||
): DesktopType? { | ||
val xdgSessionType = environment[XDG_SESSION_TYPE] ?: return null | ||
|
||
for (type in TYPES) { | ||
if (xdgSessionType.contains(type.key, ignoreCase = true)) { | ||
return type.value | ||
} | ||
} | ||
|
||
return null | ||
} | ||
|
||
private fun classifyByDesktopSessionVariable( | ||
environment: Map<String, String> | ||
): DesktopType? { | ||
val desktopSession = environment[DESKTOP_SESSION] ?: return null | ||
|
||
for (type in TYPES) { | ||
if (desktopSession.contains(type.key, ignoreCase = true)) { | ||
return type.value | ||
} | ||
} | ||
|
||
return null | ||
} | ||
|
||
private fun classifyByOthers( | ||
environment: Map<String, String> | ||
): DesktopType { | ||
val isWayland = environment.any { (_, value) -> | ||
value.contains(WAYLAND, ignoreCase = true) | ||
} | ||
|
||
return if (isWayland) { | ||
DesktopType.WAYLAND | ||
} else { | ||
DesktopType.XORG | ||
} | ||
} | ||
|
||
companion object { | ||
const val COMMAND = "env" | ||
private const val WAYLAND = "wayland" | ||
|
||
private val TYPES = mapOf( | ||
"wayland" to DesktopType.WAYLAND, | ||
"x11" to DesktopType.XORG, | ||
"xorg" to DesktopType.XORG | ||
) | ||
|
||
const val XDG_SESSION_TYPE = "XDG_SESSION_TYPE" | ||
const val DESKTOP_SESSION = "DESKTOP_SESSION" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package com.github.ai.autokpass.model | ||
|
||
enum class DesktopType { | ||
XORG, | ||
WAYLAND | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
109 changes: 109 additions & 0 deletions
109
src/test/java/com/github/ai/autokpass/domain/usecases/DetermineDesktopUseCaseTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
package com.github.ai.autokpass.domain.usecases | ||
|
||
import com.github.ai.autokpass.TestData.EXCEPTION | ||
import com.github.ai.autokpass.domain.usecases.DetermineDesktopUseCase.Companion.COMMAND | ||
import com.github.ai.autokpass.domain.usecases.DetermineDesktopUseCase.Companion.DESKTOP_SESSION | ||
import com.github.ai.autokpass.domain.usecases.DetermineDesktopUseCase.Companion.XDG_SESSION_TYPE | ||
import com.github.ai.autokpass.model.DesktopType | ||
import com.github.ai.autokpass.model.DesktopType.WAYLAND | ||
import com.github.ai.autokpass.model.DesktopType.XORG | ||
import com.github.ai.autokpass.model.Result | ||
import com.github.ai.autokpass.presentation.process.MockProcessExecutor | ||
import com.github.ai.autokpass.util.StringUtils.EMPTY | ||
import io.kotest.matchers.shouldBe | ||
import org.junit.jupiter.api.Test | ||
|
||
class DetermineDesktopUseCaseTest { | ||
|
||
@Test | ||
fun `should return error if unable to execute env command`() { | ||
// arrange | ||
val processExecutor = MockProcessExecutor( | ||
data = mapOf( | ||
COMMAND to Result.Error(EXCEPTION) | ||
) | ||
) | ||
|
||
// act | ||
val result = DetermineDesktopUseCase(processExecutor).getDesktopType() | ||
|
||
// assert | ||
result shouldBe Result.Error(EXCEPTION) | ||
} | ||
|
||
@Test | ||
fun `should classify by environment variables`() { | ||
assertUseCase( | ||
data = listOf( | ||
"$XDG_SESSION_TYPE=wayland-session" to Result.Success(WAYLAND), | ||
"$XDG_SESSION_TYPE=x11-session" to Result.Success(XORG), | ||
"$XDG_SESSION_TYPE=xorg-session" to Result.Success(XORG), | ||
|
||
"$DESKTOP_SESSION=wayland-session" to Result.Success(WAYLAND), | ||
"$DESKTOP_SESSION=x11-session-x11" to Result.Success(XORG), | ||
"$DESKTOP_SESSION=xorg-session" to Result.Success(XORG), | ||
|
||
"ENVIRONMENT_VARIABLE=wayland-session" to Result.Success(WAYLAND) | ||
) | ||
) | ||
} | ||
|
||
@Test | ||
fun `should return xorg if unable to classify by environment variables`() { | ||
assertUseCase( | ||
data = listOf( | ||
"$XDG_SESSION_TYPE=invalid" to Result.Success(XORG), | ||
"$DESKTOP_SESSION=invalid" to Result.Success(XORG) | ||
) | ||
) | ||
} | ||
|
||
@Test | ||
fun `should return xorg type if nothing is specified`() { | ||
assertUseCase( | ||
data = listOf(EMPTY to Result.Success(XORG)) | ||
) | ||
} | ||
|
||
@Test | ||
fun `should ignore invalid lines`() { | ||
assertUseCase( | ||
data = listOf( | ||
""" | ||
$XDG_SESSION_TYPE=x11=invalid | ||
$DESKTOP_SESSION=wayland | ||
""".trimIndent() to Result.Success(WAYLAND), | ||
|
||
""" | ||
$XDG_SESSION_TYPE=wayland=invalid | ||
$DESKTOP_SESSION=x11 | ||
""".trimIndent() to Result.Success(XORG), | ||
|
||
""" | ||
WAYLAND | ||
$DESKTOP_SESSION=x11 | ||
""".trimIndent() to Result.Success(XORG) | ||
) | ||
) | ||
} | ||
|
||
private fun assertUseCase( | ||
data: List<Pair<String, Result<DesktopType>>> | ||
) { | ||
data.forEach { (input, expected) -> | ||
val processExecutor = MockProcessExecutor( | ||
data = mapOf( | ||
COMMAND to Result.Success(input) | ||
) | ||
) | ||
|
||
// act | ||
val result = DetermineDesktopUseCase( | ||
processExecutor = processExecutor | ||
).getDesktopType() | ||
|
||
// assert | ||
result shouldBe expected | ||
} | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
src/test/java/com/github/ai/autokpass/presentation/process/MockProcessExecutor.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package com.github.ai.autokpass.presentation.process | ||
|
||
import com.github.ai.autokpass.model.Result | ||
|
||
class MockProcessExecutor( | ||
private val data: Map<String, Result<String>> | ||
) : ProcessExecutor { | ||
|
||
override fun execute(command: String): Result<String> { | ||
return data[command] | ||
?: throw IllegalArgumentException("Unable to find data for command: $command") | ||
} | ||
|
||
override fun executeWithBash(command: String): Result<String> { | ||
throw NotImplementedError() | ||
} | ||
|
||
override fun execute(input: ByteArray, command: String): Result<String> { | ||
throw NotImplementedError() | ||
} | ||
} |