Skip to content

Commit 646c17c

Browse files
committed
Add examples testing
1 parent ac5b2c7 commit 646c17c

File tree

4 files changed

+185
-1
lines changed

4 files changed

+185
-1
lines changed

test/examples/examples_test.go

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package main
2+
3+
import (
4+
"flag"
5+
"os"
6+
"strings"
7+
"testing"
8+
9+
"github.com/expr-lang/expr"
10+
"github.com/expr-lang/expr/internal/testify/require"
11+
)
12+
13+
func TestExamples(t *testing.T) {
14+
flag.Parse()
15+
16+
b, err := os.ReadFile("../../testdata/examples.md")
17+
require.NoError(t, err)
18+
examples := extractCodeBlocks(string(b))
19+
20+
for _, line := range examples {
21+
line := line
22+
t.Run(line, func(t *testing.T) {
23+
program, err := expr.Compile(line, expr.Env(nil))
24+
require.NoError(t, err)
25+
26+
_, err = expr.Run(program, nil)
27+
require.NoError(t, err)
28+
})
29+
}
30+
}
31+
32+
func extractCodeBlocks(markdown string) []string {
33+
var blocks []string
34+
var currentBlock []string
35+
inBlock := false
36+
37+
lines := strings.Split(markdown, "\n")
38+
for _, line := range lines {
39+
trimmed := strings.TrimSpace(line)
40+
if strings.HasPrefix(trimmed, "```") {
41+
if inBlock {
42+
blocks = append(blocks, strings.Join(currentBlock, "\n"))
43+
currentBlock = nil
44+
inBlock = false
45+
} else {
46+
inBlock = true
47+
}
48+
continue
49+
}
50+
if inBlock {
51+
currentBlock = append(currentBlock, line)
52+
}
53+
}
54+
return blocks
55+
}

test/gen/gen_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ var updateFlag = flag.Bool("update", false, "Drop failing lines from examples.tx
1616
func TestGenerated(t *testing.T) {
1717
flag.Parse()
1818

19-
b, err := os.ReadFile("../../testdata/examples.txt")
19+
b, err := os.ReadFile("../../testdata/generated.txt")
2020
require.NoError(t, err)
2121

2222
examples := strings.TrimSpace(string(b))

testdata/examples.md

+129
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# Examples
2+
3+
Character Frequency Grouping
4+
5+
```
6+
let char = "0";
7+
1..100000
8+
| map(string(#))
9+
| groupBy(split(#, char) | len() - 1)
10+
| toPairs()
11+
| map({{
12+
count: #[0],
13+
len: len(#[1]),
14+
examples: [first(#[1]), last(#[1])],
15+
}})
16+
| sortBy(.len, 'desc')
17+
```
18+
19+
Log Filtering and Aggregation
20+
21+
```
22+
let logs = [
23+
{timestamp: date("2023-08-14 08:30:00"), message: "User logged in", level: "info"},
24+
{timestamp: date("2023-08-14 09:00:00"), message: "Error processing payment", level: "error"},
25+
{timestamp: date("2023-08-14 10:15:00"), message: "User logged out", level: "info"},
26+
{timestamp: date("2023-08-14 11:00:00"), message: "Error connecting to database", level: "error"}
27+
];
28+
29+
logs
30+
| filter(.level == "error")
31+
| map({{
32+
time: string(.timestamp),
33+
detail: .message
34+
}})
35+
| sortBy(.time)
36+
```
37+
38+
Financial Data Analysis and Summary
39+
40+
```
41+
let accounts = [
42+
{name: "Alice", balance: 1234.56, transactions: [100, -50, 200]},
43+
{name: "Bob", balance: 2345.67, transactions: [-200, 300, -150]},
44+
{name: "Charlie", balance: 3456.78, transactions: [400, -100, 50]}
45+
];
46+
47+
{
48+
totalBalance: sum(accounts, .balance),
49+
averageBalance: mean(map(accounts, .balance)),
50+
totalTransactions: reduce(accounts, #acc + len(.transactions), 0),
51+
accounts: map(accounts, {{
52+
name: .name,
53+
final: .balance + sum(.transactions),
54+
transactionCount: len(.transactions)
55+
}})
56+
}
57+
```
58+
59+
Bitwise Operations and Flags Decoding
60+
61+
```
62+
let flags = [
63+
{name: "read", value: 0b0001},
64+
{name: "write", value: 0b0010},
65+
{name: "execute", value: 0b0100},
66+
{name: "admin", value: 0b1000}
67+
];
68+
69+
let userPermissions = 0b1011;
70+
71+
flags
72+
| filter(userPermissions | bitand(.value) != 0)
73+
| map(.name)
74+
```
75+
76+
Nested Predicates with Optional Chaining
77+
78+
```
79+
let users = [
80+
{id: 1, name: "Alice", posts: [{title: "Hello World", content: "Short post"}, {title: "Another Post", content: "This is a bit longer post"}]},
81+
{id: 2, name: "Bob", posts: nil},
82+
{id: 3, name: "Charlie", posts: [{title: "Quick Update", content: "Update content"}]}
83+
];
84+
85+
users
86+
| filter(
87+
// Check if any post has content length greater than 10.
88+
any(.posts ?? [], len(.content) > 10)
89+
)
90+
| map({{name: .name, postCount: len(.posts ?? [])}})
91+
```
92+
93+
String Manipulation and Validation
94+
95+
```
96+
" Apple, banana, Apple, orange, banana, kiwi "
97+
| trim()
98+
| split(",")
99+
| map(trim(#))
100+
| map(lower(#))
101+
| uniq()
102+
| sort()
103+
| join(", ")
104+
```
105+
106+
Date Difference
107+
108+
```
109+
let startDate = date("2023-01-01");
110+
let endDate = date("2023-12-31");
111+
let diff = endDate - startDate;
112+
{
113+
daysBetween: diff.Hours() / 24,
114+
hoursBetween: diff.Hours()
115+
}
116+
```
117+
118+
Phone number filtering
119+
120+
```
121+
let phone = filter(split("123-456-78901", ""), # in map(0..9, string(#)))[:10];
122+
join(concat(["("], phone[:3], [")"], phone[3:6], ["-"], phone[6:]))
123+
```
124+
125+
Prime numbers
126+
127+
```
128+
2..1000 | filter(let N = #; none(2..N-1, N % # == 0))
129+
```
File renamed without changes.

0 commit comments

Comments
 (0)