Merge pull request #25 from posix4e/tests
Browse files- puppet/app/build.gradle +13 -5
- puppet/app/src/androidTest/java/com/ttt246/puppet/MyAccessibilityServiceTest.kt +0 -31
- puppet/app/src/main/java/com/ttt246/puppet/ChatterAct.kt +0 -1
- puppet/app/src/main/java/com/ttt246/puppet/PuppetAS.kt +33 -38
- puppet/app/src/test/java/com/ttt246/puppet/PuppetASTest.kt +44 -0
- puppet/app/src/test/java/com/ttt246/puppet/SumTest.kt +0 -17
- puppet/app/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker +1 -0
puppet/app/build.gradle
CHANGED
|
@@ -1,4 +1,3 @@
|
|
| 1 |
-
|
| 2 |
plugins {
|
| 3 |
id 'com.android.application'
|
| 4 |
id 'org.jetbrains.kotlin.android'
|
|
@@ -16,10 +15,17 @@ android {
|
|
| 16 |
}
|
| 17 |
defaultConfig {
|
| 18 |
applicationId "com.ttt246.puppet"
|
| 19 |
-
minSdkVersion
|
| 20 |
versionCode 1
|
| 21 |
versionName "1.0"
|
| 22 |
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
}
|
| 24 |
|
| 25 |
buildTypes {
|
|
@@ -35,13 +41,15 @@ android {
|
|
| 35 |
}
|
| 36 |
}
|
| 37 |
|
| 38 |
-
|
| 39 |
dependencies {
|
| 40 |
implementation 'androidx.appcompat:appcompat:1.6.1'
|
| 41 |
implementation 'com.google.android.material:material:1.9.0'
|
| 42 |
-
implementation 'com.eclipsesource.j2v8:j2v8:6.2.1@aar'
|
| 43 |
implementation 'androidx.core:core-ktx:1.10.1'
|
|
|
|
| 44 |
testImplementation 'junit:junit:4.13.2'
|
| 45 |
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
|
| 46 |
-
|
|
|
|
|
|
|
|
|
|
| 47 |
}
|
|
|
|
|
|
|
| 1 |
plugins {
|
| 2 |
id 'com.android.application'
|
| 3 |
id 'org.jetbrains.kotlin.android'
|
|
|
|
| 15 |
}
|
| 16 |
defaultConfig {
|
| 17 |
applicationId "com.ttt246.puppet"
|
| 18 |
+
minSdkVersion 30
|
| 19 |
versionCode 1
|
| 20 |
versionName "1.0"
|
| 21 |
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
| 22 |
+
|
| 23 |
+
// Enable unit tests to run off the device using the JVM.
|
| 24 |
+
testOptions {
|
| 25 |
+
unitTests {
|
| 26 |
+
includeAndroidResources = true
|
| 27 |
+
}
|
| 28 |
+
}
|
| 29 |
}
|
| 30 |
|
| 31 |
buildTypes {
|
|
|
|
| 41 |
}
|
| 42 |
}
|
| 43 |
|
|
|
|
| 44 |
dependencies {
|
| 45 |
implementation 'androidx.appcompat:appcompat:1.6.1'
|
| 46 |
implementation 'com.google.android.material:material:1.9.0'
|
|
|
|
| 47 |
implementation 'androidx.core:core-ktx:1.10.1'
|
| 48 |
+
implementation 'androidx.test:core-ktx:1.5.0'
|
| 49 |
testImplementation 'junit:junit:4.13.2'
|
| 50 |
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
|
| 51 |
+
|
| 52 |
+
// Add Robolectric and Mockito dependencies for unit testing.
|
| 53 |
+
testImplementation 'org.robolectric:robolectric:4.7.2'
|
| 54 |
+
testImplementation 'org.mockito:mockito-core:4.1.0'
|
| 55 |
}
|
puppet/app/src/androidTest/java/com/ttt246/puppet/MyAccessibilityServiceTest.kt
CHANGED
|
@@ -1,31 +0,0 @@
|
|
| 1 |
-
package com.ttt246.puppet
|
| 2 |
-
|
| 3 |
-
import android.content.pm.PackageManager
|
| 4 |
-
import android.util.Log
|
| 5 |
-
import androidx.test.ext.junit.rules.ActivityScenarioRule
|
| 6 |
-
import androidx.test.ext.junit.runners.AndroidJUnit4
|
| 7 |
-
import androidx.test.platform.app.InstrumentationRegistry
|
| 8 |
-
import org.junit.Rule
|
| 9 |
-
import org.junit.Test
|
| 10 |
-
import org.junit.runner.RunWith
|
| 11 |
-
|
| 12 |
-
@RunWith(AndroidJUnit4::class)
|
| 13 |
-
class MyAccessibilityServiceTest {
|
| 14 |
-
@get:Rule
|
| 15 |
-
var rule: ActivityScenarioRule<ChatterAct> = ActivityScenarioRule(ChatterAct::class.java)
|
| 16 |
-
|
| 17 |
-
private val context = InstrumentationRegistry.getInstrumentation().targetContext
|
| 18 |
-
|
| 19 |
-
@Test
|
| 20 |
-
fun testHandleEvent() {
|
| 21 |
-
val myService = PuppetAS()
|
| 22 |
-
val packageManager = context.packageManager
|
| 23 |
-
|
| 24 |
-
val applications = packageManager.getInstalledApplications(PackageManager.GET_META_DATA)
|
| 25 |
-
for (applicationInfo in applications) {
|
| 26 |
-
val packageName = applicationInfo.packageName
|
| 27 |
-
val appName = packageManager.getApplicationLabel(applicationInfo).toString()
|
| 28 |
-
Log.d("AppList", "App: $appName, Package: $packageName")
|
| 29 |
-
}
|
| 30 |
-
}
|
| 31 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
puppet/app/src/main/java/com/ttt246/puppet/ChatterAct.kt
CHANGED
|
@@ -8,7 +8,6 @@ import android.provider.Settings
|
|
| 8 |
import android.webkit.WebView
|
| 9 |
import android.widget.Button
|
| 10 |
import androidx.appcompat.app.AppCompatActivity
|
| 11 |
-
import com.eclipsesource.v8.V8
|
| 12 |
|
| 13 |
class ChatterAct : AppCompatActivity() {
|
| 14 |
private lateinit var webView: WebView
|
|
|
|
| 8 |
import android.webkit.WebView
|
| 9 |
import android.widget.Button
|
| 10 |
import androidx.appcompat.app.AppCompatActivity
|
|
|
|
| 11 |
|
| 12 |
class ChatterAct : AppCompatActivity() {
|
| 13 |
private lateinit var webView: WebView
|
puppet/app/src/main/java/com/ttt246/puppet/PuppetAS.kt
CHANGED
|
@@ -20,7 +20,7 @@ import java.util.LinkedList
|
|
| 20 |
import java.util.Queue
|
| 21 |
|
| 22 |
|
| 23 |
-
class PuppetAS : AccessibilityService() {
|
| 24 |
private fun getServerUrl(): String =
|
| 25 |
PreferenceManager.getDefaultSharedPreferences(this).getString("SERVER_URL", "") ?: ""
|
| 26 |
|
|
@@ -42,27 +42,27 @@ class PuppetAS : AccessibilityService() {
|
|
| 42 |
Thread {
|
| 43 |
while (true) {
|
| 44 |
val uid = getUUID()
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
} finally {
|
| 51 |
-
logs.clear()
|
| 52 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 53 |
}
|
| 54 |
-
Thread.sleep((1000..3000).random().toLong())
|
| 55 |
}
|
| 56 |
}.start()
|
| 57 |
}
|
| 58 |
|
| 59 |
-
private fun heartbeat(
|
| 60 |
val serverUrl = getServerUrl()
|
| 61 |
val url = URL("$serverUrl/send_event")
|
| 62 |
-
|
| 63 |
-
put("uid", uid)
|
| 64 |
-
put("event", logMessage)
|
| 65 |
-
}
|
| 66 |
|
| 67 |
val conn = url.openConnection() as HttpURLConnection
|
| 68 |
conn.requestMethod = "POST"
|
|
@@ -101,7 +101,7 @@ class PuppetAS : AccessibilityService() {
|
|
| 101 |
}
|
| 102 |
}
|
| 103 |
|
| 104 |
-
|
| 105 |
commands.forEach { command ->
|
| 106 |
when {
|
| 107 |
isIntentCommand(command) -> executeIntentCommand(command)
|
|
@@ -111,15 +111,15 @@ class PuppetAS : AccessibilityService() {
|
|
| 111 |
}
|
| 112 |
}
|
| 113 |
|
| 114 |
-
|
| 115 |
return command.startsWith("intent:")
|
| 116 |
}
|
| 117 |
|
| 118 |
-
|
| 119 |
return command.startsWith("acc:")
|
| 120 |
}
|
| 121 |
|
| 122 |
-
|
| 123 |
val accCommand = command.removePrefix("acc:")
|
| 124 |
Log.i("PuppetAS", "Executing Acc command: $accCommand")
|
| 125 |
|
|
@@ -136,8 +136,8 @@ class PuppetAS : AccessibilityService() {
|
|
| 136 |
}
|
| 137 |
|
| 138 |
accCommand.startsWith("TYPE") -> {
|
| 139 |
-
if (accCommand
|
| 140 |
-
val text = "
|
| 141 |
val arguments = Bundle()
|
| 142 |
arguments.putCharSequence(
|
| 143 |
AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text
|
|
@@ -145,10 +145,16 @@ class PuppetAS : AccessibilityService() {
|
|
| 145 |
getFirstTypeableNode()?.performAction(
|
| 146 |
AccessibilityNodeInfo.ACTION_SET_TEXT, arguments
|
| 147 |
)
|
| 148 |
-
} else {
|
| 149 |
-
val
|
| 150 |
-
val text = accCommand.substringAfter("
|
| 151 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 152 |
}
|
| 153 |
}
|
| 154 |
}
|
|
@@ -227,25 +233,14 @@ class PuppetAS : AccessibilityService() {
|
|
| 227 |
|
| 228 |
private fun clickView(id: String) {
|
| 229 |
val rootNode = rootInActiveWindow ?: return
|
| 230 |
-
val nodes = rootNode.
|
| 231 |
-
nodes.forEach {
|
| 232 |
-
it.performAction(AccessibilityNodeInfo.ACTION_CLICK)
|
| 233 |
-
}
|
| 234 |
-
}
|
| 235 |
|
| 236 |
-
private fun typeInView(id: String, text: String) {
|
| 237 |
-
val rootNode = rootInActiveWindow ?: return
|
| 238 |
-
val nodes = rootNode.findAccessibilityNodeInfosByViewId(id)
|
| 239 |
nodes.forEach {
|
| 240 |
-
|
| 241 |
-
arguments.putCharSequence(
|
| 242 |
-
AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text
|
| 243 |
-
)
|
| 244 |
-
it.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments)
|
| 245 |
}
|
| 246 |
}
|
| 247 |
|
| 248 |
-
|
| 249 |
val intentCommand = command.removePrefix("intent:")
|
| 250 |
|
| 251 |
Log.i("PuppetAS", "Executing Intent command: $intentCommand")
|
|
|
|
| 20 |
import java.util.Queue
|
| 21 |
|
| 22 |
|
| 23 |
+
open class PuppetAS : AccessibilityService() {
|
| 24 |
private fun getServerUrl(): String =
|
| 25 |
PreferenceManager.getDefaultSharedPreferences(this).getString("SERVER_URL", "") ?: ""
|
| 26 |
|
|
|
|
| 42 |
Thread {
|
| 43 |
while (true) {
|
| 44 |
val uid = getUUID()
|
| 45 |
+
try {
|
| 46 |
+
val logMessage = logs.joinToString()
|
| 47 |
+
val jsonObject = JSONObject().apply {
|
| 48 |
+
put("uid", uid)
|
| 49 |
+
put("event", logMessage)
|
|
|
|
|
|
|
| 50 |
}
|
| 51 |
+
heartbeat(jsonObject)
|
| 52 |
+
} catch (e: Exception) {
|
| 53 |
+
Log.e("PuppetAS", "Error in sending POST request: ${e.message}")
|
| 54 |
+
} finally {
|
| 55 |
+
logs.clear()
|
| 56 |
+
Thread.sleep((1000..3000).random().toLong())
|
| 57 |
}
|
|
|
|
| 58 |
}
|
| 59 |
}.start()
|
| 60 |
}
|
| 61 |
|
| 62 |
+
private fun heartbeat(jsonObject: JSONObject) {
|
| 63 |
val serverUrl = getServerUrl()
|
| 64 |
val url = URL("$serverUrl/send_event")
|
| 65 |
+
|
|
|
|
|
|
|
|
|
|
| 66 |
|
| 67 |
val conn = url.openConnection() as HttpURLConnection
|
| 68 |
conn.requestMethod = "POST"
|
|
|
|
| 101 |
}
|
| 102 |
}
|
| 103 |
|
| 104 |
+
fun processCommands(commands: List<String>) {
|
| 105 |
commands.forEach { command ->
|
| 106 |
when {
|
| 107 |
isIntentCommand(command) -> executeIntentCommand(command)
|
|
|
|
| 111 |
}
|
| 112 |
}
|
| 113 |
|
| 114 |
+
fun isIntentCommand(command: String): Boolean {
|
| 115 |
return command.startsWith("intent:")
|
| 116 |
}
|
| 117 |
|
| 118 |
+
fun isAccCommand(command: String): Boolean {
|
| 119 |
return command.startsWith("acc:")
|
| 120 |
}
|
| 121 |
|
| 122 |
+
fun executeAccCommand(command: String) {
|
| 123 |
val accCommand = command.removePrefix("acc:")
|
| 124 |
Log.i("PuppetAS", "Executing Acc command: $accCommand")
|
| 125 |
|
|
|
|
| 136 |
}
|
| 137 |
|
| 138 |
accCommand.startsWith("TYPE") -> {
|
| 139 |
+
if (accCommand.startsWith("TYPE FIRST ")) {
|
| 140 |
+
val text = accCommand.substringAfter("TYPE FIRST ")
|
| 141 |
val arguments = Bundle()
|
| 142 |
arguments.putCharSequence(
|
| 143 |
AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text
|
|
|
|
| 145 |
getFirstTypeableNode()?.performAction(
|
| 146 |
AccessibilityNodeInfo.ACTION_SET_TEXT, arguments
|
| 147 |
)
|
| 148 |
+
} else if (accCommand.startsWith("TYPE HERE")) {
|
| 149 |
+
val focusedNode: AccessibilityNodeInfo? = rootInActiveWindow.findFocus(AccessibilityNodeInfo.FOCUS_INPUT)
|
| 150 |
+
val text = accCommand.substringAfter("TYPE HERE ")
|
| 151 |
+
val arguments = Bundle()
|
| 152 |
+
arguments.putCharSequence(
|
| 153 |
+
AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text
|
| 154 |
+
)
|
| 155 |
+
focusedNode?.performAction(
|
| 156 |
+
AccessibilityNodeInfo.ACTION_SET_TEXT, arguments
|
| 157 |
+
)
|
| 158 |
}
|
| 159 |
}
|
| 160 |
}
|
|
|
|
| 233 |
|
| 234 |
private fun clickView(id: String) {
|
| 235 |
val rootNode = rootInActiveWindow ?: return
|
| 236 |
+
val nodes = rootNode.findAccessibilityNodeInfosByText(id)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 237 |
|
|
|
|
|
|
|
|
|
|
| 238 |
nodes.forEach {
|
| 239 |
+
it.performAction(AccessibilityNodeInfo.ACTION_CLICK)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 240 |
}
|
| 241 |
}
|
| 242 |
|
| 243 |
+
fun executeIntentCommand(command: String) {
|
| 244 |
val intentCommand = command.removePrefix("intent:")
|
| 245 |
|
| 246 |
Log.i("PuppetAS", "Executing Intent command: $intentCommand")
|
puppet/app/src/test/java/com/ttt246/puppet/PuppetASTest.kt
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.ttt246.puppet
|
| 2 |
+
import android.content.Context
|
| 3 |
+
import androidx.test.core.app.ApplicationProvider
|
| 4 |
+
import org.robolectric.RobolectricTestRunner
|
| 5 |
+
import org.robolectric.annotation.Config
|
| 6 |
+
import org.junit.runner.RunWith
|
| 7 |
+
import org.junit.Test
|
| 8 |
+
import org.junit.Before
|
| 9 |
+
import org.mockito.Mockito
|
| 10 |
+
|
| 11 |
+
class TestablePuppetAS : PuppetAS() {
|
| 12 |
+
fun attachBaseContextPublic(context: Context) {
|
| 13 |
+
attachBaseContext(context)
|
| 14 |
+
}
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
@RunWith(RobolectricTestRunner::class)
|
| 19 |
+
@Config(sdk = [Config.OLDEST_SDK])
|
| 20 |
+
class PuppetASTest {
|
| 21 |
+
private lateinit var puppetService: TestablePuppetAS
|
| 22 |
+
|
| 23 |
+
@Before
|
| 24 |
+
fun setUp() {
|
| 25 |
+
puppetService = Mockito.spy(TestablePuppetAS())
|
| 26 |
+
val context = ApplicationProvider.getApplicationContext<Context>()
|
| 27 |
+
puppetService.attachBaseContextPublic(context)
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
@Test
|
| 31 |
+
fun processCommands_executesIntentCommands() {
|
| 32 |
+
val command = "intent:test"
|
| 33 |
+
puppetService.processCommands(listOf(command))
|
| 34 |
+
Mockito.verify(puppetService).executeIntentCommand("intent:test")
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
@Test
|
| 38 |
+
fun processCommands_executesAccCommands() {
|
| 39 |
+
val command = "acc:UP"
|
| 40 |
+
puppetService.processCommands(listOf(command))
|
| 41 |
+
|
| 42 |
+
Mockito.verify(puppetService).executeAccCommand(command)
|
| 43 |
+
}
|
| 44 |
+
}
|
puppet/app/src/test/java/com/ttt246/puppet/SumTest.kt
CHANGED
|
@@ -1,17 +0,0 @@
|
|
| 1 |
-
package com.ttt246.puppet
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
import org.junit.Assert.assertEquals
|
| 5 |
-
import org.junit.Test
|
| 6 |
-
|
| 7 |
-
/**
|
| 8 |
-
* Example local unit test, which will execute on the development machine (host).
|
| 9 |
-
*
|
| 10 |
-
* See [testing documentation](http://d.android.com/tools/testing).
|
| 11 |
-
*/
|
| 12 |
-
class SumTest {
|
| 13 |
-
@Test
|
| 14 |
-
fun addition_isCorrect() {
|
| 15 |
-
assertEquals(4, 2 + 2)
|
| 16 |
-
}
|
| 17 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
puppet/app/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
mock-maker-inline
|