Skip to content

Commit ee77717

Browse files
authored
Merge pull request #75 from Kros-sk/feature/function-variables
Feature/function variables
2 parents 37f92ad + 69e6a3b commit ee77717

38 files changed

+882
-18
lines changed

Directory.Packages.props

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,10 @@
2424
<PackageVersion Include="Spectre.Console.Cli" Version="0.50.0" />
2525
<PackageVersion Include="Spectre.Console.Testing" Version="0.50.0" />
2626
<PackageVersion Include="Spectre.Console" Version="0.50.0" />
27+
<PackageVersion Include="System.CommandLine" Version="2.0.0-beta7.25380.108" />
2728
<PackageVersion Include="System.Net.Http" Version="4.3.4" />
2829
<PackageVersion Include="xunit" Version="2.9.3" />
2930
<PackageVersion Include="xunit.assert" Version="2.9.3" />
3031
<PackageVersion Include="xunit.runner.visualstudio" Version="3.0.2" />
3132
</ItemGroup>
32-
</Project>
33+
</Project>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
public class CarRent
2+
{
3+
public long Id { get; set; }
4+
public long CarId { get; set; }
5+
public long CustomerId { get; set; }
6+
public string RentalStart { get; set; }
7+
public string RentalEnd { get; set; }
8+
public decimal Price { get; set; }
9+
public string Notes { get; set; }
10+
public short NumberOfDrivers { get; set; }
11+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
tp.SetVariable("RentalDays", 14);
2+
3+
// Register custom function, for generating car return date.
4+
tp.RegisterFunction("$carReturnDate", (int days) =>
5+
{
6+
return DateTime.Now.AddDays(days).ToString("yyyy-MM-dd");
7+
});

demo/Tests/003-Car-Rentals/001-Rent-Car-req.http

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,25 @@
11
# @name RentCarRequest
22
POST {{ApiBaseUrl}}{{ApiCarRentalSection}}
33
Content-Type: application/json
4-
// Usage of variables is also permitted in body definition
4+
// Variables and even functions can also be used in the body definition
55

66
{
7-
"Id": 1,
8-
"CarId": "{{NewCarId}}",
9-
"CustomerId": "{{NewCustomerId}}",
10-
"RentalStart": "2023-08-01",
11-
"RentalEnd": "2023-08-05",
7+
"Id": 42,
8+
"CarId": {{NewCarId}},
9+
"CustomerId": {{NewCustomerId}},
10+
"RentalStart": "{{$now "yyyy-MM-dd"}}",
11+
"RentalEnd": "{{$carReturnDate {{RentalDays}}}}",
1212
"Price": 200.00,
1313
"Notes": "Rented for a weekend wedding.",
1414
"NumberOfDrivers": 1
1515
}
1616

1717
###
18+
## RETRY-UNTIL-STATUS: [200]
19+
# @name GetCarRentRequest
20+
GET {{ApiBaseUrl}}{{ApiCarRentalSection}}/{{RentCarRequest.request.body.$.Id}}
21+
###
22+
1823
# Example of all available retry directives. Selected RETRY-STRATEGY must be registered first (via script, see 'demo/init.csx').
1924
# - RETRY-UNTIL-STATUS adds a condition specifying until which status codes retrying should continue.
2025
# - Other retry directives override specific properties of the selected retry strategy.

demo/Tests/003-Car-Rentals/001-Rent-Car-test.csx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Referencing multiple scripts is also allowed.
22
#load "$teapie/ClearVariables.csx"
33
#load "$teapie/Definitions/Car.csx"
4+
#load "$teapie/Definitions/CarRent.csx"
45

56
// Sometimes, when writing tests, it may be useful to skip certain tests
67
// to speed up development and avoid unnecessary code commenting or deletion.
@@ -12,10 +13,19 @@ tp.Test("Car should be rented successfully.", () =>
1213
Equal(200, tp.Response.StatusCode());
1314
}, skipTest: true); // To skip test, just add optional parameter with 'true' value.
1415

