Skip to content

Commit db7ec6a

Browse files
Added support for isl-level testing (#10)
Co-authored-by: Corneliu Tusnea <corneliu_tusnea at intuit.com / corneliu at acorns.com.au>
1 parent f289549 commit db7ec6a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+3820
-123
lines changed

build.gradle.kts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,15 @@ configure(subprojects.filter { it.name in publishModules }) {
114114
}
115115
}
116116

117+
tasks.register<Copy>("copyIslToPlugin") {
118+
group = "build"
119+
description = "Build isl-cmd fat JAR and copy to plugin/lib for extension use"
120+
dependsOn(":isl-cmd:shadowJar")
121+
from(project(":isl-cmd").tasks.named("shadowJar").map { (it as org.gradle.api.tasks.bundling.Jar).archiveFile })
122+
into(file("plugin/lib"))
123+
rename { "isl-cmd-all.jar" }
124+
}
125+
117126
tasks.register("publishToMavenCentral") {
118127
group = "publishing"
119128
description = "Publish all modules to Maven Central"

docs/cli.md

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ For development, you can run directly with Gradle:
9797

9898
## Basic Usage
9999

100-
The ISL CLI has three main commands:
100+
The ISL CLI has four main commands:
101101

102102
### 1. Transform Command
103103

@@ -138,7 +138,38 @@ isl validate script.isl
138138
# If invalid, shows error details and exit code 1
139139
```
140140

141-
### 3. Info Command
141+
### 3. Test Command
142+
143+
Run ISL unit tests. Discovers `.isl` files containing `@test` or `@setup` annotations and executes them.
144+
145+
```bash
146+
# Run tests in current directory (default: **/*.isl)
147+
isl test
148+
149+
# Run tests in a specific path (directory, file, or glob)
150+
isl test tests/
151+
isl test tests/sample.isl
152+
153+
# Custom glob pattern
154+
isl test tests/ --glob "**/*.test.isl"
155+
156+
# Write results to JSON file
157+
isl test -o results.json
158+
```
159+
160+
**Options:**
161+
162+
| Option | Description |
163+
|--------|-------------|
164+
| `path` | Directory, file, or glob to search (default: current directory) |
165+
| `--glob PATTERN` | Glob to filter files when path is a directory (default: `**/*.isl`) |
166+
| `-o, --output FILE` | Write test results to JSON file |
167+
168+
Exit code: 0 if all tests pass, 1 if any fail.
169+
170+
See [Unit Testing](../ext/unit-testing/index.md) for writing tests, assertions, and loading fixtures.
171+
172+
### 4. Info Command
142173

143174
Display version and system information:
144175

@@ -176,6 +207,27 @@ isl info
176207
debug=true isl transform script.isl -i input.json
177208
```
178209

210+
### Logging from ISL Scripts
211+
212+
When running transforms or tests from the CLI, you can log messages from your ISL scripts:
213+
214+
```isl
215+
@.Log.Info("Processing started")
216+
@.Log.Info("Item count:", $count)
217+
@.Log.Warn("Unexpected value:", $value)
218+
@.Log.Error("Failed:", $error)
219+
@.Log.Debug("Debug info") // Only outputs when -Ddebug=true
220+
```
221+
222+
| Function | Output | When |
223+
|----------|--------|------|
224+
| `@.Log.Debug(...)` | stdout | Only when `-Ddebug=true` |
225+
| `@.Log.Info(...)` | stdout | Always |
226+
| `@.Log.Warn(...)` | stderr | Always |
227+
| `@.Log.Error(...)` | stderr | Always |
228+
229+
All functions accept multiple arguments (strings, variables, expressions); they are joined with spaces. JSON objects are pretty-printed.
230+
179231
## Working with Input Data
180232

181233
### Using Input Files

docs/ext/unit-testing/annotations.md

Lines changed: 95 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,33 +5,116 @@ grand_parent: Advanced Topics
55
nav_order: 3
66
---
77

8-
## Test
8+
# Test Annotations
99

10-
To create a unit test, we need to utilise the `@test` annotation to denote that the function
11-
is a unit test.
10+
## @test
1211

13-
```kotlin
12+
Marks a function as a unit test. The function runs as a test case when tests are executed.
13+
14+
### Basic form
15+
16+
```isl
1417
@test
1518
fun test_addNumbers() {
16-
...
19+
$sum: 1 + 2;
20+
@.Assert.equal(3, $sum);
21+
}
22+
```
23+
24+
When no parameters are given, the function name is used as the test name.
25+
26+
### Custom display name
27+
28+
```isl
29+
@test("Addition of positive numbers")
30+
fun test_addNumbers() {
31+
@.Assert.equal(3, 1 + 2);
1732
}
1833
```
1934

20-
In the test function, we can write regular ISL code, along with additional functions specific for testing capabilities.
35+
### Name and group
36+
37+
```isl
38+
@test("Check total", "math")
39+
fun test_total() {
40+
@.Assert.equal(10, 5 + 5);
41+
}
42+
```
43+
44+
### Object form
45+
46+
```isl
47+
@test({ name: "Grouped test", group: "math" })
48+
fun test_grouped() {
49+
$value: 30;
50+
@.Assert.equal(30, $value);
51+
}
52+
```
53+
54+
Use the object form when you need both a custom name and group.
55+
56+
### Parameter summary
57+
58+
| Form | Example | Result |
59+
|------|---------|--------|
60+
| No params | `@test` | Test name = function name |
61+
| String | `@test("My test")` | Test name = "My test" |
62+
| Two strings | `@test("Name", "group")` | Custom name and group |
63+
| Object | `@test({ name: "x", group: "y" })` | Custom name and group |
64+
65+
## @setup
2166

22-
## Setup
67+
Marks a function to run **before each test** in the same file. Use it for shared initialization.
2368

24-
We can also use the `@setup` annotation to denote actions we wish to repeat for each unit tests (e.g. setup of something specific)
69+
- At most **one** `@setup` function per file
70+
- Runs before every `@test` function in that file
71+
- Does not run as a test itself
2572

26-
```kotlin
73+
```isl
2774
@setup
2875
fun setup() {
29-
// Perform actions required before executing test
76+
$sharedState: { count: 0 };
77+
// This runs before each test
3078
}
3179
80+
@test
81+
fun test_first() {
82+
// setup() already ran
83+
@.Assert.equal(1, 1);
84+
}
3285
3386
@test
34-
fun test_addNumbers() {
35-
...
87+
fun test_second() {
88+
// setup() runs again before this test
89+
@.Assert.equal(2, 2);
90+
}
91+
```
92+
93+
## File structure
94+
95+
A typical test file:
96+
97+
```isl
98+
// Optional: imports
99+
import Helper from "../helper.isl";
100+
101+
@setup
102+
fun setup() {
103+
// Runs before each test
104+
}
105+
106+
@test
107+
fun test_basic() {
108+
// Test code
109+
}
110+
111+
@test("Custom name")
112+
fun test_withName() {
113+
// Test code
114+
}
115+
116+
@test({ name: "Edge case", group: "validation" })
117+
fun test_edgeCase() {
118+
// Test code
36119
}
37120
```

docs/ext/unit-testing/assertions.md

Lines changed: 75 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -5,100 +5,116 @@ grand_parent: Advanced Topics
55
nav_order: 2
66
---
77

8-
In order to verify values within the unit tests, we can utilise the Assertion framework.
8+
# Assertions
99

10-
These are accessible under the `@.Assert` namespace.
10+
Assertions verify values in unit tests. They are available under the `@.Assert` namespace. All assertion methods accept an optional third parameter `message` for custom failure output.
1111

12-
## Equal
12+
## Equality
1313

14-
### Description
14+
### equal
1515

16-
Verifies whether or not values are equal.
16+
Verifies that two values are equal (deep equality for objects and arrays; property order is ignored for objects).
1717

18-
### Syntax
18+
**Syntax:** `@.Assert.equal(expected, actual, message?)`
1919

20-
`@.Assert.Equal($expectedValue, $actualValue, $msg)`
21-
22-
- `$expectedValue`: Expected value.
23-
- `$actualValue`: Actual value to verify against.
24-
- `$msg`: Optional error message to show if assertion fails.
25-
26-
### Example
27-
28-
```kotlin
20+
```isl
2921
@test
30-
fun assert_equals() {
31-
$var1 : 20
32-
@.Assert.Equal(40, $var1, "Values don't match.");
22+
fun test_equal() {
23+
$var1: 20;
24+
@.Assert.equal(20, $var1);
25+
26+
$obj1: { a: 1, b: 2 };
27+
$obj2: { b: 2, a: 1 };
28+
@.Assert.equal($obj1, $obj2); // Objects equal despite property order
3329
}
3430
```
3531

36-
## NotEqual
37-
38-
### Description
39-
40-
Verifies whether or not values are not equal.
41-
42-
### Syntax
32+
### notEqual
4333

44-
`@.Assert.NotEqual($expectedValue, $actualValue, $msg)`
34+
Verifies that two values are not equal.
4535

46-
- `$expectedValue`: Expected value.
47-
- `$actualValue`: Actual value to verify against.
48-
- `$msg`: Optional error message to show if assertion fails.
36+
**Syntax:** `@.Assert.notEqual(expected, actual, message?)`
4937

50-
### Example
51-
52-
```kotlin
38+
```isl
5339
@test
54-
fun assert_equals() {
55-
$var1 : 20
56-
@.Assert.NotEqual(40, $var1, "Values match.");
40+
fun test_notEqual() {
41+
$var1: 20;
42+
@.Assert.notEqual(40, $var1, "Values should differ");
5743
}
5844
```
5945

60-
## NotNull
46+
## Null Checks
6147

62-
### Description
48+
### notNull
6349

64-
Verifies whether or not value is not null.
50+
Verifies that a value is not null.
6551

66-
### Syntax
52+
**Syntax:** `@.Assert.notNull(value, message?)`
6753

68-
`@.Assert.NotNull($value, $msg)`
54+
```isl
55+
@test
56+
fun test_notNull() {
57+
$var1: 42;
58+
@.Assert.notNull($var1, "Value should not be null");
59+
}
60+
```
6961

70-
- `$value`: Expected value.
71-
- `$msg`: Optional error message to show if assertion fails.
62+
### isNull
7263

73-
### Example
64+
Verifies that a value is null.
7465

75-
```kotlin
66+
**Syntax:** `@.Assert.isNull(value, message?)`
67+
68+
```isl
7669
@test
77-
fun assert_equals() {
78-
$var1 : null
79-
@.Assert.NotNull($var1, "Value is null");
70+
fun test_isNull() {
71+
$var1: null;
72+
@.Assert.isNull($var1, "Value should be null");
8073
}
8174
```
8275

83-
## IsNull
76+
## Comparisons
77+
78+
| Assertion | Description |
79+
|-----------|-------------|
80+
| `@.Assert.lessThan(a, b)` | a < b |
81+
| `@.Assert.lessThanOrEqual(a, b)` | a <= b |
82+
| `@.Assert.greaterThan(a, b)` | a > b |
83+
| `@.Assert.greaterThanOrEqual(a, b)` | a >= b |
8484

85-
### Description
85+
## String and Pattern
8686

87-
Verifies whether or not value is null.
87+
| Assertion | Description |
88+
|-----------|-------------|
89+
| `@.Assert.matches(pattern, value)` | value matches regex pattern |
90+
| `@.Assert.notMatches(pattern, value)` | value does not match pattern |
91+
| `@.Assert.contains(expected, actual)` | actual contains expected |
92+
| `@.Assert.notContains(expected, actual)` | actual does not contain expected |
93+
| `@.Assert.startsWith(prefix, value)` | value starts with prefix |
94+
| `@.Assert.notStartsWith(prefix, value)` | value does not start with prefix |
95+
| `@.Assert.endsWith(suffix, value)` | value ends with suffix |
96+
| `@.Assert.notEndsWith(suffix, value)` | value does not end with suffix |
8897

89-
### Syntax
98+
## Membership and Type
9099

91-
`@.Assert.IsNull($value, $msg)`
100+
| Assertion | Description |
101+
|-----------|-------------|
102+
| `@.Assert.in(value, collection)` | value is in collection |
103+
| `@.Assert.notIn(value, collection)` | value is not in collection |
104+
| `@.Assert.isType(value, type)` | value is of type (e.g. `number`, `string`, `array`, `node`, `date`) |
105+
| `@.Assert.isNotType(value, type)` | value is not of type |
92106

93-
- `$value`: Expected value.
94-
- `$msg`: Optional error message to show if assertion fails.
107+
## Custom Failure Message
95108

96-
### Example
109+
All assertions accept an optional third parameter for a custom message:
97110

98-
```kotlin
111+
```isl
99112
@test
100-
fun assert_equals() {
101-
$var1 : null
102-
@.Assert.NotNull($var1, "Value not null");
113+
fun test_withMessage() {
114+
$var1: 1;
115+
$var2: 2;
116+
@.Assert.equal($var1, $var2, "Expected 1 to equal 2 - values mismatch");
103117
}
104118
```
119+
120+
When the assertion fails, the custom message is included in the output.

0 commit comments

Comments
 (0)