diff --git a/README.md b/README.md
index d45cb46..0354176 100644
--- a/README.md
+++ b/README.md
@@ -6,6 +6,7 @@ yap - Yet Another Go/Go+ HTTP Web Framework
[](https://github.com/goplus/yap/releases)
[](https://codecov.io/gh/goplus/yap)
[](https://pkg.go.dev/github.com/goplus/yap)
+[](https://github.com/goplus/gop)
This repo contains three [Go+ classfiles](https://github.com/goplus/gop/blob/main/doc/classfile.md): `yap` (a HTTP Web Framework), `yaptest` (a HTTP Test Framework) and `ydb` (a Go+ Database Framework).
@@ -36,7 +37,7 @@ gop get github.com/goplus/yap@latest
Create a file named [get.yap](demo/classfile2_hello/get.yap) with the following content:
-```coffee
+```go
html `
Hello, YAP!`
```
diff --git a/ytest/README.md b/ytest/README.md
index 3685e8c..90f99df 100644
--- a/ytest/README.md
+++ b/ytest/README.md
@@ -1,5 +1,9 @@
yaptest - Go+ HTTP Test Framework
=====
+[](https://github.com/goplus/gop)
+[](https://github.com/goplus/gop/releases)
+[](https://discord.gg/mYjWCJDcAr)
+[](https://pkg.go.dev/github.com/goplus/yap/ytest)
yaptest is a web server testing framework. This classfile has the file suffix `_ytest.gox`.
@@ -48,7 +52,7 @@ json {
The directive `testServer` creates the web server by [net/http/httptest](https://pkg.go.dev/net/http/httptest#NewServer) and obtained a random port as the service address. Then it calls the directive [host](https://pkg.go.dev/github.com/goplus/yap/ytest#App.Host) to map the random service address to `foo.com`. This makes all other code no need to changed.
-### match
+## match
This is almost the core concept in `yaptest`. It matches two objects.
@@ -103,11 +107,28 @@ Unbound variables are allowed in ``, but cannot appear in `` has not been bound, it will be bound according to the value of the corresponding ``; if the variable has been bound, the values on both sides must match.
-The cornerstone of `yaptest` is matching grammar. Let's look at the next example you saw at the beginning:
+The cornerstone of `yaptest` is matching grammar. Let's look at [the example](demo/match/hello/hello_yapt.gox) you saw at the beginning:
```go
+id := "123"
+get "http://foo.com/p/${id}"
+
ret 200
json {
"id": id,
}
```
+
+It is [equivalent to](demo/match/diveinto/hello_yapt.gox):
+
+```go
+id := "123"
+get "http://foo.com/p/${id}"
+
+send // send request
+match 200, resp.code // assert resp.code == 200
+match "application/json", resp.header.get("Content-Type")
+match { // assert resp.body.id == id
+ "id": id,
+}, resp.body
+```
diff --git a/ytest/demo/match/diveinto/get_p_#id.yap b/ytest/demo/match/diveinto/get_p_#id.yap
new file mode 100644
index 0000000..c0f07b6
--- /dev/null
+++ b/ytest/demo/match/diveinto/get_p_#id.yap
@@ -0,0 +1,3 @@
+json {
+ "id": ${id},
+}
diff --git a/ytest/demo/match/diveinto/gop_autogen.go b/ytest/demo/match/diveinto/gop_autogen.go
new file mode 100644
index 0000000..3b8a9f1
--- /dev/null
+++ b/ytest/demo/match/diveinto/gop_autogen.go
@@ -0,0 +1,69 @@
+// Code generated by gop (Go+); DO NOT EDIT.
+
+package main
+
+import (
+ "fmt"
+ "github.com/goplus/yap"
+ "github.com/goplus/yap/test"
+ "github.com/goplus/yap/ytest"
+ "github.com/qiniu/x/stringutil"
+)
+
+const _ = true
+
+type get_p_id struct {
+ yap.Handler
+ *AppV2
+}
+type hello struct {
+ ytest.Case
+ *App
+}
+type AppV2 struct {
+ yap.AppV2
+}
+//line ytest/demo/match/diveinto/get_p_#id.yap:1
+func (this *get_p_id) Main(_gop_arg0 *yap.Context) {
+ this.Handler.Main(_gop_arg0)
+//line ytest/demo/match/diveinto/get_p_#id.yap:1:1
+ this.Json__1(map[string]string{"id": this.Gop_Env("id")})
+}
+func (this *get_p_id) Classfname() string {
+ return "get_p_#id"
+}
+
+type App struct {
+ ytest.App
+}
+//line ytest/demo/match/diveinto/hello_yapt.gox:1
+func (this *hello) Main() {
+//line ytest/demo/match/diveinto/hello_yapt.gox:1:1
+ this.Mock("foo.com", new(AppV2))
+//line ytest/demo/match/diveinto/hello_yapt.gox:3:1
+ id := "123"
+//line ytest/demo/match/diveinto/hello_yapt.gox:4:1
+ this.Get(stringutil.Concat("http://foo.com/p/", id))
+//line ytest/demo/match/diveinto/hello_yapt.gox:6:1
+ this.Send()
+//line ytest/demo/match/diveinto/hello_yapt.gox:7:1
+ test.Gopt_Case_MatchTBase(this, 200, this.Resp().Code())
+//line ytest/demo/match/diveinto/hello_yapt.gox:8:1
+ test.Gopt_Case_MatchTBase(this, "application/json", this.Resp().Header().Get("Content-Type"))
+//line ytest/demo/match/diveinto/hello_yapt.gox:9:1
+ test.Gopt_Case_MatchAny(this, map[string]string{"id": id}, this.Resp().Body())
+//line ytest/demo/match/diveinto/hello_yapt.gox:13:1
+ fmt.Println("OK")
+}
+func (this *hello) Classfname() string {
+ return "hello"
+}
+func (this *AppV2) Main() {
+ yap.Gopt_AppV2_Main(this, new(get_p_id))
+}
+func (this *App) Main() {
+ ytest.Gopt_App_Main(this, new(hello))
+}
+func main() {
+ new(App).Main()
+}
diff --git a/ytest/demo/match/diveinto/hello_yapt.gox b/ytest/demo/match/diveinto/hello_yapt.gox
new file mode 100644
index 0000000..582ee02
--- /dev/null
+++ b/ytest/demo/match/diveinto/hello_yapt.gox
@@ -0,0 +1,13 @@
+mock "foo.com", new(AppV2)
+
+id := "123"
+get "http://foo.com/p/${id}"
+
+send // send request
+match 200, resp.code // assert resp.code == 200
+match "application/json", resp.header.get("Content-Type")
+match { // assert resp.body.id == id
+ "id": id,
+}, resp.body
+
+echo "OK"
diff --git a/ytest/demo/match/hello/hello_yapt.gox b/ytest/demo/match/hello/hello_yapt.gox
index e661cdb..8426a9f 100644
--- a/ytest/demo/match/hello/hello_yapt.gox
+++ b/ytest/demo/match/hello/hello_yapt.gox
@@ -2,8 +2,10 @@ mock "foo.com", new(AppV2)
id := "123"
get "http://foo.com/p/${id}"
+
ret 200
json {
"id": id,
}
+
echo "OK"