16+
17+
await tp.Test($"Check correct car rent interval.", async () =>
18+
{
19+
// Body content in form of given reference type. (Works only for JSON structured bodies).
20+
var carRent = await tp.Responses["GetCarRentRequest"].GetBodyAsync<CarRent>();
21+
22+
Equal(carRent.RentalStart, tp.ExecFunction<string>("$now", "yyyy-MM-dd"));
23+
Equal(carRent.RentalEnd, tp.ExecFunction<string>("$carReturnDate", tp.GetVariable<int>("RentalDays")));
24+
});
25+
1526
// If you have variable in JSON string, it can be easily converted to reference type, by using 'To<TResult>()' method.
1627
var car = tp.GetVariable<string>("NewCar").To<Car>();
1728

18-
// Interpolated strings resolve correctly ('Car' overrides the 'ToString()' method).
1929
await tp.Test($"Rented car should be '{car}'.", async () =>
2030
{
2131
// Body content in form of given reference type. (Works only for JSON structured bodies).

demo/server/CarRentalServer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@
8989
"disableTemplating": false,
9090
"fallbackTo404": false,
9191
"default": true,
92-
"crudKey": "id",
92+
"crudKey": "Id",
9393
"callbacks": []
9494
}
9595
],
@@ -131,7 +131,7 @@
131131
"disableTemplating": false,
132132
"fallbackTo404": false,
133133
"default": true,
134-
"crudKey": "id",
134+
"crudKey": "Id",
135135
"callbacks": []
136136
}
137137
],

docs/docs/functions.md

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
# Functions
2+
3+
TeaPie provides a lightweight function system for generating dynamic values in scripts and `.http` files.
4+
5+
## Function Naming Rules
6+
7+
- Must start with `$`
8+
- Allowed characters: letters, digits, `_`, `.`, `$`, `-`
9+
- Pattern used by parser: `^\$[a-zA-Z0-9_.$-]*$`
10+
- Function names are case-sensitive.
11+
- Function notation in `.http` files follows: `{{(\$.*)}}`
12+
13+
## Function Levels
14+
15+
TeaPie supports two levels of functions, determining visibility and resolution order:
16+
17+
| Level | Scope & Behavior |
18+
|------|-------------------|
19+
| Default | Built-in functions available to all test cases and collections. |
20+
| Custom | User-registered functions that live for the current collection run. |
21+
22+
### Function Resolution Order
23+
24+
Functions are resolved in this order:
25+
26+
1. Default Functions
27+
2. Custom Functions
28+
29+
>The first match is executed.
30+
31+
---
32+
33+
## Using Functions in HTTP Files
34+
35+
Syntax (no parentheses, no commas; max 2 arguments):
36+
37+
- `{{$functionName}}`
38+
- `{{$functionName arg1}}`
39+
- `{{$functionName arg1 arg2}}`
40+
41+
Notes:
42+
43+
- Arguments are whitespace-separated tokens (maximum two per function).
44+
- Use quotes for values with spaces: `{{$now "yyyy-MM-dd HH:mm"}}`
45+
- Both single and double quotes are supported.
46+
- Function names are case-sensitive.
47+
- Internally, arguments are tokenized using a command-line parser and converted to the target parameter types.
48+
49+
Using together with Variables:
50+
51+
- You can pass Variables as function arguments by embedding variable notation inside the function call.
52+
- Variable notation must follow variable rules (name pattern, `{{variableName}}`).
53+
- Examples:
54+
- `{{$add {{MyNumber}} 2}}` // passes variable MyNumber as first argument
55+
- `{{$upper "{{FullName}}"}}` // if the variable value may contain spaces, wrap it in quotes
56+
- You can also mix standalone variables and functions in the same line, e.g.:
57+
- `X-Trace-Id: {{RequestId}}-{{$guid}}`
58+
- `X-Date: {{$now "yyyyMMdd"}}-{{EnvironmentName}}`
59+
60+
If a function is not found, TeaPie throws an error during resolution.
61+
62+
---
63+
64+
## Built-in Functions
65+
66+
The following functions are available by default:
67+
68+
| Name | Signature | Description | Example |
69+
|------|-----------|-------------|---------|
70+
| `$guid` | `Guid $guid()` | Generates a new GUID. | `{{$guid}}` |
71+
| `$now` | `string $now(string? format)` | Current local time formatted via `DateTime.ToString(format)`. If `format` is omitted, default formatting is used. | `{{$now "yyyy-MM-dd"}}` |
72+
| `$rand` | `double $rand()` | Random double in the range [0, 1). | `{{$rand}}` |
73+
| `$randomInt` | `int $randomInt(int min, int max)` | Random integer in the range [min, max). | `{{$randomInt 1 100}}` |
74+
75+
Notes:
76+
77+
- `$now` uses `DateTime.Now` and the same formatting behavior as `DateTime.ToString(string?)`.
78+
79+
Example:
80+
81+
``` http
82+
# Generate values with functions
83+
POST https://example.com/api/items
84+
Content-Type: application/json
85+
86+
{
87+
"id": "{{$guid}}",
88+
"createdAt": "{{$now "yyyy-MM-dd'T'HH:mm:ss"}}",
89+
"score": {{$randomInt 10 20}},
90+
"ratio": {{$rand}}
91+
}
92+
```
93+
94+
---
95+
96+
## Working with Functions in C\#
97+
98+
Access functions through the `TeaPie` instance (`tp`).
99+
100+
### **2️⃣ Registering via TeaPie**
101+
102+
TeaPie supports registering functions with 0–2 parameters (maximum two arguments).
103+
104+
``` cs
105+
// 0-arg
106+
tp.RegisterFunction("$buildNumber", () => Environment.GetEnvironmentVariable("BUILD_NUMBER") ?? "local");
107+
108+
// 1-arg
109+
tp.RegisterFunction("$upper", (string s) => s.ToUpperInvariant());
110+
111+
// 2-arg (maximum)
112+
tp.RegisterFunction("$add", (int a, int b) => a + b);
113+
```
114+
115+
### **1️⃣ Use them in `.http` files**
116+
117+
``` http
118+
{{$upper "hello"}}
119+
{{$add 40 2}}
120+
```
121+
122+
### **3️⃣ Executing via TeaPie**
123+
124+
```cs
125+
var id = tp.ExecFunction<Guid>("$guid");
126+
var timeStamp = tp.ExecFunction<string>("$now", "yyyy-MM-dd");
127+
var sum = tp.ExecFunction<int>("$add", 2, 3);
128+
```
129+
130+
>If a function is not found or execution fails, TeaPie throws an error during resolution.
131+
132+
---
133+
134+
## Argument Conversion
135+
136+
- Arguments from `.http` files are strings
137+
- TeaPie converts them to expected parameter types using .NET conversion (`Convert.ChangeType(...)`)
138+
- Works for common primitives (int, double, bool, DateTime, etc.)
139+
- Uses the current culture during parsing
140+
- If conversion fails, execution throws an exception
141+
142+
>Tip: Prefer culture-invariant formats in `.http` files for dates and decimals when needed.

docs/docs/toc.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
href: initialization-script.md
2626
- name: Variables
2727
href: variables.md
28+
- name: Functions
29+
href: functions.md
2830
- name: Environments
2931
href: environments.md
3032
- name: Authentication

src/Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
</PropertyGroup>
1818

1919
<PropertyGroup>
20-
<Version>1.2.1</Version>
20+
<Version>1.3.0</Version>
2121
<Authors>Matej Grochal</Authors>
2222
<Company>KROS a.s.</Company>
2323
<Copyright>Copyright © KROS a.s.</Copyright>

src/TeaPie.DotnetTool/TeaPie.DotnetTool.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
<PropertyGroup>
1313
<OutputType>Exe</OutputType>
14+
<Version>1.3.0</Version>
1415
</PropertyGroup>
1516

1617
<ItemGroup>

0 commit comments

Comments
 (0)