diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/rules/HighlightRule.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/rules/HighlightRule.kt index 38f0a33ef68a2c7d927b13b5ba9bade7872b5f0f..4b6fadafb46331d60f093c0ee4889a73ecfb222d 100644 --- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/rules/HighlightRule.kt +++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/models/rules/HighlightRule.kt @@ -13,7 +13,7 @@ import de.justjanne.libquassel.protocol.util.expression.ExpressionMatch data class HighlightRule( val id: Int, - val contents: String, + val content: String, val isRegEx: Boolean = false, val isCaseSensitive: Boolean = false, val isEnabled: Boolean = true, @@ -22,7 +22,7 @@ data class HighlightRule( val channel: String ) { val contentMatch = ExpressionMatch( - contents, + content, if (isRegEx) ExpressionMatch.MatchMode.MatchRegEx else ExpressionMatch.MatchMode.MatchPhrase, isCaseSensitive diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/HighlightRuleManager.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/HighlightRuleManager.kt index 394d9d26bdfd1996ef5cafc8c96d9e5b7c39a807..f32fdbb66960a8169b25d5f3dd85d7fd3d3131f1 100644 --- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/HighlightRuleManager.kt +++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/HighlightRuleManager.kt @@ -59,9 +59,6 @@ open class HighlightRuleManager( require(idList.size == channelList.size) { "Sizes do not match: ids=${idList.size}, channelList=${channelList.size}" } - require(idList.size == channelList.size) { - "Sizes do not match: ids=${idList.size}, channelList=${channelList.size}" - } state.update { copy( @@ -93,7 +90,7 @@ open class HighlightRuleManager( QtType.QVariantList ), "name" to qVariant( - state().rules.map(HighlightRule::contents), + state().rules.map(HighlightRule::content), QtType.QStringList ), "isRegEx" to qVariant( @@ -134,7 +131,7 @@ open class HighlightRuleManager( fun count() = state().count() fun removeAt(index: Int) { state.update { - copy(rules = rules.drop(index)) + copy(rules = rules.take(index) + rules.drop(index + 1)) } } @@ -157,13 +154,13 @@ open class HighlightRuleManager( override fun addHighlightRule( id: Int, - name: String?, + content: String?, isRegEx: Boolean, isCaseSensitive: Boolean, isEnabled: Boolean, isInverse: Boolean, sender: String?, - chanName: String? + channel: String? ) { if (contains(id)) { return @@ -173,18 +170,18 @@ open class HighlightRuleManager( copy( rules = rules + HighlightRule( id, - name ?: "", + content ?: "", isRegEx, isCaseSensitive, isEnabled, isInverse, sender ?: "", - chanName ?: "" + channel ?: "" ) ) } - super.addHighlightRule(id, name, isRegEx, isCaseSensitive, isEnabled, isInverse, sender, chanName) + super.addHighlightRule(id, content, isRegEx, isCaseSensitive, isEnabled, isInverse, sender, channel) } override fun setHighlightNick(highlightNick: Int) { diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/stubs/HighlightRuleManagerStub.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/stubs/HighlightRuleManagerStub.kt index 118b56969e0240bfd7f8846b0bfd787f012c2336..9ebac411d98238ca8d086b77b5d9d6af4e165bc3 100644 --- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/stubs/HighlightRuleManagerStub.kt +++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/stubs/HighlightRuleManagerStub.kt @@ -58,50 +58,50 @@ interface HighlightRuleManagerStub : SyncableStub { @SyncedCall(target = ProtocolSide.CORE) fun requestAddHighlightRule( id: Int, - name: String?, + content: String?, isRegEx: Boolean, isCaseSensitive: Boolean, isEnabled: Boolean, isInverse: Boolean, sender: String?, - chanName: String? + channel: String? ) { sync( target = ProtocolSide.CORE, "requestToggleHighlightRule", qVariant(id, QtType.Int), - qVariant(name, QtType.QString), + qVariant(content, QtType.QString), qVariant(isRegEx, QtType.Bool), qVariant(isCaseSensitive, QtType.Bool), qVariant(isEnabled, QtType.Bool), qVariant(isInverse, QtType.Bool), qVariant(sender, QtType.QString), - qVariant(chanName, QtType.QString), + qVariant(channel, QtType.QString), ) } @SyncedCall(target = ProtocolSide.CLIENT) fun addHighlightRule( id: Int, - name: String?, + content: String?, isRegEx: Boolean, isCaseSensitive: Boolean, isEnabled: Boolean, isInverse: Boolean, sender: String?, - chanName: String? + channel: String? ) { sync( target = ProtocolSide.CLIENT, "addHighlightRule", qVariant(id, QtType.Int), - qVariant(name, QtType.QString), + qVariant(content, QtType.QString), qVariant(isRegEx, QtType.Bool), qVariant(isCaseSensitive, QtType.Bool), qVariant(isEnabled, QtType.Bool), qVariant(isInverse, QtType.Bool), qVariant(sender, QtType.QString), - qVariant(chanName, QtType.QString), + qVariant(channel, QtType.QString), ) } diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/syncables/HighlightRuleManagerTest.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/syncables/HighlightRuleManagerTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..9180494f3a40b749daf0699cac916d3a911709b1 --- /dev/null +++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/syncables/HighlightRuleManagerTest.kt @@ -0,0 +1,405 @@ +/* + * libquassel + * Copyright (c) 2021 Janne Mareike Koschinski + * + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at https://mozilla.org/MPL/2.0/. + */ + +package de.justjanne.libquassel.protocol.syncables + +import de.justjanne.libquassel.protocol.models.QStringList +import de.justjanne.libquassel.protocol.models.rules.HighlightNickType +import de.justjanne.libquassel.protocol.models.rules.HighlightRule +import de.justjanne.libquassel.protocol.models.types.QtType +import de.justjanne.libquassel.protocol.syncables.state.HighlightRuleManagerState +import de.justjanne.libquassel.protocol.testutil.nextEnum +import de.justjanne.libquassel.protocol.testutil.nextHighlightRule +import de.justjanne.libquassel.protocol.variant.QVariantList +import de.justjanne.libquassel.protocol.variant.QVariantMap +import de.justjanne.libquassel.protocol.variant.qVariant +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertFalse +import org.junit.jupiter.api.Assertions.assertNotEquals +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import kotlin.random.Random + +class HighlightRuleManagerTest { + @Test + fun testEmpty() { + val state = HighlightRuleManagerState() + val actual = HighlightRuleManager(state = state).apply { + update(emptyMap()) + }.state() + + assertEquals(state, actual) + } + + @Test + fun testInvalidData() { + val state = HighlightRuleManagerState() + val actual = HighlightRuleManager(state = state).apply { + assertThrows<IllegalArgumentException> { + update( + mapOf( + "HighlightRuleList" to qVariant<QVariantMap>( + mapOf( + "id" to qVariant<QVariantList>(emptyList(), QtType.QVariantList), + "name" to qVariant<QStringList>(listOf(""), QtType.QStringList), + ), QtType.QVariantMap + ) + ) + ) + } + assertThrows<IllegalArgumentException> { + update( + mapOf( + "HighlightRuleList" to qVariant<QVariantMap>( + mapOf( + "id" to qVariant<QVariantList>(emptyList(), QtType.QVariantList), + "isRegEx" to qVariant<QVariantList>(listOf( + qVariant(false, QtType.Bool) + ), QtType.QVariantList), + ), QtType.QVariantMap + ) + ) + ) + } + assertThrows<IllegalArgumentException> { + update( + mapOf( + "HighlightRuleList" to qVariant<QVariantMap>( + mapOf( + "id" to qVariant<QVariantList>(emptyList(), QtType.QVariantList), + "isCaseSensitive" to qVariant<QVariantList>(listOf( + qVariant(false, QtType.Bool) + ), QtType.QVariantList), + ), QtType.QVariantMap + ) + ) + ) + } + assertThrows<IllegalArgumentException> { + update( + mapOf( + "HighlightRuleList" to qVariant<QVariantMap>( + mapOf( + "id" to qVariant<QVariantList>(emptyList(), QtType.QVariantList), + "isEnabled" to qVariant<QVariantList>(listOf( + qVariant(false, QtType.Bool) + ), QtType.QVariantList), + ), QtType.QVariantMap + ) + ) + ) + } + assertThrows<IllegalArgumentException> { + update( + mapOf( + "HighlightRuleList" to qVariant<QVariantMap>( + mapOf( + "id" to qVariant<QVariantList>(emptyList(), QtType.QVariantList), + "isInverse" to qVariant<QVariantList>(listOf( + qVariant(false, QtType.Bool) + ), QtType.QVariantList), + ), QtType.QVariantMap + ) + ) + ) + } + assertThrows<IllegalArgumentException> { + update( + mapOf( + "HighlightRuleList" to qVariant<QVariantMap>( + mapOf( + "id" to qVariant<QVariantList>(emptyList(), QtType.QVariantList), + "sender" to qVariant<QStringList>(listOf(""), QtType.QStringList), + ), QtType.QVariantMap + ) + ) + ) + } + assertThrows<IllegalArgumentException> { + update( + mapOf( + "HighlightRuleList" to qVariant<QVariantMap>( + mapOf( + "id" to qVariant<QVariantList>(emptyList(), QtType.QVariantList), + "channel" to qVariant<QStringList>(listOf(""), QtType.QStringList), + ), QtType.QVariantMap + ) + ) + ) + } + }.state() + + assertEquals(state, actual) + } + + @Test + fun testNulLData() { + val random = Random(1337) + val actual = HighlightRuleManager( + state = HighlightRuleManagerState() + ).apply { + update(mapOf( + "HighlightRuleList" to qVariant(mapOf( + "id" to qVariant(listOf( + qVariant(999, QtType.Int) + ), QtType.QVariantList), + "name" to qVariant(listOf( + null + ), QtType.QStringList), + "isRegEx" to qVariant(listOf( + qVariant(false, QtType.Bool) + ), QtType.QVariantList), + "isCaseSensitive" to qVariant(listOf( + qVariant(false, QtType.Bool) + ), QtType.QVariantList), + "isEnabled" to qVariant(listOf( + qVariant(false, QtType.Bool) + ), QtType.QVariantList), + "isInverse" to qVariant(listOf( + qVariant(false, QtType.Bool) + ), QtType.QVariantList), + "sender" to qVariant(listOf( + null + ), QtType.QStringList), + "channel" to qVariant(listOf( + null + ), QtType.QStringList) + ), QtType.QVariantMap) + )) + }.state() + + assertEquals(HighlightRule( + id = 999, + content = "", + isRegEx = false, + isCaseSensitive = false, + isEnabled = false, + isInverse = false, + sender = "", + channel = "" + ), actual.rules.first()) + } + + @Test + fun testSerialization() { + val random = Random(1337) + val expected = HighlightRuleManagerState( + rules = List(random.nextInt(20)) { + random.nextHighlightRule(it) + }, + highlightNickType = random.nextEnum(), + highlightNickCaseSensitive = random.nextBoolean() + ) + + val actual = HighlightRuleManager( + state = HighlightRuleManagerState() + ).apply { + update(HighlightRuleManager(state = expected).toVariantMap()) + }.state() + + assertEquals(expected, actual) + } + + @Nested + inner class Setters { + @Test + fun testRemoveHighlightRule() { + val random = Random(1337) + val value = HighlightRuleManager( + state = HighlightRuleManagerState( + rules = List(random.nextInt(20)) { + random.nextHighlightRule(it) + }, + highlightNickType = random.nextEnum(), + highlightNickCaseSensitive = random.nextBoolean() + ) + ) + + val rule = value.state().rules.random(random) + assertTrue(value.contains(rule.id)) + assertNotEquals(-1, value.indexOf(rule.id)) + value.removeHighlightRule(rule.id) + assertFalse(value.contains(rule.id)) + assertEquals(-1, value.indexOf(rule.id)) + } + + @Test + fun testRemoveAll() { + val random = Random(1337) + val value = HighlightRuleManager( + state = HighlightRuleManagerState( + rules = List(random.nextInt(20)) { + random.nextHighlightRule(it) + }, + highlightNickType = random.nextEnum(), + highlightNickCaseSensitive = random.nextBoolean() + ) + ) + + assertFalse(value.isEmpty()) + for (rule in value.state().rules) { + value.removeHighlightRule(rule.id) + } + assertTrue(value.isEmpty()) + assertEquals(0, value.count()) + } + + @Test + fun testToggleHighlightRule() { + val random = Random(1337) + val value = HighlightRuleManager( + state = HighlightRuleManagerState( + rules = List(random.nextInt(20)) { + random.nextHighlightRule(it) + }, + highlightNickType = random.nextEnum(), + highlightNickCaseSensitive = random.nextBoolean() + ) + ) + + val rule = value.state().rules.random(random) + assertTrue(value.contains(rule.id)) + assertNotEquals(-1, value.indexOf(rule.id)) + assertFalse(value.state().rules[value.indexOf(rule.id)].isEnabled) + value.toggleHighlightRule(rule.id) + assertTrue(value.contains(rule.id)) + assertNotEquals(-1, value.indexOf(rule.id)) + assertTrue(value.state().rules[value.indexOf(rule.id)].isEnabled) + value.toggleHighlightRule(rule.id) + assertTrue(value.contains(rule.id)) + assertNotEquals(-1, value.indexOf(rule.id)) + assertFalse(value.state().rules[value.indexOf(rule.id)].isEnabled) + } + + @Test + fun testHighlightNick() { + val random = Random(1337) + val value = HighlightRuleManager( + state = HighlightRuleManagerState( + rules = List(random.nextInt(20)) { + random.nextHighlightRule(it) + }, + highlightNickType = random.nextEnum(), + highlightNickCaseSensitive = random.nextBoolean() + ) + ) + + assertEquals(HighlightNickType.AllNicks, value.state().highlightNickType) + value.setHighlightNick(HighlightNickType.CurrentNick.value) + assertEquals(HighlightNickType.CurrentNick, value.state().highlightNickType) + value.setHighlightNick(-2) + assertEquals(HighlightNickType.CurrentNick, value.state().highlightNickType) + } + + @Test + fun testNicksCaseSensitive() { + val random = Random(1337) + val value = HighlightRuleManager( + state = HighlightRuleManagerState( + rules = List(random.nextInt(20)) { + random.nextHighlightRule(it) + }, + highlightNickType = random.nextEnum(), + highlightNickCaseSensitive = random.nextBoolean() + ) + ) + + value.setNicksCaseSensitive(false) + assertEquals(false, value.state().highlightNickCaseSensitive) + value.setNicksCaseSensitive(true) + assertEquals(true, value.state().highlightNickCaseSensitive) + } + + @Test + fun testAddExisting() { + val random = Random(1337) + val value = HighlightRuleManager( + state = HighlightRuleManagerState( + rules = List(random.nextInt(20)) { + random.nextHighlightRule(it) + }, + highlightNickType = random.nextEnum(), + highlightNickCaseSensitive = random.nextBoolean() + ) + ) + + val rule = value.state().rules.random(random) + val sizeBefore = value.count() + value.addHighlightRule( + id = rule.id, + content = rule.content, + isRegEx = rule.isRegEx, + isCaseSensitive = rule.isCaseSensitive, + isEnabled = rule.isEnabled, + isInverse = rule.isInverse, + sender = rule.sender, + channel = rule.channel + ) + assertEquals(sizeBefore, value.count()) + } + + @Test + fun testAddNew() { + val random = Random(1337) + val value = HighlightRuleManager( + state = HighlightRuleManagerState( + rules = List(random.nextInt(20)) { + random.nextHighlightRule(it) + }, + highlightNickType = random.nextEnum(), + highlightNickCaseSensitive = random.nextBoolean() + ) + ) + + val rule = random.nextHighlightRule(value.count()) + val sizeBefore = value.count() + value.addHighlightRule( + id = rule.id, + content = rule.content, + isRegEx = rule.isRegEx, + isCaseSensitive = rule.isCaseSensitive, + isEnabled = rule.isEnabled, + isInverse = rule.isInverse, + sender = rule.sender, + channel = rule.channel + ) + assertEquals(sizeBefore + 1, value.count()) + } + + @Test + fun testAddEdgeCase() { + val random = Random(1337) + val value = HighlightRuleManager( + state = HighlightRuleManagerState( + rules = List(random.nextInt(20)) { + random.nextHighlightRule(it) + }, + highlightNickType = random.nextEnum(), + highlightNickCaseSensitive = random.nextBoolean() + ) + ) + + val rule = random.nextHighlightRule(value.count()) + val sizeBefore = value.count() + value.addHighlightRule( + id = rule.id, + content = null, + isRegEx = rule.isRegEx, + isCaseSensitive = rule.isCaseSensitive, + isEnabled = rule.isEnabled, + isInverse = rule.isInverse, + sender = null, + channel = null + ) + assertEquals(sizeBefore + 1, value.count()) + } + } +} diff --git a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/Random.kt b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/Random.kt index 80766aaab4263812a67af3d21e224e18b1fbc576..4575d537f3ed7f6e657039a15a10d0895a9620dc 100644 --- a/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/Random.kt +++ b/libquassel-protocol/src/test/kotlin/de/justjanne/libquassel/protocol/testutil/Random.kt @@ -16,6 +16,8 @@ import de.justjanne.libquassel.protocol.models.ids.BufferId import de.justjanne.libquassel.protocol.models.ids.IdentityId import de.justjanne.libquassel.protocol.models.ids.NetworkId import de.justjanne.libquassel.protocol.models.network.NetworkServer +import de.justjanne.libquassel.protocol.models.rules.HighlightRule +import de.justjanne.libquassel.protocol.models.rules.IgnoreRule import de.justjanne.libquassel.protocol.syncables.BufferViewConfig import de.justjanne.libquassel.protocol.syncables.IrcChannel import de.justjanne.libquassel.protocol.syncables.IrcUser @@ -184,3 +186,24 @@ fun Random.nextBufferViewManager() = BufferViewManagerState( BufferViewConfig(state = BufferViewConfigState(bufferViewId = nextInt())) }.associateBy(BufferViewConfig::bufferViewId) ) + +fun Random.nextHighlightRule(id: Int) = HighlightRule( + id = id, + content = nextString(), + isRegEx = nextBoolean(), + isCaseSensitive = nextBoolean(), + isEnabled = nextBoolean(), + isInverse = nextBoolean(), + sender = nextString(), + channel = nextString() +) + +fun Random.nextIgnoreRule() = IgnoreRule( + type = nextEnum(), + ignoreRule = nextString(), + isRegEx = nextBoolean(), + strictness = nextEnum(), + isEnabled = nextBoolean(), + scope = nextEnum(), + scopeRule = nextString() +)