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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ dependencies {
implementation group: "com.fasterxml.uuid", name: "java-uuid-generator", version: uuidGeneratorVersion
implementation group: "org.jetbrains.kotlin", name: "kotlin-stdlib-jdk8"
implementation group: "org.jetbrains.kotlin", name: "kotlin-reflect"
implementation group: "com.vdurmont", name: "emoji-java", version: emojiVersion

testImplementation group: "com.nhaarman.mockitokotlin2", name: "mockito-kotlin", version: mockitoKotlinVersion
testImplementation group: "org.assertj", name: "assertj-core", version: assertjVersion
Expand Down
1 change: 1 addition & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ kotlin.code.style = official
assertjVersion = 3.8.0
assertjSwingVersion = 3.8.0
detektVersion = 1.4.0
emojiVersion = 5.1.1
intellijVersion = 2019.3
junitVersion = 5.5.2
junitRunnerVersion = 1.5.2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import com.fwdekker.randomness.DataSettingsAction
import com.fwdekker.randomness.array.ArrayScheme
import com.fwdekker.randomness.array.ArraySettings
import com.fwdekker.randomness.array.ArraySettingsAction
import com.vdurmont.emoji.EmojiParser
import icons.RandomnessIcons


Expand Down Expand Up @@ -65,14 +66,14 @@ class StringInsertAction(private val scheme: StringScheme = StringSettings.defau
* @throws DataGenerationException if a random character could not be generated
*/
@Throws(DataGenerationException::class)
private fun generateCharacter(): Char {
private fun generateCharacter(): String {
val symbolSet = scheme.activeSymbolSetList.sum(scheme.excludeLookAlikeSymbols)
if (symbolSet.isEmpty())
throw DataGenerationException("No valid symbols found in active symbol sets.")

val charIndex = random.nextInt(symbolSet.length)

return symbolSet[charIndex]
val symbolList =
EmojiParser.extractEmojis(symbolSet) + EmojiParser.removeAllEmojis(symbolSet).map { it.toString() }
return symbolList[random.nextInt(symbolList.size)]
}


Expand Down
15 changes: 11 additions & 4 deletions src/main/kotlin/com/fwdekker/randomness/string/SymbolSet.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.fwdekker.randomness.string

import com.vdurmont.emoji.EmojiParser


/**
* A `SymbolSet` represents a named collection of symbols.
Expand Down Expand Up @@ -82,12 +84,17 @@ fun Map<String, String>.toSymbolSets() = this.map { (name, symbols) -> SymbolSet
/**
* Concatenates the symbols of all the symbol sets, removing duplicate characters.
*
* This method respects emoji sequences and will not remove duplicate characters if these characters are essential to
* displaying the embedded emoji correctly.
*
* @param excludeLookAlikeSymbols whether to remove symbols that occur in [SymbolSet.lookAlikeCharacters]
* @return the concatenation of all symbols of all the symbol sets, excluding duplicate characters
*/
fun Iterable<SymbolSet>.sum(excludeLookAlikeSymbols: Boolean = false) =
this.fold("") { acc, symbolSet -> acc + symbolSet.symbols }.toSet().joinToString("")
.let { sum ->
if (excludeLookAlikeSymbols) sum.filterNot { it in SymbolSet.lookAlikeCharacters }
else sum
this.fold("") { acc, symbolSet -> acc + symbolSet.symbols }
.let { Pair(EmojiParser.extractEmojis(it).distinct(), EmojiParser.removeAllEmojis(it).toList().distinct()) }
.let { (emoji, noEmoji) ->
emoji.joinToString("") +
(if (excludeLookAlikeSymbols) noEmoji.filterNot { it in SymbolSet.lookAlikeCharacters }
else noEmoji).joinToString("")
}
1 change: 1 addition & 0 deletions src/main/resources/META-INF/change-notes.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<li>Exclude look-alike characters in string settings if you don't want them.</li>
<li>Opening the Randomness popup without an editor will display settings-related actions only.</li>
<li>Slightly friendlier and more accurate error messages for tables.</li>
<li>Symbol sets now support emoji. Note that IntelliJ doesn't actually display modifiers that well.</li>
</ul>

<b>Fixes</b>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,19 @@ class StringInsertActionTest : Spek({
assertThat(insertRandomString.generateString()).containsPattern(expectedPattern)
}
}

it("retains emoji modifiers in the right order") {
val emoji = "👩‍👩‍👧‍👧"
val stringScheme = StringScheme(
minLength = 1,
maxLength = 1,
enclosure = "",
capitalization = CapitalizationMode.RETAIN,
activeSymbolSets = setOf(SymbolSet("emoji", "👩‍👩‍👧‍👧")).toMap()
)

assertThat(StringInsertAction(stringScheme).generateString()).isEqualTo(emoji)
}
}

describe("error handling") {
Expand Down
12 changes: 12 additions & 0 deletions src/test/kotlin/com/fwdekker/randomness/string/SymbolSetTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,18 @@ object SymbolSetTest : Spek({
it("removes look-alike symbols if the option is given") {
assertThat(listOf(SymbolSet("set", "a" + SymbolSet.lookAlikeCharacters)).sum(true)).isEqualTo("a")
}

it("retains emoji with modifiers") {
assertThat(listOf(SymbolSet("emoji", "a👨‍💼b")).sum()).isEqualTo("👨‍💼ab")
}

it("retains duplicate characters in emoji") {
assertThat(listOf(SymbolSet("emoji", "🇦🇶🇦")).sum()).isEqualTo("🇦🇶🇦")
}

it("removes duplicate emoji") {
assertThat(listOf(SymbolSet("emoji", "🇦🇶😀🇦🇶😀")).sum()).isEqualTo("🇦🇶😀")
}
}
}
})