mirror of https://github.com/tuskyapp/Tusky.git
Browse Source
* Allow any String IDs as long as they're sortable * Allow any String IDs as long as they're sortablepull/1027/head
12 changed files with 148 additions and 73 deletions
@ -1,17 +0,0 @@
|
||||
package com.keylesspalace.tusky.util; |
||||
|
||||
import java.util.Random; |
||||
|
||||
public class StringUtils { |
||||
|
||||
public static String randomAlphanumericString(int count) { |
||||
char[] chars = new char[count]; |
||||
Random random = new Random(); |
||||
final String POSSIBLE_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; |
||||
for (int i = 0; i < count; i++) { |
||||
chars[i] = POSSIBLE_CHARS.charAt(random.nextInt(POSSIBLE_CHARS.length())); |
||||
} |
||||
return new String(chars); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,72 @@
|
||||
@file:JvmName("StringUtils") |
||||
|
||||
package com.keylesspalace.tusky.util |
||||
|
||||
import java.util.Random |
||||
|
||||
|
||||
private const val POSSIBLE_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
||||
|
||||
fun randomAlphanumericString(count: Int): String { |
||||
val chars = CharArray(count) |
||||
val random = Random() |
||||
for (i in 0 until count) { |
||||
chars[i] = POSSIBLE_CHARS[random.nextInt(POSSIBLE_CHARS.length)] |
||||
} |
||||
return String(chars) |
||||
} |
||||
|
||||
// We sort statuses by ID. Something we need to invent some ID for placeholder. |
||||
// Not sure if inc()/dec() should be made `operator` or not |
||||
|
||||
/** |
||||
* "Increment" string so that during sorting it's bigger than [this]. |
||||
*/ |
||||
fun String.inc(): String { |
||||
// We assume that we will stay in the safe range for now |
||||
val builder = this.toCharArray() |
||||
builder.last().inc() |
||||
return String(builder) |
||||
} |
||||
|
||||
|
||||
/** |
||||
* "Decrement" string so that during sorting it's smaller than [this]. |
||||
*/ |
||||
fun String.dec(): String { |
||||
val builder = this.toCharArray() |
||||
var i = builder.lastIndex |
||||
while (i > 0) { |
||||
if (builder[i] > '0') { |
||||
builder[i] = builder[i].dec() |
||||
break |
||||
} else { |
||||
builder[i] = 'z' |
||||
} |
||||
i-- |
||||
} |
||||
// All characters were '0' |
||||
if (i == 0 && this.isNotEmpty()) { |
||||
// Remove one character |
||||
return String(builder.copyOfRange(1, builder.size)) |
||||
} |
||||
|
||||
return String(builder) |
||||
} |
||||
|
||||
/** |
||||
* A < B (strictly) by length and then by content. |
||||
* Examples: |
||||
* "abc" < "bcd" |
||||
* "ab" < "abc" |
||||
* "cb" < "abc" |
||||
* not: "ab" < "ab" |
||||
* not: "abc" > "cb" |
||||
*/ |
||||
fun String.isLessThan(other: String): Boolean { |
||||
return when { |
||||
this.length < other.length -> true |
||||
this.length > other.length -> false |
||||
else -> this < other |
||||
} |
||||
} |
||||
@ -0,0 +1,34 @@
|
||||
package com.keylesspalace.tusky |
||||
|
||||
import com.keylesspalace.tusky.util.dec |
||||
import com.keylesspalace.tusky.util.isLessThan |
||||
import org.junit.Assert.* |
||||
import org.junit.Test |
||||
|
||||
class StringUtilsTest { |
||||
@Test |
||||
fun isLessThan() { |
||||
val lessList = listOf( |
||||
"abc" to "bcd", |
||||
"ab" to "abc", |
||||
"cb" to "abc" |
||||
) |
||||
lessList.forEach { (l, r) -> assertTrue("$l < $r", l.isLessThan(r)) } |
||||
val notLessList = lessList.map { (l, r) -> r to l } + listOf( |
||||
"abc" to "abc" |
||||
) |
||||
notLessList.forEach { (l, r) -> assertFalse("not $l < $r", l.isLessThan(r)) } |
||||
} |
||||
|
||||
@Test |
||||
fun dec() { |
||||
listOf( |
||||
"123" to "122", |
||||
"12B" to "12A", |
||||
"120" to "11z", |
||||
"100" to "zz", |
||||
"0" to "", |
||||
"" to "" |
||||
).forEach { (l, r) -> assertEquals("$l - 1 = $r", r, l.dec()) } |
||||
} |
||||
} |
||||
Loading…
Reference in new issue