Skip to content

Commit c91f7f3

Browse files
committed
feat: adds random.any() expression function.
1 parent 9e27453 commit c91f7f3

File tree

3 files changed

+127
-21
lines changed

3 files changed

+127
-21
lines changed

core/expression/src/main/java/io/gatehill/imposter/expression/eval/RandomEvaluator.kt

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2023.
2+
* Copyright (c) 2023-2024.
33
*
44
* This file is part of Imposter.
55
*
@@ -80,15 +80,31 @@ object RandomEvaluator : ExpressionEvaluator<String> {
8080
it.split("=").let { parts -> parts[0] to parts[1] }
8181
}
8282
val type = randomConfig.substringBefore("(")
83-
val length = args["length"]?.toInt()
83+
val length = args["length"]?.toInt() ?: 1
8484
val uppercase = args["uppercase"].toBoolean()
8585

86+
// the chars string must be enclosed in double quotes
87+
val chars = args["chars"]?.let {
88+
if (!it.startsWith("\"") || !it.endsWith("\"")) {
89+
LOGGER.warn("chars string must be enclosed in double quotes")
90+
return null
91+
}
92+
it.substring(1, it.length - 1)
93+
}
94+
8695
val random = when (type) {
87-
"alphabetic" -> getRandomString(length!!, alphabetUpper + alphabetLower)
88-
"alphanumeric" -> getRandomString(length!!, alphabetUpper + alphabetLower + numbers)
89-
"numeric" -> getRandomString(length!!, numbers.toList())
96+
"alphabetic" -> getRandomString(length, alphabetUpper + alphabetLower)
97+
"alphanumeric" -> getRandomString(length, alphabetUpper + alphabetLower + numbers)
98+
"any" -> {
99+
if (chars == null) {
100+
LOGGER.warn("chars string must be provided for random type 'any'")
101+
return null
102+
}
103+
getRandomString(length, chars.toList())
104+
}
105+
"numeric" -> getRandomString(length, numbers.toList())
90106
"uuid" -> UUID.randomUUID().toString()
91-
else -> run {
107+
else -> {
92108
LOGGER.warn("Could not parse random expression: $randomConfig")
93109
return null
94110
}
@@ -97,6 +113,6 @@ object RandomEvaluator : ExpressionEvaluator<String> {
97113
}
98114

99115
private fun getRandomString(length: Int, allowedChars: List<Char>) = (1..length)
100-
.map { allowedChars.random() }
101-
.joinToString("")
116+
.map { allowedChars.random() }
117+
.joinToString("")
102118
}

core/expression/src/test/java/io/gatehill/imposter/expression/eval/RandomEvaluatorTest.kt

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,46 @@
1+
/*
2+
* Copyright (c) 2024.
3+
*
4+
* This file is part of Imposter.
5+
*
6+
* "Commons Clause" License Condition v1.0
7+
*
8+
* The Software is provided to you by the Licensor under the License, as
9+
* defined below, subject to the following condition.
10+
*
11+
* Without limiting other conditions in the License, the grant of rights
12+
* under the License will not include, and the License does not grant to
13+
* you, the right to Sell the Software.
14+
*
15+
* For purposes of the foregoing, "Sell" means practicing any or all of
16+
* the rights granted to you under the License to provide to third parties,
17+
* for a fee or other consideration (including without limitation fees for
18+
* hosting or consulting/support services related to the Software), a
19+
* product or service whose value derives, entirely or substantially, from
20+
* the functionality of the Software. Any license notice or attribution
21+
* required by the License must also include this Commons Clause License
22+
* Condition notice.
23+
*
24+
* Software: Imposter
25+
*
26+
* License: GNU Lesser General Public License version 3
27+
*
28+
* Licensor: Peter Cornish
29+
*
30+
* Imposter is free software: you can redistribute it and/or modify
31+
* it under the terms of the GNU Lesser General Public License as published by
32+
* the Free Software Foundation, either version 3 of the License, or
33+
* (at your option) any later version.
34+
*
35+
* Imposter is distributed in the hope that it will be useful,
36+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
37+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38+
* GNU Lesser General Public License for more details.
39+
*
40+
* You should have received a copy of the GNU Lesser General Public License
41+
* along with Imposter. If not, see <https://www.gnu.org/licenses/>.
42+
*/
43+
144
package io.gatehill.imposter.expression.eval
245

346
import org.hamcrest.MatcherAssert.assertThat
@@ -37,6 +80,25 @@ class RandomEvaluatorTest {
3780
assertContainsOnly(result, RandomEvaluator.alphabetLower + RandomEvaluator.numbers + listOf('-'))
3881
}
3982

83+
@Test
84+
fun `generates from list of chars`() {
85+
val result = RandomEvaluator.eval("""random.any(chars="abc", length=5)""", emptyMap<String, Any>())
86+
assertThat(result, hasLength(5))
87+
assertContainsOnly(result, listOf('a', 'b', 'c'))
88+
}
89+
90+
@Test
91+
fun `returns null for invalid chars string`() {
92+
val result = RandomEvaluator.eval("""random.any(chars=notquoted, length=5)""", emptyMap<String, Any>())
93+
Assert.assertNull(result)
94+
}
95+
96+
@Test
97+
fun `returns null for invalid random type`() {
98+
val result = RandomEvaluator.eval("random.invalid()", emptyMap<String, Any>())
99+
Assert.assertNull(result)
100+
}
101+
40102
private fun assertContainsOnly(
41103
actual: String?,
42104
allowed: List<Char>

docs/templates.md

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -231,47 +231,75 @@ Example config:
231231
# part of your configuration file
232232
233233
resources:
234-
- path: /now
234+
- path: /number
235235
method: POST
236236
response:
237-
content: "An integer is ${random.numeric}"
237+
content: "An integer is ${random.numeric()}"
238+
template: true
239+
240+
- path: /chars
241+
method: POST
242+
response:
243+
content: "A random string is ${random.alphabetic(length=5)}"
238244
template: true
239245
```
240246

241-
Example request:
247+
Example requests:
242248

243249
```
244-
$ curl http://localhost:8080/now
250+
$ curl http://localhost:8080/number
251+
An integer is 4
245252
246-
An integer is 42
253+
$ curl http://localhost:8080/chars
254+
A random string is abcde
247255
```
248256

249257
Valid random functions:
250258

251-
| Syntax | Example | Example value |
252-
|-------------------------|----------------------------|------------------------------------------|
253-
| `random.alphabetic()` | `${random.alphabetic()}` | `"i"` |
254-
| `random.alphanumeric()` | `${random.alphanumeric()}` | `"i"` or `"42"` |
255-
| `random.numeric()` | `${random.numeric()}` | `"42"` |
256-
| `random.uuid()` | `${random.uuid()}` | `"e1a4fba9-33eb-4241-84cf-472f90639c37"` |
259+
| Syntax | Example | Example value |
260+
|---------------------------|---------------------------------|------------------------------------------|
261+
| `random.alphabetic()` | `${random.alphabetic()}` | `"i"` |
262+
| `random.alphanumeric()` | `${random.alphanumeric()}` | `"i"` or `"42"` |
263+
| `random.any(chars="...")` | `${random.any(chars="abc123")}` | `"a"` or `"1"` |
264+
| `random.numeric()` | `${random.numeric()}` | `"42"` |
265+
| `random.uuid()` | `${random.uuid()}` | `"e1a4fba9-33eb-4241-84cf-472f90639c37"` |
257266

258267
> Note: the syntax for `random` is slightly different to the other placeholder types. These are functions, not properties, so are called with parentheses.
259268

260269
#### Customise length
261270

262271
Customise the length of the generated value by passing `length=NUM` argument into the function.
263272

264-
For example: `${random.alphabetic(length=5)}`
273+
For example: `${random.alphabetic(length=5)}` will generate a 5-character alphabetic string.
274+
275+
> The default length is 1.
265276

266277
This applies to the following functions:
267278

268279
- alphabetic
269280
- alphanumeric
281+
- any
270282
- numeric
271283

272284
#### Uppercase
273285

274-
Convert the generated value to uppercase by passing `uppercase=true` argument
286+
Convert the generated value to uppercase by passing `uppercase=true` argument into the function.
287+
288+
For example: `${random.alphabetic(uppercase=true)}` will generate an uppercase alphabetic character.
289+
290+
> You can combine `length` and `uppercase` arguments.
291+
>
292+
> For example: `${random.alphabetic(length=5, uppercase=true)}` will generate a 5-character uppercase alphabetic string.
293+
294+
#### Generate from a set of characters
295+
296+
Generate a value from a set of characters by passing `chars="..."` argument into the `random.any()` function.
297+
298+
For example: `${random.any(chars="abc123")}` will generate a value from the set of characters `a`, `b`, `c`, `1`, `2`, `3`.
299+
300+
> You can also use the `length` and `uppercase` arguments with `random.any()`.
301+
>
302+
> For example: `${random.any(chars="xyz", length=5, uppercase=true)}` will generate a 5-character uppercase value from the set of characters `x`, `y`, `z`.
275303

276304
### Items in a Store
277305

0 commit comments

Comments
 (0)