kotlin を1.5.30 に戻す。androidTestとtestを通す。

This commit is contained in:
tateisu 2021-10-28 08:37:39 +09:00
parent 9c68857e6e
commit 2e19190901
43 changed files with 1724 additions and 1367 deletions

View File

@ -34,8 +34,8 @@ repositories {
dependencies {
testImplementation "junit:junit:$junit_version"
androidTestImplementation 'androidx.test:runner:1.3.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
androidTestImplementation 'androidx.test:runner:1.4.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
api project(':apng')
// 'api'

View File

@ -41,7 +41,8 @@ android {
]
}
buildFeatures {
compose true
// composeを導入できない
// compose true
}
composeOptions {
kotlinCompilerExtensionVersion compose_version
@ -115,6 +116,10 @@ dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation fileTree(include: ['*.aar'], dir: 'src/main/libs')
// targetSdkVersion 31 androidTest android:exported
// https://github.com/android/android-test/issues/1022
androidTestImplementation "androidx.test:core:1.4.0"
androidTestImplementation('androidx.test.espresso:espresso-core:3.1.0-alpha4', {
exclude group: 'com.android.support', module: 'support-annotations'
})
@ -152,7 +157,6 @@ dependencies {
// https://firebase.google.com/support/release-notes/android
implementation "com.google.firebase:firebase-messaging:22.0.0"
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
@ -176,7 +180,7 @@ dependencies {
implementation "com.squareup.okhttp3:okhttp:$okhttpVersion"
implementation "com.squareup.okhttp3:okhttp-urlconnection:$okhttpVersion"
testImplementation "com.squareup.okhttp3:mockwebserver:$okhttpVersion"
androidTestImplementation "'com.squareup.okhttp3:mockwebserver:$okhttpVersion"
androidTestImplementation "com.squareup.okhttp3:mockwebserver:$okhttpVersion"
def glideVersion = '4.12.0'
implementation "com.github.bumptech.glide:glide:$glideVersion"
@ -241,18 +245,19 @@ dependencies {
// optional - Test helpers for LiveData
testImplementation "androidx.arch.core:core-testing:$arch_version"
implementation "com.google.accompanist:accompanist-flowlayout:0.20.0"
implementation "androidx.compose.ui:ui:$compose_version"
implementation "androidx.compose.material:material:$compose_version"
implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
implementation "androidx.compose.runtime:runtime-livedata:$compose_version"
implementation "androidx.compose.material:material-icons-extended:$compose_version"
androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
implementation 'androidx.activity:activity-compose:1.4.0-rc01'
// composeはkotlin 1.5.31
// https://gist.github.com/tateisu/cbda451135d2b5c9b69f7ac4599f9833 1.5.31使
// compose導入を諦める
// implementation "androidx.compose.ui:ui:$compose_version"
// implementation "androidx.compose.material:material:$compose_version"
// implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
// implementation "androidx.compose.runtime:runtime-livedata:$compose_version"
// implementation "androidx.compose.material:material-icons-extended:$compose_version"
// androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
// debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
// implementation 'androidx.activity:activity-compose:1.4.0-rc01'
// implementation "com.google.accompanist:accompanist-flowlayout:0.20.0"
}

View File

@ -1,23 +0,0 @@
package jp.juggler.subwaytooter;
import android.content.Context;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
// Android instrumentation test run configuration を編集しないと Empty tests とかいうエラーになります
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext(){
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();
assertEquals( "jp.juggler.subwaytooter", appContext.getPackageName() );
}
}

View File

@ -0,0 +1,18 @@
package jp.juggler.subwaytooter
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.runner.AndroidJUnit4
import org.junit.Assert
import org.junit.Test
import org.junit.runner.RunWith
// Android instrumentation test は run configuration を編集しないと Empty tests とかいうエラーになります
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
Assert.assertEquals("jp.juggler.subwaytooter", appContext.packageName)
}
}

View File

@ -1,14 +1,12 @@
package jp.juggler.subwaytooter
import androidx.test.runner.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import jp.juggler.util.*
import jp.juggler.util.jsonArray
import org.jetbrains.anko.collections.forEachReversedByIndex
import org.jetbrains.anko.collections.forEachReversedWithIndex
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
/**
* Example local unit test, which will execute on the development machine (host).

View File

@ -1,7 +1,7 @@
package jp.juggler.subwaytooter
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.runner.AndroidJUnit4
import jp.juggler.subwaytooter.api.TootApiCallback
import jp.juggler.subwaytooter.api.TootApiClient
import jp.juggler.subwaytooter.api.entity.Host

View File

@ -1,15 +1,12 @@
package jp.juggler.subwaytooter
import androidx.test.runner.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import jp.juggler.util.CharacterGroup
import jp.juggler.util.WordTrieTree
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Test
import org.junit.runner.RunWith
/**
* Instrumentation test, which will execute on an Android device.
@ -22,7 +19,44 @@ class WordTrieTreeTest {
companion object {
private val whitespace_chars = charArrayOf(0x0009.toChar(), 0x000A.toChar(), 0x000B.toChar(), 0x000C.toChar(), 0x000D.toChar(), 0x001C.toChar(), 0x001D.toChar(), 0x001E.toChar(), 0x001F.toChar(), 0x0020.toChar(), 0x0085.toChar(), 0x00A0.toChar(), 0x1680.toChar(), 0x180E.toChar(), 0x2000.toChar(), 0x2001.toChar(), 0x2002.toChar(), 0x2003.toChar(), 0x2004.toChar(), 0x2005.toChar(), 0x2006.toChar(), 0x2007.toChar(), 0x2008.toChar(), 0x2009.toChar(), 0x200A.toChar(), 0x200B.toChar(), 0x200C.toChar(), 0x200D.toChar(), 0x2028.toChar(), 0x2029.toChar(), 0x202F.toChar(), 0x205F.toChar(), 0x2060.toChar(), 0x3000.toChar(), 0x3164.toChar(), 0xFEFF.toChar())
private val whitespace_chars = charArrayOf(
0x0009.toChar(),
0x000A.toChar(),
0x000B.toChar(),
0x000C.toChar(),
0x000D.toChar(),
0x001C.toChar(),
0x001D.toChar(),
0x001E.toChar(),
0x001F.toChar(),
0x0020.toChar(),
0x0085.toChar(),
0x00A0.toChar(),
0x1680.toChar(),
0x180E.toChar(),
0x2000.toChar(),
0x2001.toChar(),
0x2002.toChar(),
0x2003.toChar(),
0x2004.toChar(),
0x2005.toChar(),
0x2006.toChar(),
0x2007.toChar(),
0x2008.toChar(),
0x2009.toChar(),
0x200A.toChar(),
0x200B.toChar(),
0x200C.toChar(),
0x200D.toChar(),
0x2028.toChar(),
0x2029.toChar(),
0x202F.toChar(),
0x205F.toChar(),
0x2060.toChar(),
0x3000.toChar(),
0x3164.toChar(),
0xFEFF.toChar()
)
}
@Test
@ -60,7 +94,10 @@ class WordTrieTreeTest {
assertEquals((whitespace_len + 3).toLong(), tokenizer.offset.toLong())
//
id = tokenizer.next()
assertEquals((whitespace_len + 3).toLong(), tokenizer.offset.toLong()) // offsetはCの次の位置のまま
assertEquals(
(whitespace_len + 3).toLong(),
tokenizer.offset.toLong()
) // offsetはCの次の位置のまま
assertEquals(CharacterGroup.END, id)
}

View File

@ -1,23 +1,21 @@
package jp.juggler.subwaytooter.api
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.runner.AndroidJUnit4
import android.test.mock.MockContext
import jp.juggler.subwaytooter.api.entity.*
import jp.juggler.subwaytooter.table.SavedAccount
import jp.juggler.util.JsonObject
import jp.juggler.util.jsonObject
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class TestDuplicateMap {
private val parser = TootParser(
MockContext(),
InstrumentationRegistry.getInstrumentation().targetContext,
SavedAccount(
db_id = 1,
acctArg = "user1@host1",
@ -25,31 +23,31 @@ class TestDuplicateMap {
)
)
private val generatedItems = ArrayList<TimelineItem>()
private fun genStatus(
parser: TootParser,
accountJson: JsonObject,
statusId: String,
uri : String?,
uri: String,
url: String?
): TootStatus {
val itemJson = jsonObject {
put("account", accountJson)
put("id", statusId)
if(uri != null) put("uri", uri)
put("uri", uri)
if (url != null) put("url", url)
}
return TootStatus(parser, itemJson)
}
private fun checkStatus(
private fun testDuplicateStatus(): ArrayList<TimelineItem> {
val generatedItems = ArrayList<TimelineItem>()
fun checkStatus(
map: DuplicateMap,
parser: TootParser,
accountJson: JsonObject,
statusId: String,
uri : String?,
uri: String,
url: String?
) {
val item = genStatus(parser, accountJson, statusId, uri, url)
@ -59,7 +57,6 @@ class TestDuplicateMap {
assertEquals(true, map.isDuplicate(item))
}
private fun testDuplicateStatus() {
val account1Json = jsonObject {
put("username", "user1")
@ -78,7 +75,7 @@ class TestDuplicateMap {
map,
parser,
account1Json,
"1",
"s1",
"http://${parser.apiHost}/@${account1.username}/1",
"http://${parser.apiHost}/@${account1.username}/1"
)
@ -87,27 +84,19 @@ class TestDuplicateMap {
map,
parser,
account1Json,
"2",
"s2",
"http://${parser.apiHost}/@${account1.username}/2",
"http://${parser.apiHost}/@${account1.username}/2"
)
// 今度はuriがない
// URIは必須になったので、URIなしのテストは行わない
// 今度はURLがない
checkStatus(
map,
parser,
account1Json,
"3",
null, // "http://${parser.accessHost}/@${account1.username}/3",
"http://${parser.apiHost}/@${account1.username}/3"
)
// 今度はuriとURLがない
checkStatus(
map,
parser,
account1Json,
"4",
null, // "http://${parser.accessHost}/@${account1.username}/4",
null //"http://${parser.accessHost}/@${account1.username}/4"
"s4",
"http://${parser.apiHost}/@${account1.username}/4",
null //"http://${parser.apiHost}/@${account1.username}/4"
)
// 今度はIDがおかしい
checkStatus(
@ -115,17 +104,19 @@ class TestDuplicateMap {
parser,
account1Json,
"",
null, // "http://${parser.accessHost}/@${account1.username}/4",
null //"http://${parser.accessHost}/@${account1.username}/4"
"http://${parser.apiHost}/@${account1.username}/5",
"http://${parser.apiHost}/@${account1.username}/5"
)
return generatedItems
}
private fun checkNotification(
private fun testDuplicateNotification(): ArrayList<TimelineItem> {
val generatedItems = ArrayList<TimelineItem>()
fun checkNotification(
map: DuplicateMap,
parser: TootParser,
id : Long
id: String
) {
val itemJson = JsonObject()
@ -141,17 +132,19 @@ class TestDuplicateMap {
assertEquals(true, map.isDuplicate(item))
}
private fun testDuplicateNotification() {
val map = DuplicateMap()
checkNotification(map,parser,0L)
checkNotification(map,parser,1L)
checkNotification(map,parser,2L)
checkNotification(map,parser,3L)
checkNotification(map, parser, "n0")
checkNotification(map, parser, "n1")
checkNotification(map, parser, "n2")
checkNotification(map, parser, "n3")
return generatedItems
}
private fun checkReport(
private fun testDuplicateReport(): ArrayList<TimelineItem> {
val generatedItems = ArrayList<TimelineItem>()
fun checkReport(
map: DuplicateMap,
id : Long
id: String
) {
val item = TootReport(JsonObject().apply {
put("id", id)
@ -165,18 +158,21 @@ class TestDuplicateMap {
}
private fun testDuplicateReport() {
val map = DuplicateMap()
checkReport(map,0L)
checkReport(map,1L)
checkReport(map,2L)
checkReport(map,3L)
checkReport(map, "r0")
checkReport(map, "r1")
checkReport(map, "r2")
checkReport(map, "r3")
return generatedItems
}
private fun checkAccount(
private fun testDuplicateAccount(): ArrayList<TimelineItem> {
val generatedItems = ArrayList<TimelineItem>()
fun checkAccount(
map: DuplicateMap,
parser: TootParser,
id : Long
id: String
) {
val itemJson = JsonObject()
@ -194,27 +190,47 @@ class TestDuplicateMap {
assertEquals(true, map.isDuplicate(item)) // 二回目はtrueになる
}
private fun testDuplicateAccount() {
val map = DuplicateMap()
checkAccount(map,parser,0L)
checkAccount(map,parser,1L)
checkAccount(map,parser,2L)
checkAccount(map,parser,3L)
checkAccount(map, parser, "a0")
checkAccount(map, parser, "a1")
checkAccount(map, parser, "a2")
checkAccount(map, parser, "a3")
return generatedItems
}
@Test fun testFilterList(){
generatedItems.clear()
testDuplicateStatus()
testDuplicateNotification()
testDuplicateReport()
testDuplicateAccount()
@Test
fun testFilterList() {
val statusItems = testDuplicateStatus()
val notiItems = testDuplicateNotification()
val reportItems = testDuplicateReport()
val accountItems = testDuplicateAccount()
val map = DuplicateMap()
var map = DuplicateMap()
var dst = map.filterDuplicate(statusItems)
assertEquals("statusItems", statusItems.size, dst.size)
val dst = map.filterDuplicate( generatedItems)
assertEquals( generatedItems.size,dst.size)
map = DuplicateMap()
dst = map.filterDuplicate(notiItems)
assertEquals("notiItems", notiItems.size, dst.size)
val dst2 = map.filterDuplicate( generatedItems)
map = DuplicateMap()
dst = map.filterDuplicate(reportItems)
assertEquals("reportItems", reportItems.size, dst.size)
map = DuplicateMap()
dst = map.filterDuplicate(accountItems)
assertEquals("accountItems", accountItems.size, dst.size)
val totalItems = ArrayList<TimelineItem>()
totalItems.addAll(statusItems)
totalItems.addAll(notiItems)
totalItems.addAll(reportItems)
totalItems.addAll(accountItems)
map = DuplicateMap()
dst = map.filterDuplicate(totalItems)
assertEquals("totalItems", totalItems.size, dst.size)
val dst2 = map.filterDuplicate(totalItems)
assertEquals(0, dst2.size)
}
}

View File

@ -2,7 +2,7 @@
package jp.juggler.subwaytooter.api
import androidx.test.InstrumentationRegistry
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.runner.AndroidJUnit4
import jp.juggler.subwaytooter.api.entity.Host
import jp.juggler.subwaytooter.api.entity.TootInstance
@ -28,7 +28,7 @@ import java.util.concurrent.atomic.AtomicReference
@RunWith(AndroidJUnit4::class)
class TestTootApiClient {
private val appContext = InstrumentationRegistry.getTargetContext()!!
private val appContext = InstrumentationRegistry.getInstrumentation().targetContext!!
class SimpleHttpClientMock(
private val responseGenerator: (request: Request) -> Response,
@ -39,7 +39,10 @@ class TestTootApiClient {
// override var currentCallCallback : CurrentCallCallback? = null
override suspend fun getResponse(request: Request, tmpOkhttpClient: OkHttpClient?): Response {
override suspend fun getResponse(
request: Request,
tmpOkhttpClient: OkHttpClient?
): Response {
return responseGenerator(request)
}
@ -51,6 +54,27 @@ class TestTootApiClient {
}
}
private fun <T> assertOneOf(actual: T?, vararg expect: T?) {
if (!expect.any { it == actual }) {
fail("actual=$actual, expected = one of [${expect.joinToString(", ")}]")
}
}
private fun assertParsingResponse(callback: ProgressRecordTootApiCallback) {
assertOneOf(
callback.progressString,
"Parsing response…",
"応答の解析中…"
)
}
private fun assertReading(callback: ProgressRecordTootApiCallback,path:String){
assertOneOf(
callback.progressString,
"Reading: GET $path",
"読込中: GET $path",
)
}
private fun requestBodyString(request: Request?): String? {
try {
val copyBody = request?.newBuilder()?.build()?.body ?: return null
@ -461,7 +485,7 @@ class TestTootApiClient {
bodyString = response.body?.string()
message = TootApiClient.formatResponse(response, "caption", bodyString)
assertEquals("Error! (HTTP 500 status-message) caption", message)
assertEquals("(HTTP 500 status-message) caption", message)
// without status message
request = Request.Builder()
@ -478,8 +502,12 @@ class TestTootApiClient {
bodyString = response.body?.string()
message = TootApiClient.formatResponse(response = response,caption = "caption",bodyString = bodyString)
assertEquals("Error! (HTTP 500) caption", message)
message = TootApiClient.formatResponse(
response = response,
caption = "caption",
bodyString = bodyString
)
assertEquals("(HTTP 500) caption", message)
}
@Test
@ -543,7 +571,11 @@ class TestTootApiClient {
callback.progressString = null
val bOk = client.sendRequest(result) { requestSimple }
assertEquals(true, bOk)
assertEquals("Acquiring: GET /", callback.progressString)
assertOneOf(
callback.progressString,
"Acquiring: GET /",
"取得中: GET /",
)
assertEquals(null, result.error)
assertNotNull(result.response)
}
@ -561,10 +593,15 @@ class TestTootApiClient {
callback.progressString = null
val bOk = client.sendRequest(result) { requestSimple }
assertEquals(false, bOk)
assertEquals("Acquiring: GET /", callback.progressString)
assertEquals(
assertOneOf(
callback.progressString,
"Acquiring: GET /",
"取得中: GET /",
)
assertOneOf(
result.error,
"instance: Network error.: NotImplementedError An operation is not implemented.",
result.error
"instance: 通信エラー。: NotImplementedError An operation is not implemented.",
)
assertNull(result.response)
@ -583,7 +620,11 @@ class TestTootApiClient {
callback.progressString = null
val bOk = client.sendRequest(result, progressPath = "XXX") { requestSimple }
assertEquals(true, bOk)
assertEquals("Acquiring: GET XXX", callback.progressString)
assertOneOf(
callback.progressString,
"Acquiring: GET XXX",
"取得中: GET XXX",
)
assertEquals(null, result.error)
assertNotNull(result.response)
}
@ -626,7 +667,7 @@ class TestTootApiClient {
val bodyString = client.readBodyString(result)
assertEquals(strJsonOk, bodyString)
assertEquals(strJsonOk, result.bodyString)
assertEquals("Parsing response…", callback.progressString)
assertParsingResponse(callback)
assertNull(result.error)
assertNull(result.data)
}
@ -642,7 +683,7 @@ class TestTootApiClient {
val bodyString = client.readBodyString(result)
assertEquals(null, bodyString)
assertEquals(null, result.bodyString)
assertEquals("Reading: GET instance", callback.progressString)
assertReading(callback,"instance")
assertEquals("Error! (HTTP 500 status-message) instance", result.error)
assertNull(result.data)
}
@ -657,7 +698,7 @@ class TestTootApiClient {
val bodyString = client.readBodyString(result)
assertEquals("", bodyString)
assertEquals("", result.bodyString)
assertEquals("Reading: GET instance", callback.progressString)
assertReading(callback,"instance")
assertEquals(null, result.error)
assertNull(result.data)
}
@ -672,7 +713,7 @@ class TestTootApiClient {
val bodyString = client.readBodyString(result)
assertEquals("", bodyString)
assertEquals("", result.bodyString)
assertEquals("Reading: GET instance", callback.progressString)
assertReading(callback,"instance")
assertEquals(null, result.error)
assertNull(result.data)
}
@ -736,7 +777,7 @@ class TestTootApiClient {
assertNotNull(r2)
assertEquals(strJsonOk, result.string)
assertEquals(strJsonOk, result.bodyString)
assertEquals("Parsing response…", callback.progressString)
assertParsingResponse(callback)
assertNull(result.error)
}
// 正常レスポンスならJSONにエラーがあってもreadStringは関知しない
@ -750,7 +791,7 @@ class TestTootApiClient {
assertNotNull(r2)
assertEquals(strJsonError, result.string)
assertEquals(strJsonError, result.bodyString)
assertEquals("Parsing response…", callback.progressString)
assertParsingResponse(callback)
assertNull(result.error)
}
@ -765,7 +806,7 @@ class TestTootApiClient {
assertNotNull(r2)
assertEquals(null, result.string)
assertEquals(null, result.bodyString)
assertEquals("Reading: GET instance", callback.progressString)
assertReading(callback,"instance")
assertEquals("Error! (HTTP 500 status-message) instance", result.error)
}
@ -780,7 +821,7 @@ class TestTootApiClient {
assertNotNull(r2)
assertEquals(null, result.string)
assertEquals(null, result.bodyString)
assertEquals("Reading: GET instance", callback.progressString)
assertReading(callback,"instance")
assertEquals("(no information) (HTTP 404 status-message) instance", result.error)
assertNull(result.data)
}
@ -796,7 +837,7 @@ class TestTootApiClient {
assertNotNull(r2)
assertEquals("", result.string)
assertEquals("", result.bodyString)
assertEquals("Reading: GET instance", callback.progressString)
assertReading(callback,"instance")
assertEquals(null, result.error)
assertEquals("", result.data)
}
@ -811,7 +852,7 @@ class TestTootApiClient {
assertNotNull(r2)
assertEquals(null, result.string)
assertEquals(null, result.bodyString)
assertEquals("Reading: GET instance", callback.progressString)
assertReading(callback,"instance")
assertEquals("(no information) (HTTP 200 status-message) instance", result.error)
assertNull(result.data)
}
@ -857,7 +898,7 @@ class TestTootApiClient {
assertNotNull(r2)
assertEquals("A!", result.jsonObject?.optString("a"))
assertEquals(strJsonOk, result.bodyString)
assertEquals("Parsing response…", callback.progressString)
assertParsingResponse(callback)
assertNull(result.error)
}
// 正常ケースでもjsonデータにerror項目があれば
@ -872,7 +913,7 @@ class TestTootApiClient {
assertNotNull(r2)
assertEquals(null, result.data)
assertEquals(strJsonError, result.bodyString)
assertEquals("Parsing response…", callback.progressString)
assertParsingResponse(callback)
assertEquals("Error!", result.error)
}
@ -886,7 +927,7 @@ class TestTootApiClient {
assertNotNull(r2)
assertEquals(null, result.data)
assertEquals(null, result.bodyString)
assertEquals("Reading: GET instance", callback.progressString)
assertReading(callback,"instance")
assertEquals("Error! (HTTP 500 status-message) instance", result.error)
}
@ -901,7 +942,7 @@ class TestTootApiClient {
assertNotNull(r2)
assertEquals(0, result.jsonObject?.size)
assertEquals("", result.bodyString)
assertEquals("Reading: GET instance", callback.progressString)
assertReading(callback,"instance")
assertEquals(null, result.error)
}
@ -915,7 +956,7 @@ class TestTootApiClient {
assertNotNull(r2)
assertEquals(0, result.jsonObject?.size)
assertEquals("", result.bodyString)
assertEquals("Reading: GET instance", callback.progressString)
assertReading(callback,"instance")
assertEquals(null, result.error)
}
@ -929,7 +970,7 @@ class TestTootApiClient {
assertNotNull(r2)
assertEquals(null, result.data)
assertEquals(null, result.bodyString)
assertEquals("Reading: GET instance", callback.progressString)
assertReading(callback,"instance")
assertEquals("(no information) (HTTP 200 status-message) instance", result.error)
assertNull(result.data)
}
@ -945,7 +986,7 @@ class TestTootApiClient {
assertNotNull(r2)
assertEquals("A!", result.jsonArray?.optString(0))
assertEquals(strJsonArray1, result.bodyString)
assertEquals("Parsing response…", callback.progressString)
assertParsingResponse(callback)
assertNull(result.error)
}
@ -961,7 +1002,7 @@ class TestTootApiClient {
assertNotNull(r2)
assertEquals("A!", result.jsonArray?.optString(0))
assertEquals(strJsonArray2, result.bodyString)
assertEquals("Parsing response…", callback.progressString)
assertParsingResponse(callback)
assertNull(result.error)
}
@ -976,7 +1017,7 @@ class TestTootApiClient {
assertNotNull(r2)
assertEquals("A!", result.jsonObject?.optString("a"))
assertEquals(strJsonObject2, result.bodyString)
assertEquals("Parsing response…", callback.progressString)
assertParsingResponse(callback)
assertNull(result.error)
}
// JSONじゃない
@ -990,8 +1031,12 @@ class TestTootApiClient {
assertNotNull(r2)
assertEquals(null, result.data)
assertEquals(strPlainText, result.bodyString)
assertEquals("Parsing response…", callback.progressString)
assertEquals("API response is not JSON. Hello! (HTTP 200 status-message) https://dummy-url.net/", result.error)
assertParsingResponse(callback)
assertOneOf(
result.error,
"API response is not JSON. Hello! (HTTP 200 status-message) https://dummy-url.net/",
"APIの応答がJSONではありません Hello! (HTTP 200 status-message) https://dummy-url.net/",
)
}
}
}

View File

@ -1,17 +1,16 @@
package jp.juggler.subwaytooter.api.entity
import androidx.test.runner.AndroidJUnit4
import android.test.mock.MockContext
import androidx.test.runner.AndroidJUnit4
import jp.juggler.subwaytooter.api.TootParser
import jp.juggler.subwaytooter.table.SavedAccount
import jp.juggler.util.JsonArray
import jp.juggler.util.JsonObject
import jp.juggler.util.notEmptyOrThrow
import jp.juggler.util.decodeJsonObject
import jp.juggler.util.notEmptyOrThrow
import org.junit.Assert.*
import org.junit.runner.RunWith
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class TestEntityUtils {

View File

@ -2,12 +2,10 @@ package jp.juggler.subwaytooter.api.entity
import androidx.test.runner.AndroidJUnit4
import jp.juggler.subwaytooter.util.LinkHelper
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.assertEquals
@RunWith(AndroidJUnit4::class)
class TestTootAccount {
@ -15,25 +13,35 @@ class TestTootAccount {
@Throws(Exception::class)
fun testFindHostFromUrl() {
val emptyHost = Host.EMPTY
// all null
assertEquals(null, TootAccount.findHostFromUrl(null, null, null).first)
var pair = TootAccount.findHostFromUrl(null, null, null)
assertEquals(null, pair.first)
// find from acct
assertEquals(null, TootAccount.findHostFromUrl("", null, null).first)
pair = TootAccount.findHostFromUrl("", null, null)
assertEquals(Host.UNKNOWN, pair.first)
assertEquals(null, TootAccount.findHostFromUrl("user", null, null).first)
assertEquals(null, TootAccount.findHostFromUrl("user@", null, null).first)
assertEquals("host", TootAccount.findHostFromUrl("user@HOST", null, null).first)
assertEquals(emptyHost, TootAccount.findHostFromUrl("user@", null, null).first)
assertEquals(
"host",
TootAccount.findHostFromUrl("user@HOST", null, null)
.first?.ascii
)
// find from accessHost
assertEquals(
"",
TootAccount.findHostFromUrl(null, LinkHelper.create(Host.parse("")), null).first
emptyHost,
TootAccount.findHostFromUrl(null, LinkHelper.create(emptyHost), null).first
)
val testHost = Host.parse("any string is allowed")
assertEquals(
"any string is allowed",
testHost,
TootAccount.findHostFromUrl(
null,
LinkHelper.create(Host.parse("any string is allowed")),
LinkHelper.create(testHost),
null
).first
)
@ -46,15 +54,15 @@ class TestTootAccount {
TootAccount.findHostFromUrl(null, null, "mailto:tateisu@gmail.com").first
)
assertEquals(
"mastodon.juggler.jp",
Host.parse("mastodon.juggler.jp"),
TootAccount.findHostFromUrl(null, null, "https://MASTODON.juggler.jp/@tateisu").first
)
assertEquals(
"mastodon.juggler.jp",
Host.parse("mastodon.juggler.jp"),
TootAccount.findHostFromUrl(null, null, "https://mastodon.juggler.jp/").first
)
assertEquals(
"mastodon.juggler.jp",
Host.parse("mastodon.juggler.jp"),
TootAccount.findHostFromUrl(null, null, "https://mastodon.juggler.jp").first
)
}

View File

@ -0,0 +1,26 @@
package jp.juggler.subwaytooter.database
import androidx.test.runner.AndroidJUnit4
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class TestArrayListSizeBug {
@Test
fun testArrayListSize() {
val list = ArrayList(arrayOf("c", "b", "a").toList())
assertEquals("ArrayList size", 3, list.size)
}
class ArrayListDerived<E>(args: List<E>) : ArrayList<E>(args)
@Test
fun testArrayListDerived() {
val list = ArrayListDerived(arrayOf("c", "b", "a").toList())
assertEquals("ArrayListDerived size", 3, list.size)
// kotlin 1.5.31で(Javaの) size() ではなく getSize() にアクセスしようとして例外を出していた
// kotlin 1.5.30では大丈夫だったが、JetPack Composeは 1.5.31を要求するのだった…。
}
}

View File

@ -0,0 +1,66 @@
package jp.juggler.subwaytooter.database
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.runner.AndroidJUnit4
import jp.juggler.subwaytooter.App1
import org.junit.Assert.assertNull
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class TestDatabase {
private class MockDbHelper(
context: Context,
dbName: String,
dbVersion: Int,
val create: (SQLiteDatabase) -> Unit,
val upgrade: (SQLiteDatabase, Int, Int) -> Unit,
) : SQLiteOpenHelper(context, dbName, null, dbVersion) {
override fun onCreate(db: SQLiteDatabase) {
create(db)
}
override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
upgrade(db, oldVersion, newVersion)
}
}
@Test
fun testCreateAll() {
val context = InstrumentationRegistry.getInstrumentation().targetContext
val dbName = "testCreateAll"
val helper = MockDbHelper(
context,
dbName,
App1.DB_VERSION,
create = { db ->
App1.tableList.forEach {
val ex = try {
it.onDBCreate(db)
null
} catch (ex: Throwable) {
ex
}
assertNull("${it.table} onDBCreate", ex)
}
},
upgrade = { db, oldV, newV ->
App1.tableList.forEach {
val ex = try {
it.onDBUpgrade(db, oldV, newV)
null
} catch (ex: Throwable) {
ex
}
assertNull("${it.table} onDBUpgrade", ex)
}
}
)
context.deleteDatabase(dbName)
helper.writableDatabase
}
}

View File

@ -1,15 +1,16 @@
package jp.juggler.subwaytooter.util
import androidx.test.runner.AndroidJUnit4
import org.junit.Assert.*
import androidx.test.runner.AndroidJUnit4
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
@Suppress("MemberVisibilityCanPrivate")
@RunWith(AndroidJUnit4::class)
class TestBucketList {
@Test fun test1(){
@Test
fun test1() {
val list = BucketList<String>(bucketCapacity = 2)
assertEquals(true, list.isEmpty())
list.addAll(listOf("A", "B", "C"))

View File

@ -1,6 +1,6 @@
package jp.juggler.subwaytooter.util
import androidx.test.InstrumentationRegistry
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.runner.AndroidJUnit4
import jp.juggler.subwaytooter.api.entity.Host
import jp.juggler.util.neatSpaces
@ -22,9 +22,10 @@ class TestHtmlDecoder {
override fun toString() = "[$start..$end) $flags ${span.javaClass.simpleName} $text"
}
@Test fun test1(){
@Test
fun test1() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getTargetContext()
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
val options = DecodeOptions(appContext, LinkHelper.create(Host.parse("instance.test")))
@ -49,9 +50,9 @@ class TestHtmlDecoder {
}
spanArray.forEach { println(it) }
assertEquals(3,spanArray.size)
assertEquals(5, spanArray.size)
assertEquals("利用規約", spanArray[0].text)
assertEquals( "<img/>", spanArray[1].text)
assertEquals( "<img/>", spanArray[2].text)
assertEquals("Androidアプリ", spanArray[1].text)
assertEquals("<img Androidアプリ />", spanArray[2].text)
}
}

View File

@ -131,9 +131,9 @@ class App1 : Application() {
// 2021/5/11 59=>60 SavedAccountテーブルに項目追加
// 2021/5/23 60=>61 SavedAccountテーブルに項目追加
internal const val DB_VERSION = 61
const val DB_VERSION = 61
private val tableList = arrayOf(
val tableList = arrayOf(
LogData,
SavedAccount,
ClientInfo,

View File

@ -3,12 +3,11 @@ package jp.juggler.subwaytooter
import android.content.Context
import android.content.SharedPreferences
import android.graphics.Color
import androidx.preference.PreferenceManager
import jp.juggler.subwaytooter.itemviewholder.AdditionalButtonsPosition
import jp.juggler.util.optInt
fun Context.pref(): SharedPreferences =
PreferenceManager.getDefaultSharedPreferences(this)
this.getSharedPreferences(this.packageName + "_preferences", Context.MODE_PRIVATE)
@Suppress("EqualsOrHashCode")
abstract class BasePref<T>(val key: String, val defVal: T) {
@ -503,7 +502,8 @@ object PrefI {
const val VS_MISSKEY = 2
val ipVisibilityStyle = IntPref("ipVisibilityStyle", VS_BY_ACCOUNT)
val ipAdditionalButtonsPosition = IntPref("AdditionalButtonsPosition", AdditionalButtonsPosition.End.idx)
val ipAdditionalButtonsPosition =
IntPref("AdditionalButtonsPosition", AdditionalButtonsPosition.End.idx)
val ipFooterButtonBgColor = IntPref("footer_button_bg_color", 0)
val ipFooterButtonFgColor = IntPref("footer_button_fg_color", 0)

View File

@ -75,7 +75,7 @@ class AcctColor {
private val log = LogCategory("AcctColor")
const val table = "acct_color"
override val table = "acct_color"
val columnList: ColumnMeta.List = ColumnMeta.List(table, 9).apply {
// not used, but must be defined

View File

@ -16,7 +16,7 @@ object AcctSet : TableCompanion {
private val log = LogCategory("AcctSet")
private const val table = "acct_set"
override val table = "acct_set"
val columnList: ColumnMeta.List = ColumnMeta.List(table, 7).apply {
ColumnMeta(this, 0, BaseColumns._ID, "INTEGER PRIMARY KEY", primary = true)

View File

@ -9,7 +9,7 @@ import jp.juggler.util.*
object ClientInfo : TableCompanion {
private val log = LogCategory("ClientInfo")
const val table = "client_info2"
override val table = "client_info2"
val columnList: ColumnMeta.List = ColumnMeta.List(table, 19).apply {
ColumnMeta(this, 0, BaseColumns._ID, "INTEGER PRIMARY KEY", primary = true)
createExtra = {

View File

@ -11,7 +11,7 @@ import jp.juggler.util.*
object ContentWarning : TableCompanion {
private val log = LogCategory("ContentWarning")
private const val table = "content_warning"
override val table = "content_warning"
val columnList: ColumnMeta.List = ColumnMeta.List(table, 0).apply {
ColumnMeta(this, 0, BaseColumns._ID, "INTEGER PRIMARY KEY", primary = true)

View File

@ -13,7 +13,7 @@ object FavMute : TableCompanion {
private val log = LogCategory("FavMute")
const val table = "fav_mute"
override val table = "fav_mute"
const val COL_ID = "_id"
const val COL_ACCT = "acct"

View File

@ -19,7 +19,7 @@ class HighlightWord {
const val SOUND_TYPE_DEFAULT = 1
const val SOUND_TYPE_CUSTOM = 2
const val table = "highlight_word"
override val table = "highlight_word"
const val COL_ID = BaseColumns._ID
const val COL_NAME = "name"
private const val COL_TIME_SAVE = "time_save"

View File

@ -6,7 +6,7 @@ import jp.juggler.util.TableCompanion
object LogData : TableCompanion {
// private const val TAG = "SubwayTooter"
internal const val table = "warning"
override val table = "warning"
private const val COL_TIME = "t"
private const val COL_LEVEL = "l"

View File

@ -10,7 +10,7 @@ import jp.juggler.util.*
object MediaShown : TableCompanion {
private val log = LogCategory("MediaShown")
private const val table = "media_shown_misskey"
override val table = "media_shown_misskey"
val columnList: ColumnMeta.List = ColumnMeta.List(table, 30).apply {
ColumnMeta(this, 0, BaseColumns._ID, "INTEGER PRIMARY KEY", primary = true)

View File

@ -14,7 +14,7 @@ object MutedApp : TableCompanion {
private val log = LogCategory("MutedApp")
internal const val table = "app_mute"
override val table = "app_mute"
const val COL_ID = "_id"
const val COL_NAME = "name"
private const val COL_TIME_SAVE = "time_save"

View File

@ -13,7 +13,7 @@ object MutedWord : TableCompanion {
private val log = LogCategory("MutedWord")
const val table = "word_mute"
override val table = "word_mute"
const val COL_ID = "_id"
const val COL_NAME = "name"
private const val COL_TIME_SAVE = "time_save"

View File

@ -28,7 +28,7 @@ class NotificationCache(private val account_db_id: Long) {
private val log = LogCategory("NotificationCache")
private const val table = "noti_cache"
override val table = "noti_cache"
private const val COL_ID = BaseColumns._ID

View File

@ -83,7 +83,12 @@ class NotificationTracking {
val cv = ContentValues()
postId.putTo(cv, COL_POST_ID)
cv.put(COL_POST_TIME, postTime)
val rows = App1.database.update(table, cv, WHERE_AID, arrayOf(accountDbId.toString(), notificationType))
val rows = App1.database.update(
table,
cv,
WHERE_AID,
arrayOf(accountDbId.toString(), notificationType)
)
log.d("updatePost account_db_id=$accountDbId, nt=$notificationType, post=$postId,$postTime update_rows=$rows")
dirty = false
clearCache(accountDbId, notificationType)
@ -97,7 +102,7 @@ class NotificationTracking {
private val log = LogCategory("NotificationTracking")
private const val table = "noti_trac"
override val table = "noti_trac"
private const val COL_ID = BaseColumns._ID
@ -179,9 +184,13 @@ class NotificationTracking {
/////////////////////////////////////////////////////////////////////////////////
private val cache = ConcurrentHashMap<Long, ConcurrentHashMap<String, NotificationTracking>>()
private val cache =
ConcurrentHashMap<Long, ConcurrentHashMap<String, NotificationTracking>>()
private fun <K : Any, V : Any> ConcurrentHashMap<K, V>.getOrCreate(key: K, creator: () -> V): V {
private fun <K : Any, V : Any> ConcurrentHashMap<K, V>.getOrCreate(
key: K,
creator: () -> V
): V {
var v = this[key]
if (v == null) v = creator().also { this[key] = it }
return v
@ -193,7 +202,11 @@ class NotificationTracking {
private fun clearCache(accountDbId: Long, notificationType: String): NotificationTracking? =
cache[accountDbId]?.remove(notificationType)
private fun saveCache(accountDbId: Long, notificationType: String, nt: NotificationTracking) {
private fun saveCache(
accountDbId: Long,
notificationType: String,
nt: NotificationTracking
) {
cache.getOrCreate(accountDbId) {
ConcurrentHashMap<String, NotificationTracking>()
}[notificationType] = nt
@ -248,7 +261,8 @@ class NotificationTracking {
log.i("$acct/$notificationType read>show! clip to $show")
val cv = ContentValues()
show.putTo(cv, COL_NID_READ) //変数名とキー名が異なるのに注意
val where_args = arrayOf(accountDbId.toString(), notificationType)
val where_args =
arrayOf(accountDbId.toString(), notificationType)
App1.database.update(table, cv, WHERE_AID, where_args)
}
}

View File

@ -34,7 +34,7 @@ class PostDraft {
private val log = LogCategory("PostDraft")
private const val table = "post_draft"
override val table = "post_draft"
private const val COL_ID = BaseColumns._ID
private const val COL_TIME_SAVE = "time_save"
private const val COL_JSON = "json"

View File

@ -344,7 +344,7 @@ class SavedAccount(
private val log = LogCategory("SavedAccount")
const val table = "access_info"
override val table = "access_info"
val columnList = ColumnMeta.List(table, 0).apply {
createExtra = {
@ -355,7 +355,8 @@ class SavedAccount(
}
}
private val COL_ID = ColumnMeta(columnList, 0, BaseColumns._ID, "INTEGER PRIMARY KEY", primary = true)
private val COL_ID =
ColumnMeta(columnList, 0, BaseColumns._ID, "INTEGER PRIMARY KEY", primary = true)
private val COL_HOST = ColumnMeta(columnList, 0, "h", "text not null")
private val COL_DOMAIN = ColumnMeta(columnList, 56, "d", "text")
private val COL_USER = ColumnMeta(columnList, 0, "u", "text not null")
@ -363,30 +364,48 @@ class SavedAccount(
private val COL_TOKEN = ColumnMeta(columnList, 0, "t", "text not null")
private val COL_VISIBILITY = ColumnMeta(columnList, 0, "visibility", "text")
private val COL_CONFIRM_BOOST = ColumnMeta(columnList, 0, "confirm_boost", ColumnMeta.TS_TRUE)
private val COL_DONT_HIDE_NSFW = ColumnMeta(columnList, 0, "dont_hide_nsfw", ColumnMeta.TS_ZERO)
private val COL_CONFIRM_BOOST =
ColumnMeta(columnList, 0, "confirm_boost", ColumnMeta.TS_TRUE)
private val COL_DONT_HIDE_NSFW =
ColumnMeta(columnList, 0, "dont_hide_nsfw", ColumnMeta.TS_ZERO)
private val COL_NOTIFICATION_MENTION = ColumnMeta(columnList, 2, "notification_mention", ColumnMeta.TS_TRUE)
private val COL_NOTIFICATION_BOOST = ColumnMeta(columnList, 2, "notification_boost", ColumnMeta.TS_TRUE)
private val COL_NOTIFICATION_FAVOURITE = ColumnMeta(columnList, 2, "notification_favourite", ColumnMeta.TS_TRUE)
private val COL_NOTIFICATION_FOLLOW = ColumnMeta(columnList, 2, "notification_follow", ColumnMeta.TS_TRUE)
private val COL_NOTIFICATION_MENTION =
ColumnMeta(columnList, 2, "notification_mention", ColumnMeta.TS_TRUE)
private val COL_NOTIFICATION_BOOST =
ColumnMeta(columnList, 2, "notification_boost", ColumnMeta.TS_TRUE)
private val COL_NOTIFICATION_FAVOURITE =
ColumnMeta(columnList, 2, "notification_favourite", ColumnMeta.TS_TRUE)
private val COL_NOTIFICATION_FOLLOW =
ColumnMeta(columnList, 2, "notification_follow", ColumnMeta.TS_TRUE)
private val COL_NOTIFICATION_FOLLOW_REQUEST =
ColumnMeta(columnList, 44, "notification_follow_request", ColumnMeta.TS_TRUE)
private val COL_NOTIFICATION_REACTION = ColumnMeta(columnList, 33, "notification_reaction", ColumnMeta.TS_TRUE)
private val COL_NOTIFICATION_VOTE = ColumnMeta(columnList, 33, "notification_vote", ColumnMeta.TS_TRUE)
private val COL_NOTIFICATION_POST = ColumnMeta(columnList, 57, "notification_post", ColumnMeta.TS_TRUE)
private val COL_NOTIFICATION_REACTION =
ColumnMeta(columnList, 33, "notification_reaction", ColumnMeta.TS_TRUE)
private val COL_NOTIFICATION_VOTE =
ColumnMeta(columnList, 33, "notification_vote", ColumnMeta.TS_TRUE)
private val COL_NOTIFICATION_POST =
ColumnMeta(columnList, 57, "notification_post", ColumnMeta.TS_TRUE)
private val COL_CONFIRM_FOLLOW = ColumnMeta(columnList, 10, "confirm_follow", ColumnMeta.TS_TRUE)
private val COL_CONFIRM_FOLLOW_LOCKED = ColumnMeta(columnList, 10, "confirm_follow_locked", ColumnMeta.TS_TRUE)
private val COL_CONFIRM_UNFOLLOW = ColumnMeta(columnList, 10, "confirm_unfollow", ColumnMeta.TS_TRUE)
private val COL_CONFIRM_POST = ColumnMeta(columnList, 10, "confirm_post", ColumnMeta.TS_TRUE)
private val COL_CONFIRM_FAVOURITE = ColumnMeta(columnList, 23, "confirm_favourite", ColumnMeta.TS_TRUE)
private val COL_CONFIRM_UNBOOST = ColumnMeta(columnList, 24, "confirm_unboost", ColumnMeta.TS_TRUE)
private val COL_CONFIRM_UNFAVOURITE = ColumnMeta(columnList, 24, "confirm_unfavourite", ColumnMeta.TS_TRUE)
private val COL_CONFIRM_REACTION = ColumnMeta(columnList, 61, "confirm_reaction", ColumnMeta.TS_TRUE)
private val COL_CONFIRM_FOLLOW =
ColumnMeta(columnList, 10, "confirm_follow", ColumnMeta.TS_TRUE)
private val COL_CONFIRM_FOLLOW_LOCKED =
ColumnMeta(columnList, 10, "confirm_follow_locked", ColumnMeta.TS_TRUE)
private val COL_CONFIRM_UNFOLLOW =
ColumnMeta(columnList, 10, "confirm_unfollow", ColumnMeta.TS_TRUE)
private val COL_CONFIRM_POST =
ColumnMeta(columnList, 10, "confirm_post", ColumnMeta.TS_TRUE)
private val COL_CONFIRM_FAVOURITE =
ColumnMeta(columnList, 23, "confirm_favourite", ColumnMeta.TS_TRUE)
private val COL_CONFIRM_UNBOOST =
ColumnMeta(columnList, 24, "confirm_unboost", ColumnMeta.TS_TRUE)
private val COL_CONFIRM_UNFAVOURITE =
ColumnMeta(columnList, 24, "confirm_unfavourite", ColumnMeta.TS_TRUE)
private val COL_CONFIRM_REACTION =
ColumnMeta(columnList, 61, "confirm_reaction", ColumnMeta.TS_TRUE)
// スキーマ13から
val COL_NOTIFICATION_TAG = ColumnMeta(columnList, 13, "notification_server", ColumnMeta.TS_EMPTY)
val COL_NOTIFICATION_TAG =
ColumnMeta(columnList, 13, "notification_server", ColumnMeta.TS_EMPTY)
// スキーマ14から
val COL_REGISTER_KEY = ColumnMeta(columnList, 14, "register_key", ColumnMeta.TS_EMPTY)
@ -396,29 +415,40 @@ class SavedAccount(
private val COL_SOUND_URI = ColumnMeta(columnList, 16, "sound_uri", ColumnMeta.TS_EMPTY)
// スキーマ18から
private val COL_DONT_SHOW_TIMEOUT = ColumnMeta(columnList, 18, "dont_show_timeout", ColumnMeta.TS_ZERO)
private val COL_DONT_SHOW_TIMEOUT =
ColumnMeta(columnList, 18, "dont_show_timeout", ColumnMeta.TS_ZERO)
// スキーマ27から
private val COL_DEFAULT_TEXT = ColumnMeta(columnList, 27, "default_text", ColumnMeta.TS_EMPTY)
private val COL_DEFAULT_TEXT =
ColumnMeta(columnList, 27, "default_text", ColumnMeta.TS_EMPTY)
// スキーマ28から
private val COL_MISSKEY_VERSION = ColumnMeta(columnList, 28, "is_misskey", ColumnMeta.TS_ZERO)
private val COL_MISSKEY_VERSION =
ColumnMeta(columnList, 28, "is_misskey", ColumnMeta.TS_ZERO)
// カラム名がおかしいのは、昔はboolean扱いだったから
// 0: not misskey
// 1: old(v10) misskey
// 11: misskey v11
private val COL_DEFAULT_SENSITIVE = ColumnMeta(columnList, 38, "default_sensitive", ColumnMeta.TS_ZERO)
private val COL_DEFAULT_SENSITIVE =
ColumnMeta(columnList, 38, "default_sensitive", ColumnMeta.TS_ZERO)
private val COL_EXPAND_CW = ColumnMeta(columnList, 38, "expand_cw", ColumnMeta.TS_ZERO)
private val COL_MAX_TOOT_CHARS = ColumnMeta(columnList, 39, "max_toot_chars", ColumnMeta.TS_ZERO)
private val COL_MAX_TOOT_CHARS =
ColumnMeta(columnList, 39, "max_toot_chars", ColumnMeta.TS_ZERO)
private val COL_LAST_NOTIFICATION_ERROR = ColumnMeta(columnList, 42, "last_notification_error", "text")
private val COL_LAST_SUBSCRIPTION_ERROR = ColumnMeta(columnList, 45, "last_subscription_error", "text")
private val COL_LAST_PUSH_ENDPOINT = ColumnMeta(columnList, 46, "last_push_endpoint", "text")
private val COL_LAST_NOTIFICATION_ERROR =
ColumnMeta(columnList, 42, "last_notification_error", "text")
private val COL_LAST_SUBSCRIPTION_ERROR =
ColumnMeta(columnList, 45, "last_subscription_error", "text")
private val COL_LAST_PUSH_ENDPOINT =
ColumnMeta(columnList, 46, "last_push_endpoint", "text")
private val COL_IMAGE_RESIZE = ColumnMeta(columnList, 59, "image_resize", "text default null")
private val COL_IMAGE_MAX_MEGABYTES = ColumnMeta(columnList, 59, "image_max_megabytes", "text default null")
private val COL_MOVIE_MAX_MEGABYTES = ColumnMeta(columnList, 59, "movie_max_megabytes", "text default null")
private val COL_IMAGE_RESIZE =
ColumnMeta(columnList, 59, "image_resize", "text default null")
private val COL_IMAGE_MAX_MEGABYTES =
ColumnMeta(columnList, 59, "image_max_megabytes", "text default null")
private val COL_MOVIE_MAX_MEGABYTES =
ColumnMeta(columnList, 59, "movie_max_megabytes", "text default null")
private val COL_PUSH_POLICY = ColumnMeta(columnList, 60, "push_policy", "text default null")
@ -563,7 +593,10 @@ class SavedAccount(
} catch (ex: Throwable) {
log.trace(ex)
log.e(ex, "loadAccountList failed.")
context.showToast(true, ex.withCaption("(SubwayTooter) broken in-app database?"))
context.showToast(
true,
ex.withCaption("(SubwayTooter) broken in-app database?")
)
}
}
@ -827,7 +860,14 @@ class SavedAccount(
this.loginAccount = ta
ContentValues().apply {
put(COL_ACCOUNT, result.jsonObject.toString())
}.let { App1.database.update(table, it, "$COL_ID=?", arrayOf(db_id.toString())) }
}.let {
App1.database.update(
table,
it,
"$COL_ID=?",
arrayOf(db_id.toString())
)
}
PollingWorker.queueUpdateNotification(context)
}
}

View File

@ -13,7 +13,7 @@ object SubscriptionServerKey : TableCompanion {
private val log = LogCategory("ServerKey")
private const val table = "subscription_server_key2"
override val table = "subscription_server_key2"
private const val COL_ID = BaseColumns._ID
private const val COL_CLIENT_IDENTIFIER = "ci"
private const val COL_SERVER_KEY = "sk"

View File

@ -2,18 +2,16 @@ package jp.juggler.subwaytooter.table
import android.content.ContentValues
import android.database.sqlite.SQLiteDatabase
import java.util.ArrayList
import jp.juggler.subwaytooter.App1
import jp.juggler.util.LogCategory
import jp.juggler.util.TableCompanion
import java.util.*
object TagSet : TableCompanion {
private val log = LogCategory("TagSet")
private const val table = "tag_set"
override val table = "tag_set"
private const val COL_TIME_SAVE = "time_save"
private const val COL_TAG = "tag" // タグ。先頭の#を含まない

View File

@ -48,7 +48,7 @@ class UserRelation {
private val log = LogCategory("UserRelationMisskey")
private const val table = "user_relation_misskey"
override val table = "user_relation_misskey"
val columnList: ColumnMeta.List = ColumnMeta.List(table, 30).apply {
createExtra = {
@ -60,7 +60,8 @@ class UserRelation {
deleteBeforeCreate = true
}
val COL_ID = ColumnMeta(columnList, 0, BaseColumns._ID, "INTEGER PRIMARY KEY", primary = true)
val COL_ID =
ColumnMeta(columnList, 0, BaseColumns._ID, "INTEGER PRIMARY KEY", primary = true)
private val COL_TIME_SAVE = ColumnMeta(columnList, 0, "time_save", "integer not null")
// SavedAccount のDB_ID。 疑似アカウント用のエントリは -2L
@ -73,10 +74,12 @@ class UserRelation {
private val COL_BLOCKING = ColumnMeta(columnList, 0, "blocking", "integer not null")
private val COL_MUTING = ColumnMeta(columnList, 0, "muting", "integer not null")
private val COL_REQUESTED = ColumnMeta(columnList, 0, "requested", "integer not null")
private val COL_FOLLOWING_REBLOGS = ColumnMeta(columnList, 0, "following_reblogs", "integer not null")
private val COL_FOLLOWING_REBLOGS =
ColumnMeta(columnList, 0, "following_reblogs", "integer not null")
private val COL_ENDORSED = ColumnMeta(columnList, 32, "endorsed", "integer default 0")
private val COL_BLOCKED_BY = ColumnMeta(columnList, 34, "blocked_by", "integer default 0")
private val COL_REQUESTED_BY = ColumnMeta(columnList, 35, "requested_by", "integer default 0")
private val COL_REQUESTED_BY =
ColumnMeta(columnList, 35, "requested_by", "integer default 0")
private val COL_NOTE = ColumnMeta(columnList, 55, "note", "text default null")
private val COL_NOTIFYING = ColumnMeta(columnList, 58, "notifying", "integer default 0")

View File

@ -17,6 +17,8 @@ import jp.juggler.apng.ApngFrames
import jp.juggler.subwaytooter.App1
import jp.juggler.util.LogCategory
import jp.juggler.util.TableCompanion
import jp.juggler.util.getBlobOrNull
import jp.juggler.util.getLong
import kotlinx.coroutines.channels.Channel
import java.io.ByteArrayInputStream
import java.lang.ref.WeakReference
@ -55,7 +57,7 @@ class CustomEmojiCache(
companion object : TableCompanion {
const val table = "custom_emoji_cache"
override val table = "custom_emoji_cache"
const val COL_ID = BaseColumns._ID
const val COL_TIME_SAVE = "time_save"
@ -91,9 +93,9 @@ class CustomEmojiCache(
)?.use { cursor ->
if (cursor.moveToNext()) {
DbCache(
id = cursor.getLong(cursor.getColumnIndex(COL_ID)),
timeUsed = cursor.getLong(cursor.getColumnIndex(COL_TIME_USED)),
data = cursor.getBlob(cursor.getColumnIndex(COL_DATA))
id = cursor.getLong(COL_ID),
timeUsed = cursor.getLong(COL_TIME_USED),
data = cursor.getBlobOrNull(COL_DATA)!!
).apply {
if (now - timeUsed >= 5 * 3600000L) {
db.update(

View File

@ -52,9 +52,16 @@ fun Cursor.getStringOrNull(keyIdx: Int) =
fun Cursor.getStringOrNull(key: String) =
getStringOrNull(getColumnIndex(key))
fun Cursor.getBlobOrNull(keyIdx: Int) =
if (isNull(keyIdx)) null else getBlob(keyIdx)
fun Cursor.getBlobOrNull(key: String) =
getBlobOrNull(getColumnIndex(key))
/////////////////////////////////////////////////////////////
interface TableCompanion {
val table: String
fun onDBCreate(db: SQLiteDatabase)
fun onDBUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int)
}

View File

@ -0,0 +1,23 @@
package jp.juggler.subwaytooter
import org.junit.Assert.assertEquals
import org.junit.Test
class TestArrayListSizeBug {
@Test
fun testArrayListSize() {
val list = ArrayList(arrayOf("c", "b", "a").toList())
assertEquals("ArrayList size", 3, list.size)
}
class ArrayListDerived<E>(args: List<E>) : ArrayList<E>(args)
@Test
fun testArrayListDerived() {
val list = ArrayListDerived(arrayOf("c", "b", "a").toList())
assertEquals("ArrayListDerived size", 3, list.size)
// kotlin 1.5.31で(Javaの) size() ではなく getSize() にアクセスしようとして例外を出していた
// kotlin 1.5.30では大丈夫だったが、JetPack Composeは 1.5.31を要求するのだった…。
}
}

View File

@ -8,7 +8,7 @@ buildscript {
ext.lifecycle_version="2.4.0-rc01"
ext.arch_version = "2.1.0"
ext.kotlin_version = '1.5.31'
ext.kotlin_version = '1.5.30'
ext.kotlinx_coroutines_version = '1.5.2'
ext.anko_version='0.10.8'

Binary file not shown.

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

294
gradlew vendored
View File

@ -1,74 +1,129 @@
#!/usr/bin/env bash
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
##
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
MAX_FD=maximum
warn () {
echo "$*"
}
} >&2
die () {
echo
echo "$*"
echo
exit 1
}
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD="$JAVA_HOME/bin/java"
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@ -77,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
@ -85,76 +140,95 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

53
gradlew.bat vendored
View File

@ -1,3 +1,19 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@ -8,20 +24,23 @@
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@ -35,7 +54,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@ -45,34 +64,14 @@ echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell