4
4
"encoding/json"
5
5
"fmt"
6
6
"github.com/antonmedv/expr/ast"
7
+ "reflect"
7
8
"strings"
8
9
"testing"
9
10
"time"
@@ -495,9 +496,9 @@ func TestExpr_readme_example(t *testing.T) {
495
496
496
497
func TestExpr (t * testing.T ) {
497
498
date := time .Date (2017 , time .October , 23 , 18 , 30 , 0 , 0 , time .UTC )
498
- tnow := time .Now ()
499
+ timeNow := time .Now ()
499
500
oneDay , _ := time .ParseDuration ("24h" )
500
- tnowPlusOne := tnow .Add (oneDay )
501
+ timeNowPlusOneDay := timeNow .Add (oneDay )
501
502
502
503
env := & mockEnv {
503
504
Any : "any" ,
@@ -520,8 +521,8 @@ func TestExpr(t *testing.T) {
520
521
{Origin : "LED" , Destination : "MOW" },
521
522
},
522
523
BirthDay : date ,
523
- Now : tnow ,
524
- NowPlusOne : tnowPlusOne ,
524
+ Now : timeNow ,
525
+ NowPlusOne : timeNowPlusOneDay ,
525
526
OneDayDuration : oneDay ,
526
527
One : 1 ,
527
528
Two : 2 ,
@@ -950,11 +951,11 @@ func TestExpr(t *testing.T) {
950
951
},
951
952
{
952
953
`Now + OneDayDuration` ,
953
- tnowPlusOne ,
954
+ timeNowPlusOneDay ,
954
955
},
955
956
{
956
957
`OneDayDuration + Now` ,
957
- tnowPlusOne ,
958
+ timeNowPlusOneDay ,
958
959
},
959
960
{
960
961
`lowercase` ,
@@ -973,6 +974,9 @@ func TestExpr(t *testing.T) {
973
974
}
974
975
975
976
for _ , tt := range tests {
977
+ if tt .code == "map(filter(Tweets, {len(.Text) > 10}), {Format(.Date)})" {
978
+ expr .Compile (tt .code , expr .Optimize (false ))
979
+ }
976
980
program , err := expr .Compile (tt .code , expr .Optimize (false ))
977
981
require .NoError (t , err , "compile error" )
978
982
@@ -1299,35 +1303,70 @@ func TestConstExpr_error_no_env(t *testing.T) {
1299
1303
require .Equal (t , "no environment for const expression: divide" , err .Error ())
1300
1304
}
1301
1305
1302
- //func TestPatch(t *testing.T) {
1303
- // program, err := expr.Compile(
1304
- // `Ticket == "$100" and "$90" != Ticket + "0"`,
1305
- // expr.Env(mockEnv{}),
1306
- // expr.Patch(&stringerPatcher{}),
1307
- // )
1308
- // require.NoError(t, err)
1309
- //
1310
- // env := mockEnv{
1311
- // Ticket: &ticket{Price: 100},
1312
- // }
1313
- // output, err := expr.Run(program, env)
1314
- // require.NoError(t, err)
1315
- // require.Equal(t, true, output)
1316
- //}
1317
-
1318
- //func TestPatch_length(t *testing.T) {
1319
- // program, err := expr.Compile(
1320
- // `String.length == 5`,
1321
- // expr.Env(mockEnv{}),
1322
- // expr.Patch(&lengthPatcher{}),
1323
- // )
1324
- // require.NoError(t, err)
1325
- //
1326
- // env := mockEnv{String: "hello"}
1327
- // output, err := expr.Run(program, env)
1328
- // require.NoError(t, err)
1329
- // require.Equal(t, true, output)
1330
- //}
1306
+ var stringer = reflect .TypeOf ((* fmt .Stringer )(nil )).Elem ()
1307
+
1308
+ type stringerPatcher struct {}
1309
+
1310
+ func (p * stringerPatcher ) Enter (_ * ast.Node ) {}
1311
+ func (p * stringerPatcher ) Exit (node * ast.Node ) {
1312
+ t := (* node ).Type ()
1313
+ if t == nil {
1314
+ return
1315
+ }
1316
+ if t .Implements (stringer ) {
1317
+ ast .Patch (node , & ast.CallNode {
1318
+ Callee : & ast.MemberNode {
1319
+ Node : * node ,
1320
+ Property : & ast.StringNode {Value : "String" },
1321
+ },
1322
+ })
1323
+ }
1324
+ }
1325
+
1326
+ func TestPatch (t * testing.T ) {
1327
+ program , err := expr .Compile (
1328
+ `Ticket == "$100" and "$90" != Ticket + "0"` ,
1329
+ expr .Env (mockEnv {}),
1330
+ expr .Patch (& stringerPatcher {}),
1331
+ )
1332
+ require .NoError (t , err )
1333
+
1334
+ env := mockEnv {
1335
+ Ticket : & ticket {Price : 100 },
1336
+ }
1337
+ output , err := expr .Run (program , env )
1338
+ require .NoError (t , err )
1339
+ require .Equal (t , true , output )
1340
+ }
1341
+
1342
+ type lengthPatcher struct {}
1343
+
1344
+ func (p * lengthPatcher ) Enter (_ * ast.Node ) {}
1345
+ func (p * lengthPatcher ) Exit (node * ast.Node ) {
1346
+ switch n := (* node ).(type ) {
1347
+ case * ast.MemberNode :
1348
+ if prop , ok := n .Property .(* ast.StringNode ); ok && prop .Value == "length" {
1349
+ ast .Patch (node , & ast.BuiltinNode {
1350
+ Name : "len" ,
1351
+ Arguments : []ast.Node {n .Node },
1352
+ })
1353
+ }
1354
+ }
1355
+ }
1356
+
1357
+ func TestPatch_length (t * testing.T ) {
1358
+ program , err := expr .Compile (
1359
+ `String.length == 5` ,
1360
+ expr .Env (mockEnv {}),
1361
+ expr .Patch (& lengthPatcher {}),
1362
+ )
1363
+ require .NoError (t , err )
1364
+
1365
+ env := mockEnv {String : "hello" }
1366
+ output , err := expr .Run (program , env )
1367
+ require .NoError (t , err )
1368
+ require .Equal (t , true , output )
1369
+ }
1331
1370
1332
1371
func TestCompile_exposed_error (t * testing.T ) {
1333
1372
_ , err := expr .Compile (`1 == true` )
@@ -1516,7 +1555,9 @@ func (*mockEnv) Float(i interface{}) float64 {
1516
1555
}
1517
1556
}
1518
1557
1519
- func (* mockEnv ) Format (t time.Time ) string { return t .Format (time .RFC822 ) }
1558
+ func (* mockEnv ) Format (t time.Time ) string {
1559
+ return t .Format (time .RFC822 )
1560
+ }
1520
1561
1521
1562
type ticket struct {
1522
1563
Price int
@@ -1573,37 +1614,3 @@ func (p *patcher) Exit(node *ast.Node) {
1573
1614
})
1574
1615
}
1575
1616
}
1576
-
1577
- //
1578
- //var stringer = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
1579
- //
1580
- //type stringerPatcher struct{}
1581
- //
1582
- //func (p *stringerPatcher) Enter(_ *ast.Node) {}
1583
- //func (p *stringerPatcher) Exit(node *ast.Node) {
1584
- // t := (*node).Type()
1585
- // if t == nil {
1586
- // return
1587
- // }
1588
- // if t.Implements(stringer) {
1589
- // ast.Patch(node, &ast.MethodNode{
1590
- // Node: *node,
1591
- // Method: "String",
1592
- // })
1593
- // }
1594
- //}
1595
- //
1596
- //type lengthPatcher struct{}
1597
- //
1598
- //func (p *lengthPatcher) Enter(_ *ast.Node) {}
1599
- //func (p *lengthPatcher) Exit(node *ast.Node) {
1600
- // switch n := (*node).(type) {
1601
- // case *ast.MemberNode:
1602
- // if n.Property == "length" {
1603
- // ast.Patch(node, &ast.BuiltinNode{
1604
- // Name: "len",
1605
- // Arguments: []ast.Node{n.Node},
1606
- // })
1607
- // }
1608
- // }
1609
- //}
0 commit comments