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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog
## Unreleased
### Added
* Added ability to generate non-matching strings.
([#447](https://github.com/FWDekker/intellij-randomness/issues/447))

### Changed
* When inserting arrays at multiple carets, the number of elements per array is now independently chosen for each array.
([#450](https://github.com/FWDekker/intellij-randomness/issues/450))
Expand Down
24 changes: 18 additions & 6 deletions src/main/kotlin/com/fwdekker/randomness/string/StringScheme.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,17 @@ import kotlin.random.asJavaRandom
*
* @property pattern The regex-like pattern according to which the string is generated.
* @property isRegex `true` if and only if [pattern] should be interpreted as a regex.
* @property removeLookAlikeSymbols Whether the symbols in [LOOK_ALIKE_CHARACTERS] should be removed.
* @property isNonMatching `true` if and only if non-matching values should be generated if [isRegex] is `true`.
* @property capitalization The capitalization mode of the generated string.
* @property removeLookAlikeSymbols Whether the symbols in [LOOK_ALIKE_CHARACTERS] should be removed.
* @property arrayDecorator Settings that determine whether the output should be an array of values.
*/
data class StringScheme(
var pattern: String = DEFAULT_PATTERN,
var isRegex: Boolean = DEFAULT_IS_REGEX,
var removeLookAlikeSymbols: Boolean = DEFAULT_REMOVE_LOOK_ALIKE_SYMBOLS,
var isNonMatching: Boolean = DEFAULT_IS_NON_MATCHING,
var capitalization: CapitalizationMode = DEFAULT_CAPITALIZATION,
var removeLookAlikeSymbols: Boolean = DEFAULT_REMOVE_LOOK_ALIKE_SYMBOLS,
val arrayDecorator: ArrayDecorator = DEFAULT_ARRAY_DECORATOR,
) : Scheme() {
override val name = Bundle("string.title")
Expand All @@ -50,7 +52,10 @@ data class StringScheme(
val rawStrings =
if (isRegex) {
val rgxGen = RgxGen(pattern)
List(count) { rgxGen.generate(random.asJavaRandom()) }
List(count) {
if (this.isNonMatching) rgxGen.generateNotMatching(random.asJavaRandom())
else rgxGen.generate(random.asJavaRandom())
}
} else {
List(count) { pattern }
}
Expand All @@ -73,7 +78,9 @@ data class StringScheme(
else ->
@Suppress("detekt:TooGenericExceptionCaught") // Consequence of incomplete validation in RgxGen
try {
RgxGen(pattern).generate()
if (this.isNonMatching) RgxGen(pattern).generate()
else RgxGen(pattern).generateNotMatching()

arrayDecorator.doValidate()
} catch (exception: RgxGenParseException) {
exception.message
Expand Down Expand Up @@ -117,9 +124,9 @@ data class StringScheme(
const val DEFAULT_IS_REGEX = true

/**
* The default value of the [removeLookAlikeSymbols] field.
* The default value of the [isNonMatching] field.
*/
const val DEFAULT_REMOVE_LOOK_ALIKE_SYMBOLS = false
const val DEFAULT_IS_NON_MATCHING = false

/**
* The preset values for the [capitalization] field.
Expand All @@ -136,6 +143,11 @@ data class StringScheme(
*/
val DEFAULT_CAPITALIZATION get() = CapitalizationMode.RETAIN

/**
* The default value of the [removeLookAlikeSymbols] field.
*/
const val DEFAULT_REMOVE_LOOK_ALIKE_SYMBOLS = false

/**
* The default value of the [arrayDecorator] field.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import com.intellij.ui.dsl.builder.bindText
import com.intellij.ui.dsl.builder.panel
import com.intellij.ui.dsl.builder.toNullableProperty
import com.intellij.ui.dsl.gridLayout.HorizontalAlign
import com.intellij.ui.layout.selected
import javax.swing.JCheckBox


/**
Expand All @@ -38,19 +40,19 @@ class StringSchemeEditor(scheme: StringScheme = StringScheme()) : SchemeEditor<S
}

row("") {
lateinit var isRegexBox: JCheckBox

checkBox(Bundle("string.ui.value.is_regex_option"))
.loadMnemonic()
.withName("isRegex")
.bindSelected(scheme::isRegex)
}
.also { isRegexBox = it.component }

row("") {
checkBox(Bundle("string.ui.value.remove_look_alike"))
checkBox(Bundle("string.ui.value.is_non_matching_option"))
.loadMnemonic()
.withName("removeLookAlikeCharacters")
.bindSelected(scheme::removeLookAlikeSymbols)

contextHelp(Bundle("string.ui.value.remove_look_alike_help", StringScheme.LOOK_ALIKE_CHARACTERS))
.withName("isNonMatching")
.bindSelected(scheme::isNonMatching)
.enabledIf(isRegexBox.selected)
}.bottomGap(BottomGap.SMALL)

row(Bundle("string.ui.value.capitalization_option")) {
Expand All @@ -59,6 +61,15 @@ class StringSchemeEditor(scheme: StringScheme = StringScheme()) : SchemeEditor<S
.withName("capitalization")
.bindItem(scheme::capitalization.toNullableProperty())
}

row {
checkBox(Bundle("string.ui.value.remove_look_alike"))
.loadMnemonic()
.withName("removeLookAlikeCharacters")
.bindSelected(scheme::removeLookAlikeSymbols)

contextHelp(Bundle("string.ui.value.remove_look_alike_help", StringScheme.LOOK_ALIKE_CHARACTERS))
}
}

row {
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/randomness.properties
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ string.error.trailing_backslash=Regex pattern must not end in unescaped backslas
string.title=String
string.ui.value.capitalization_option=&Capitalization:
string.ui.value.header=Value
string.ui.value.is_non_matching_option=&Non-matching
string.ui.value.is_regex_option=Parse as rege&x
string.ui.value.pattern_help=Supported syntax
string.ui.value.pattern_help_url=https://github.com/curious-odd-man/RgxGen/tree/1.4#supported-syntax
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ object StringSchemeEditorTest : FunSpec({
false,
)
},
"isInverseRegex" to {
row(
frame.checkBox("isNonMatching").isSelectedProp(),
editor.scheme::isNonMatching.prop(),
true,
)
},
"removeLookAlikeCharacters" to {
row(
frame.checkBox("removeLookAlikeCharacters").isSelectedProp(),
Expand Down
38 changes: 25 additions & 13 deletions src/test/kotlin/com/fwdekker/randomness/string/StringSchemeTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,32 @@ object StringSchemeTest : FunSpec({
mapOf(
"false if invalid" to
row(StringScheme(pattern = "{}"), false),
"false if pattern uses quantifier" to
row(StringScheme(pattern = "[u]{4}"), false),
"false if pattern uses grouping" to
row(StringScheme(pattern = "(a|b)"), false),
"true if pattern is plain string, as non-regex" to
row(StringScheme(pattern = "text", isRegex = false), true),
"true if pattern is plain string, as regex" to
row(StringScheme(pattern = "text", isRegex = true), true),
"true if pattern is plain string, as matching regex" to
row(StringScheme(pattern = "text"), true),
"false if pattern is plain string, as non-matching regex" to
row(StringScheme(pattern = "text", isNonMatching = true), false),
"true if pattern escapes character, as non-regex" to
row(StringScheme(pattern = """te\[xt""", isRegex = false), true),
"true if pattern escapes character, as regex" to
row(StringScheme(pattern = """te\[xt""", isRegex = true), true),
"true if pattern escapes character, as matching regex" to
row(StringScheme(pattern = """te\[xt"""), true),
"false if pattern escapes character, as non-matching regex" to
row(StringScheme(pattern = """te\[xt""", isNonMatching = true), false),
"true if pattern escapes backslash, as non-regex" to
row(StringScheme(pattern = """te\\xt""", isRegex = false), true),
"true if pattern escapes backslash, as regex" to
row(StringScheme(pattern = """te\\xt""", isRegex = true), true),
"true if pattern uses quantifier, as non-regex" to
row(StringScheme(pattern = "[u]{4}", isRegex = false), true),
"true if pattern escapes backslash, as matching regex" to
row(StringScheme(pattern = """te\\xt"""), true),
"false if pattern escapes backslash, as non-matching regex" to
row(StringScheme(pattern = """te\\xt""", isNonMatching = true), false),
"false if pattern uses quantifier, as matching regex" to
row(StringScheme(pattern = "[u]{4}"), false),
"false if pattern uses quantifier, as non-matching regex" to
row(StringScheme(pattern = "[u]{4}", isNonMatching = true), false),
"false if pattern uses grouping, as matching regex" to
row(StringScheme(pattern = "(a|b)"), false),
"false if pattern uses grouping, as non-matching regex" to
row(StringScheme(pattern = "(a|b)", isNonMatching = true), false),
)
) { (scheme, isSimple) -> scheme.isSimple() shouldBe isSimple }
}
Expand All @@ -63,6 +71,8 @@ object StringSchemeTest : FunSpec({
row(StringScheme(pattern = "a[bc]d", isRegex = false), "a[bc]d"),
"returns reverse-regexed string" to
row(StringScheme(pattern = "[x]{4}"), "xxxx"),
"returns non-matching reverse-regexed string" to
row(StringScheme(pattern = ".", isNonMatching = true), ""),
)
) { (scheme, output) -> scheme.generateStrings()[0] shouldBe output }
}
Expand All @@ -72,8 +82,10 @@ object StringSchemeTest : FunSpec({
mapOf(
"succeeds for default state" to
row(StringScheme(), null),
"fails if pattern is invalid" to
"fails if matching pattern is invalid" to
row(StringScheme(pattern = "{x"), ""),
"fails if non-matching pattern is invalid" to
row(StringScheme(pattern = "{x", isNonMatching = true), ""),
"fails if pattern is empty curly braces" to
row(StringScheme(pattern = "{}"), "string.error.empty_curly"),
"fails if pattern has empty curly braces" to
Expand Down