diff --git a/client/client.go b/client/client.go index 027d40b0..307ae8d2 100644 --- a/client/client.go +++ b/client/client.go @@ -276,6 +276,17 @@ func (c *CSAPI) SendRedaction(t TestLike, roomID string, e b.Event, eventID stri return GetJSONFieldStr(t, body, "event_id") } +// SendTyping marks this user as typing until the timeout is reached. If isTyping is false, timeout is ignored. +func (c *CSAPI) SendTyping(t TestLike, roomID string, isTyping bool, timeoutMillis int) { + content := map[string]interface{}{ + "typing": isTyping, + } + if isTyping { + content["timeout"] = timeoutMillis + } + c.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "typing", c.UserID}, WithJSONBody(t, content)) +} + // GetCapbabilities queries the server's capabilities func (c *CSAPI) GetCapabilities(t TestLike) []byte { t.Helper() diff --git a/client/sync.go b/client/sync.go index 99495426..461465f0 100644 --- a/client/sync.go +++ b/client/sync.go @@ -3,6 +3,8 @@ package client import ( "fmt" "net/url" + "reflect" + "sort" "strings" "time" @@ -365,6 +367,32 @@ func SyncRoomAccountDataHas(roomID string, check func(gjson.Result) bool) SyncCh } } +// SyncUsersTyping passes when all users in `userIDs` are typing in the same typing EDU. +// It must see a typing EDU first before returning, even if the list of user IDs is empty. +func SyncUsersTyping(roomID string, userIDs []string) SyncCheckOpt { + // don't sort the input slice the test gave us. + userIDsCopy := make([]string, len(userIDs)) + copy(userIDsCopy, userIDs) + sort.Strings(userIDsCopy) + return SyncEphemeralHas(roomID, func(r gjson.Result) bool { + if r.Get("type").Str != "m.typing" { + return false + } + + var usersSeenTyping []string + for _, item := range r.Get("content").Get("user_ids").Array() { + usersSeenTyping = append(usersSeenTyping, item.Str) + } + // special case to support nil and 0 length slices + if len(usersSeenTyping) == 0 && len(userIDsCopy) == 0 { + return true + } + sort.Strings(userIDsCopy) + sort.Strings(usersSeenTyping) + return reflect.DeepEqual(userIDsCopy, usersSeenTyping) + }) +} + // Check that sync has received a to-device message, // with optional user filtering. // diff --git a/go.mod b/go.mod index ce52cfd6..60fe636f 100644 --- a/go.mod +++ b/go.mod @@ -1,32 +1,46 @@ module github.com/matrix-org/complement -go 1.16 +go 1.18 require ( - github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect - github.com/Microsoft/go-winio v0.5.2 // indirect - github.com/docker/distribution v2.8.2+incompatible // indirect github.com/docker/docker v20.10.24+incompatible github.com/docker/go-connections v0.4.0 - github.com/docker/go-units v0.4.0 // indirect - github.com/gogo/protobuf v1.3.2 // indirect github.com/gorilla/mux v1.8.0 github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530 github.com/matrix-org/gomatrixserverlib v0.0.0-20230921171121-0466775328c7 github.com/matrix-org/util v0.0.0-20221111132719-399730281e66 + github.com/sirupsen/logrus v1.9.3 + github.com/tidwall/gjson v1.16.0 + github.com/tidwall/sjson v1.2.5 + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 + gonum.org/v1/plot v0.11.0 + maunium.net/go/mautrix v0.11.0 +) + +require ( + git.sr.ht/~sbinet/gg v0.3.1 // indirect + github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect + github.com/Microsoft/go-winio v0.5.2 // indirect + github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b // indirect + github.com/docker/distribution v2.8.2+incompatible // indirect + github.com/docker/go-units v0.4.0 // indirect + github.com/go-fonts/liberation v0.2.0 // indirect + github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81 // indirect + github.com/go-pdf/fpdf v0.6.0 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/moby/term v0.0.0-20210610120745-9d4ed1856297 // indirect github.com/morikuni/aec v1.0.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect - github.com/sirupsen/logrus v1.9.3 - github.com/tidwall/gjson v1.16.0 + github.com/pkg/errors v0.9.1 // indirect + github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.1 // indirect - github.com/tidwall/sjson v1.2.5 golang.org/x/crypto v0.13.0 // indirect - golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 // indirect golang.org/x/image v0.5.0 // indirect + golang.org/x/net v0.10.0 // indirect + golang.org/x/sys v0.12.0 // indirect + golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect - gonum.org/v1/plot v0.11.0 gotest.tools/v3 v3.0.3 // indirect - maunium.net/go/mautrix v0.11.0 ) diff --git a/go.sum b/go.sum index a3e2ea9b..11b35ba7 100644 --- a/go.sum +++ b/go.sum @@ -1,22 +1,17 @@ -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= git.sr.ht/~sbinet/gg v0.3.1 h1:LNhjNn8DerC8f9DHLz6lS0YYul/b602DUxDgGkd/Aik= git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= -github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b h1:slYM766cy2nI3BwyRiyQj/Ud48djTMtMebDqepE95rw= github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -29,21 +24,14 @@ github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKoh github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= -github.com/frankban/quicktest v1.0.0/go.mod h1:R98jIehRai+d1/3Hv2//jOVCTJhW1VBavT6B6CuGq2k= -github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/go-fonts/dejavu v0.1.0 h1:JSajPXURYqpr+Cu8U9bt8K+XcACIHWqWrvWCKyeFmVQ= github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= github.com/go-fonts/latin-modern v0.2.0 h1:5/Tv1Ek/QCr20C6ZOz15vw3g7GELYL98KWr8Hgo+3vk= github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= -github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= github.com/go-fonts/liberation v0.2.0 h1:jAkAWJP4S+OsrPLZM4/eC9iW7CtHy+HBXrEwZXWo5VM= github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81 h1:6zl3BbBhdnMkpSj2YY30qV3gDcVBGtFgVsV3+/i+mKQ= github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= @@ -53,44 +41,26 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw= -github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= -github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16/go.mod h1:/gBX06Kw0exX1HrwmoBibFA98yBk/jxKpGVeyQbff+s= github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530 h1:kHKxCOLcHH8r4Fzarl4+Y3K5hjothkVW5z7T1dUM11U= github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530/go.mod h1:/gBX06Kw0exX1HrwmoBibFA98yBk/jxKpGVeyQbff+s= github.com/matrix-org/gomatrixserverlib v0.0.0-20230921171121-0466775328c7 h1:NhPNNFLHwdDb/upeicBh1GkxX/sFinEp5HF1WBqPtiY= github.com/matrix-org/gomatrixserverlib v0.0.0-20230921171121-0466775328c7/go.mod h1:H9V9N3Uqn1bBJqYJNGK1noqtgJTaCEhtTdcH/mp50uU= -github.com/matrix-org/util v0.0.0-20200807132607-55161520e1d4/go.mod h1:vVQlW/emklohkZnOPwD3LrZUBqdfsbiyO3p1lNV8F6U= github.com/matrix-org/util v0.0.0-20221111132719-399730281e66 h1:6z4KxomXSIGWqhHcfzExgkH3Z3UkIXry4ibJS4Aqz2Y= github.com/matrix-org/util v0.0.0-20221111132719-399730281e66/go.mod h1:iBI1foelCqA09JJgPV0FYz4qA5dUXYOxMi57FxKBdd4= -github.com/mattn/go-sqlite3 v1.14.13/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= -github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/moby/term v0.0.0-20210610120745-9d4ed1856297 h1:yH0SvLzcbZxcJXho2yh7CqdENGMQe73Cw3woZBpPli0= github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= -github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 h1:rc3tiVYb5z54aKaDfakKn0dDjIyPpTtszkjuMzyt7ec= @@ -103,27 +73,17 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/gjson v1.14.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/gjson v1.14.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.16.0 h1:SyXa+dsSPpUlcwEDuKuEBJEz5vzTvOea+9rjyYodQFg= github.com/tidwall/gjson v1.16.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= @@ -131,172 +91,95 @@ github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JT github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= -github.com/tidwall/sjson v1.2.4/go.mod h1:098SZ494YoMWPmMO6ct4dcFnqxwj9r/gF0Etp19pSNM= github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.12/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -golang.org/x/crypto v0.0.0-20180723164146-c126467f60eb/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220513210258-46612604a0f9/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= -golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/image v0.5.0 h1:5JMiNunQeQw++mMOz48/ISeNu3Iweh/JaZU8ZLqHRrI= golang.org/x/image v0.5.0/go.mod h1:FVC7BI/5Ym8R25iw5OLsgshdUBbT1h5jZTpA+mvAdZ4= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220513224357-95641704303c/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220907140024-f12130a52804/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= -gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= -gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= gonum.org/v1/gonum v0.11.0 h1:f1IJhK4Km5tBJmaiJXtk/PkL4cdVX6J+tGiM187uT5E= -gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA= -gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= -gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= -gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= -gonum.org/v1/plot v0.10.1/go.mod h1:VZW5OlhkL1mysU9vaqNHnsy86inf6Ot+jB3r+BczCEo= gonum.org/v1/plot v0.11.0 h1:z2ZkgNqW34d0oYUzd80RRlc0L9kWtenqK4kflZG1lGc= gonum.org/v1/plot v0.11.0/go.mod h1:fH9YnKnDKax0u5EzHVXvhN5HJwtMFWIOLNuhgUahbCQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/h2non/gock.v1 v1.1.2 h1:jBbHXgGBK/AoPVfJh5x4r/WxIrElvbLel8TCZkkZJoY= -gopkg.in/h2non/gock.v1 v1.1.2/go.mod h1:n7UGz/ckNChHiK05rDoiC4MYSunEC/lyaUm2WWaDva0= -gopkg.in/macaroon.v2 v2.1.0/go.mod h1:OUb+TQP/OP0WOerC2Jp/3CwhIKyIa9kQjuc7H24e6/o= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= -maunium.net/go/maulogger/v2 v2.3.2/go.mod h1:TYWy7wKwz/tIXTpsx8G3mZseIRiC5DoMxSZazOHy68A= maunium.net/go/mautrix v0.11.0 h1:B1FBHcvE4Mud+AC+zgNQQOw0JxSVrt40watCejhVA7w= maunium.net/go/mautrix v0.11.0/go.mod h1:K29EcHwsNg6r7fMfwvi0GHQ9o5wSjqB9+Q8RjCIQEjA= rsc.io/pdf v0.1.1 h1:k1MczvYDUvJBe93bYd7wrZLLUEcLZAuF824/I4e5Xr4= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/internal/match/http.go b/match/http.go similarity index 100% rename from internal/match/http.go rename to match/http.go diff --git a/internal/match/json.go b/match/json.go similarity index 75% rename from internal/match/json.go rename to match/json.go index 068000ee..3b1b3829 100644 --- a/internal/match/json.go +++ b/match/json.go @@ -1,3 +1,21 @@ +// package match contains matchers for HTTP and JSON data. +// +// Matchers are composable functions which check for the data specified, returning a golang error if a matcher fails. +// They are typically used with the 'must' package in the following way: +// +// res := user.Do(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.server_acl"}) +// must.MatchResponse(t, res, match.HTTPResponse{ +// StatusCode: 200, +// JSON: []match.JSON{ +// match.JSONKeyEqual("allow", []string{"*"}), +// match.JSONKeyEqual("deny", []string{"hs2"}), +// match.JSONKeyEqual("allow_ip_literals", true), +// }, +// }) +// +// Matchers have no concept of tests, and do not automatically fail tests if the match fails. This can be useful +// when you want to repeatedly perform a check until it succeeds (e.g from /sync). If you want matches to fail a test, +// you can use the 'must' package. package match import ( @@ -11,45 +29,36 @@ import ( // JSON will perform some matches on the given JSON body, returning an error on a mis-match. // It can be assumed that the bytes are valid JSON. -type JSON func(body []byte) error +type JSON func(body gjson.Result) error // JSONKeyEqual returns a matcher which will check that `wantKey` is present and its value matches `wantValue`. // `wantKey` can be nested, see https://godoc.org/github.com/tidwall/gjson#Get for details. // `wantValue` is matched via JSONDeepEqual and the JSON takes the forms according to https://godoc.org/github.com/tidwall/gjson#Result.Value func JSONKeyEqual(wantKey string, wantValue interface{}) JSON { - return func(body []byte) error { - res := gjson.GetBytes(body, wantKey) + return func(body gjson.Result) error { + res := body + if wantKey != "" { + res = body.Get(wantKey) + } if !res.Exists() { return fmt.Errorf("key '%s' missing", wantKey) } gotValue := res.Value() - if !JSONDeepEqual([]byte(res.Raw), wantValue) { + if !jsonDeepEqual([]byte(res.Raw), wantValue) { return fmt.Errorf( "key '%s' got '%v' (type %T) want '%v' (type %T)", wantKey, gotValue, gotValue, wantValue, wantValue, ) - } else { - return nil } + return nil } } -// JSONDeepEqual compares raw json with a json-serializable value, seeing if they're equal. -func JSONDeepEqual(gotJson []byte, wantValue interface{}) bool { - // marshal what the test gave us - wantBytes, _ := json.Marshal(wantValue) - // re-marshal what the network gave us to acount for key ordering - var gotVal interface{} - _ = json.Unmarshal(gotJson, &gotVal) - gotBytes, _ := json.Marshal(gotVal) - return bytes.Equal(gotBytes, wantBytes) -} - // JSONKeyPresent returns a matcher which will check that `wantKey` is present in the JSON object. // `wantKey` can be nested, see https://godoc.org/github.com/tidwall/gjson#Get for details. func JSONKeyPresent(wantKey string) JSON { - return func(body []byte) error { - res := gjson.GetBytes(body, wantKey) + return func(body gjson.Result) error { + res := body.Get(wantKey) if !res.Exists() { return fmt.Errorf("key '%s' missing", wantKey) } @@ -60,8 +69,8 @@ func JSONKeyPresent(wantKey string) JSON { // JSONKeyMissing returns a matcher which will check that `forbiddenKey` is not present in the JSON object. // `forbiddenKey` can be nested, see https://godoc.org/github.com/tidwall/gjson#Get for details. func JSONKeyMissing(forbiddenKey string) JSON { - return func(body []byte) error { - res := gjson.GetBytes(body, forbiddenKey) + return func(body gjson.Result) error { + res := body.Get(forbiddenKey) if res.Exists() { return fmt.Errorf("key '%s' present", forbiddenKey) } @@ -72,8 +81,8 @@ func JSONKeyMissing(forbiddenKey string) JSON { // JSONKeyTypeEqual returns a matcher which will check that `wantKey` is present and its value is of the type `wantType`. // `wantKey` can be nested, see https://godoc.org/github.com/tidwall/gjson#Get for details. func JSONKeyTypeEqual(wantKey string, wantType gjson.Type) JSON { - return func(body []byte) error { - res := gjson.GetBytes(body, wantKey) + return func(body gjson.Result) error { + res := body.Get(wantKey) if !res.Exists() { return fmt.Errorf("key '%s' missing", wantKey) } @@ -88,8 +97,8 @@ func JSONKeyTypeEqual(wantKey string, wantType gjson.Type) JSON { // its value is an array with the given size. // `wantKey` can be nested, see https://godoc.org/github.com/tidwall/gjson#Get for details. func JSONKeyArrayOfSize(wantKey string, wantSize int) JSON { - return func(body []byte) error { - res := gjson.GetBytes(body, wantKey) + return func(body gjson.Result) error { + res := body.Get(wantKey) if !res.Exists() { return fmt.Errorf("key '%s' missing", wantKey) } @@ -105,8 +114,8 @@ func JSONKeyArrayOfSize(wantKey string, wantSize int) JSON { } func jsonCheckOffInternal(wantKey string, wantItems []interface{}, allowUnwantedItems bool, mapper func(gjson.Result) interface{}, fn func(interface{}, gjson.Result) error) JSON { - return func(body []byte) error { - res := gjson.GetBytes(body, wantKey) + return func(body gjson.Result) error { + res := body.Get(wantKey) if !res.Exists() { return fmt.Errorf("JSONCheckOff: missing key '%s'", wantKey) } @@ -130,7 +139,7 @@ func jsonCheckOffInternal(wantKey string, wantItems []interface{}, allowUnwanted want := -1 for i, w := range wantItems { wBytes, _ := json.Marshal(w) - if JSONDeepEqual(wBytes, item) { + if jsonDeepEqual(wBytes, item) { want = i break } @@ -166,6 +175,7 @@ func jsonCheckOffInternal(wantKey string, wantItems []interface{}, allowUnwanted } } +// EXPERIMENTAL // JSONCheckOffAllowUnwanted returns a matcher which will loop over `wantKey` and ensure that the items // (which can be array elements or object keys) // are present exactly once in any order in `wantItems`. Allows unexpected items or items @@ -177,17 +187,19 @@ func jsonCheckOffInternal(wantKey string, wantItems []interface{}, allowUnwanted // it's an object). // // Usage: (ensures `events` has these events in any order, with the right event type) -// JSONCheckOffAllowUnwanted("events", []interface{}{"$foo:bar", "$baz:quuz"}, func(r gjson.Result) interface{} { -// return r.Get("event_id").Str -// }, func(eventID interface{}, eventBody gjson.Result) error { -// if eventBody.Get("type").Str != "m.room.message" { -// return fmt.Errorf("expected event to be 'm.room.message'") -// } -// }) +// +// JSONCheckOffAllowUnwanted("events", []interface{}{"$foo:bar", "$baz:quuz"}, func(r gjson.Result) interface{} { +// return r.Get("event_id").Str +// }, func(eventID interface{}, eventBody gjson.Result) error { +// if eventBody.Get("type").Str != "m.room.message" { +// return fmt.Errorf("expected event to be 'm.room.message'") +// } +// }) func JSONCheckOffAllowUnwanted(wantKey string, wantItems []interface{}, mapper func(gjson.Result) interface{}, fn func(interface{}, gjson.Result) error) JSON { return jsonCheckOffInternal(wantKey, wantItems, true, mapper, fn) } +// EXPERIMENTAL // JSONCheckOff returns a matcher which will loop over `wantKey` and ensure that the items // (which can be array elements or object keys) // are present exactly once in any order in `wantItems`. If there are unexpected items or items @@ -199,13 +211,14 @@ func JSONCheckOffAllowUnwanted(wantKey string, wantItems []interface{}, mapper f // it's an object). // // Usage: (ensures `events` has these events in any order, with the right event type) -// JSONCheckOff("events", []interface{}{"$foo:bar", "$baz:quuz"}, func(r gjson.Result) interface{} { -// return r.Get("event_id").Str -// }, func(eventID interface{}, eventBody gjson.Result) error { -// if eventBody.Get("type").Str != "m.room.message" { -// return fmt.Errorf("expected event to be 'm.room.message'") -// } -// }) +// +// JSONCheckOff("events", []interface{}{"$foo:bar", "$baz:quuz"}, func(r gjson.Result) interface{} { +// return r.Get("event_id").Str +// }, func(eventID interface{}, eventBody gjson.Result) error { +// if eventBody.Get("type").Str != "m.room.message" { +// return fmt.Errorf("expected event to be 'm.room.message'") +// } +// }) func JSONCheckOff(wantKey string, wantItems []interface{}, mapper func(gjson.Result) interface{}, fn func(interface{}, gjson.Result) error) JSON { return jsonCheckOffInternal(wantKey, wantItems, false, mapper, fn) } @@ -213,22 +226,19 @@ func JSONCheckOff(wantKey string, wantItems []interface{}, mapper func(gjson.Res // JSONArrayEach returns a matcher which will check that `wantKey` is an array then loops over each // item calling `fn`. If `fn` returns an error, iterating stops and an error is returned. func JSONArrayEach(wantKey string, fn func(gjson.Result) error) JSON { - return func(body []byte) error { - var res gjson.Result - if wantKey == "" { - res = gjson.ParseBytes(body) - } else { - res = gjson.GetBytes(body, wantKey) + return func(body gjson.Result) error { + if wantKey != "" { + body = body.Get(wantKey) } - if !res.Exists() { + if !body.Exists() { return fmt.Errorf("missing key '%s'", wantKey) } - if !res.IsArray() { + if !body.IsArray() { return fmt.Errorf("key '%s' is not an array", wantKey) } var err error - res.ForEach(func(_, val gjson.Result) bool { + body.ForEach(func(_, val gjson.Result) bool { err = fn(val) return err == nil }) @@ -239,8 +249,8 @@ func JSONArrayEach(wantKey string, fn func(gjson.Result) error) JSON { // JSONMapEach returns a matcher which will check that `wantKey` is a map then loops over each // item calling `fn`. If `fn` returns an error, iterating stops and an error is returned. func JSONMapEach(wantKey string, fn func(k, v gjson.Result) error) JSON { - return func(body []byte) error { - res := gjson.GetBytes(body, wantKey) + return func(body gjson.Result) error { + res := body.Get(wantKey) if !res.Exists() { return fmt.Errorf("missing key '%s'", wantKey) } @@ -256,10 +266,11 @@ func JSONMapEach(wantKey string, fn func(k, v gjson.Result) error) JSON { } } +// EXPERIMENTAL // AnyOf takes 1 or more `checkers`, and builds a new checker which accepts a given // json body iff it's accepted by at least one of the original `checkers`. func AnyOf(checkers ...JSON) JSON { - return func(body []byte) error { + return func(body gjson.Result) error { if len(checkers) == 0 { return fmt.Errorf("must provide at least one checker to AnyOf") } @@ -281,3 +292,15 @@ func AnyOf(checkers ...JSON) JSON { return fmt.Errorf(builder.String()) } } + +// jsonDeepEqual compares raw json with a json-serializable value, seeing if they're equal. +// It forces `gotJson` through a JSON parser to ensure keys/whitespace are identical to the marshalled form of `wantValue`. +func jsonDeepEqual(gotJson []byte, wantValue interface{}) bool { + // marshal what the test gave us + wantBytes, _ := json.Marshal(wantValue) + // re-marshal what the network gave us to acount for key ordering + var gotVal interface{} + _ = json.Unmarshal(gotJson, &gotVal) + gotBytes, _ := json.Marshal(gotVal) + return bytes.Equal(gotBytes, wantBytes) +} diff --git a/internal/must/must.go b/must/must.go similarity index 61% rename from internal/must/must.go rename to must/must.go index 4b218c00..5ba0a84a 100644 --- a/internal/must/must.go +++ b/must/must.go @@ -2,19 +2,21 @@ package must import ( + "bytes" "encoding/json" "fmt" "io" - "io/ioutil" "net/http" "strings" "testing" "github.com/tidwall/gjson" + "golang.org/x/exp/slices" "github.com/matrix-org/gomatrixserverlib/fclient" - "github.com/matrix-org/complement/internal/match" + "github.com/matrix-org/complement/client" + "github.com/matrix-org/complement/match" ) // NotError will ensure `err` is nil else terminate the test with `msg`. @@ -25,23 +27,25 @@ func NotError(t *testing.T, msg string, err error) { } } +// EXPERIMENTAL // ParseJSON will ensure that the HTTP request/response body is valid JSON, then return the body, else terminate the test. -func ParseJSON(t *testing.T, b io.ReadCloser) []byte { +func ParseJSON(t *testing.T, b io.ReadCloser) gjson.Result { t.Helper() - body, err := ioutil.ReadAll(b) + body, err := io.ReadAll(b) if err != nil { t.Fatalf("MustParseJSON: reading body returned %s", err) } if !gjson.ValidBytes(body) { t.Fatalf("MustParseJSON: not valid JSON") } - return body + return gjson.ParseBytes(body) } +// EXPERIMENTAL // MatchRequest consumes the HTTP request and performs HTTP-level assertions on it. Returns the raw response body. func MatchRequest(t *testing.T, req *http.Request, m match.HTTPRequest) []byte { t.Helper() - body, err := ioutil.ReadAll(req.Body) + body, err := io.ReadAll(req.Body) if err != nil { t.Fatalf("MatchRequest: Failed to read request body: %s", err) } @@ -59,8 +63,9 @@ func MatchRequest(t *testing.T, req *http.Request, m match.HTTPRequest) []byte { if !gjson.ValidBytes(body) { t.Fatalf("MatchRequest request body is not valid JSON - %s", contextStr) } + parsedBody := gjson.ParseBytes(body) for _, jm := range m.JSON { - if err = jm(body); err != nil { + if err = jm(parsedBody); err != nil { t.Fatalf("MatchRequest %s - %s", err, contextStr) } } @@ -68,6 +73,7 @@ func MatchRequest(t *testing.T, req *http.Request, m match.HTTPRequest) []byte { return body } +// EXPERIMENTAL // MatchSuccess consumes the HTTP response and fails if the response is non-2xx. func MatchSuccess(t *testing.T, res *http.Response) { if res.StatusCode < 200 || res.StatusCode > 299 { @@ -75,6 +81,7 @@ func MatchSuccess(t *testing.T, res *http.Response) { } } +// EXPERIMENTAL // MatchFailure consumes the HTTP response and fails if the response is 2xx. func MatchFailure(t *testing.T, res *http.Response) { if res.StatusCode >= 200 && res.StatusCode <= 299 { @@ -82,10 +89,11 @@ func MatchFailure(t *testing.T, res *http.Response) { } } +// EXPERIMENTAL // MatchResponse consumes the HTTP response and performs HTTP-level assertions on it. Returns the raw response body. func MatchResponse(t *testing.T, res *http.Response, m match.HTTPResponse) []byte { t.Helper() - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) if err != nil { t.Fatalf("MatchResponse: Failed to read response body: %s", err) } @@ -108,8 +116,9 @@ func MatchResponse(t *testing.T, res *http.Response, m match.HTTPResponse) []byt if !gjson.ValidBytes(body) { t.Fatalf("MatchResponse response body is not valid JSON - %s", contextStr) } + parsedBody := gjson.ParseBytes(body) for _, jm := range m.JSON { - if err = jm(body); err != nil { + if err = jm(parsedBody); err != nil { t.Fatalf("MatchResponse %s - %s", err, contextStr) } } @@ -125,27 +134,23 @@ func MatchFederationRequest(t *testing.T, fedReq *fclient.FederationRequest, mat t.Fatalf("MatchFederationRequest content is not valid JSON - %s", fedReq.RequestURI()) } + parsedContent := gjson.ParseBytes(content) for _, jm := range matchers { - if err := jm(content); err != nil { + if err := jm(parsedContent); err != nil { t.Fatalf("MatchFederationRequest %s - %s", err, fedReq.RequestURI()) } } } +// EXPERIMENTAL // MatchGJSON performs JSON assertions on a gjson.Result object. func MatchGJSON(t *testing.T, jsonResult gjson.Result, matchers ...match.JSON) { t.Helper() - MatchJSON(t, jsonResult.Raw, matchers...) -} - -// MatchJSON performs JSON assertions on a raw JSON string. -func MatchJSON(t *testing.T, json string, matchers ...match.JSON) { - t.Helper() - - MatchJSONBytes(t, []byte(json), matchers...) + MatchJSONBytes(t, []byte(jsonResult.Raw), matchers...) } +// EXPERIMENTAL // MatchJSONBytes performs JSON assertions on a raw json byte slice. func MatchJSONBytes(t *testing.T, rawJson []byte, matchers ...match.JSON) { t.Helper() @@ -154,29 +159,33 @@ func MatchJSONBytes(t *testing.T, rawJson []byte, matchers ...match.JSON) { t.Fatalf("MatchJSONBytes: rawJson is not valid JSON") } + body := gjson.ParseBytes(rawJson) for _, jm := range matchers { - if err := jm(rawJson); err != nil { - t.Fatalf("MatchJSONBytes %s", err) + if err := jm(body); err != nil { + t.Fatalf("MatchJSONBytes %s with input = %v", err, string(rawJson)) } } } -// EqualStr ensures that got==want else logs an error. -func EqualStr(t *testing.T, got, want, msg string) { +// Equal ensures that got==want else logs an error. +// The 'msg' is displayed with the error to provide extra context. +func Equal[V comparable](t *testing.T, got, want V, msg string) { t.Helper() if got != want { - t.Errorf("EqualStr %s: got '%s' want '%s'", msg, got, want) + t.Errorf("Equal %s: got '%v' want '%v'", msg, got, want) } } -// NotEqualStr ensures that got!=want else logs an error. -func NotEqualStr(t *testing.T, got, want, msg string) { +// NotEqual ensures that got!=want else logs an error. +// The 'msg' is displayed with the error to provide extra context. +func NotEqual[V comparable](t *testing.T, got, want V, msg string) { t.Helper() if got == want { - t.Errorf("NotEqualStr %s: got '%s', but didn't want it", msg, got) + t.Errorf("NotEqual %s: got '%v', want '%v'", msg, got, want) } } +// EXPERIMENTAL // StartWithStr ensures that got starts with wantPrefix else logs an error. func StartWithStr(t *testing.T, got, wantPrefix, msg string) { t.Helper() @@ -187,31 +196,75 @@ func StartWithStr(t *testing.T, got, wantPrefix, msg string) { // GetJSONFieldStr extracts the string value under `wantKey` or fails the test. // The format of `wantKey` is specified at https://godoc.org/github.com/tidwall/gjson#Get -func GetJSONFieldStr(t *testing.T, body []byte, wantKey string) string { +func GetJSONFieldStr(t *testing.T, body gjson.Result, wantKey string) string { t.Helper() - res := gjson.GetBytes(body, wantKey) + res := body.Get(wantKey) if res.Index == 0 { - t.Fatalf("JSONFieldStr: key '%s' missing from %s", wantKey, string(body)) + t.Fatalf("JSONFieldStr: key '%s' missing from %s", wantKey, body.Raw) } if res.Str == "" { - t.Fatalf("JSONFieldStr: key '%s' is not a string, body: %s", wantKey, string(body)) + t.Fatalf("JSONFieldStr: key '%s' is not a string, body: %s", wantKey, body.Raw) } return res.Str } -// HaveInOrder checks that the two string slices match exactly, failing the test on mismatches or omissions. -func HaveInOrder(t *testing.T, gots []string, wants []string) { +// EXPERIMENTAL +// HaveInOrder checks that the two slices match exactly, failing the test on mismatches or omissions. +func HaveInOrder[V comparable](t *testing.T, gots []V, wants []V) { t.Helper() if len(gots) != len(wants) { - t.Fatalf("HaveEventsInOrder: length mismatch, got %v want %v", gots, wants) + t.Fatalf("HaveInOrder: length mismatch, got %v want %v", gots, wants) } for i := range gots { if gots[i] != wants[i] { - t.Errorf("HaveEventsInOrder: index %d got %s want %s", i, gots[i], wants[i]) + t.Errorf("HaveInOrder: index %d got %v want %v", i, gots[i], wants[i]) + } + } +} + +// EXPERIMENTAL +// ContainSubset checks that every item in smaller is in larger, failing the test if at least 1 item isn't. Ignores extra elements +// in larger. Ignores ordering. +func ContainSubset[V comparable](t *testing.T, larger []V, smaller []V) { + t.Helper() + if len(larger) < len(smaller) { + t.Fatalf("ContainSubset: length mismatch, larger=%d smaller=%d", len(larger), len(smaller)) + } + for i, item := range smaller { + if !slices.Contains(larger, item) { + t.Fatalf("ContainSubset: element not found in larger set: smaller[%d] (%v) larger=%v", i, item, larger) } } } +// EXPERIMENTAL +// NotContainSubset checks that every item in smaller is NOT in larger, failing the test if at least 1 item is. Ignores extra elements +// in larger. Ignores ordering. +func NotContainSubset[V comparable](t *testing.T, larger []V, smaller []V) { + t.Helper() + if len(larger) < len(smaller) { + t.Fatalf("NotContainSubset: length mismatch, larger=%d smaller=%d", len(larger), len(smaller)) + } + for i, item := range smaller { + if slices.Contains(larger, item) { + t.Fatalf("NotContainSubset: element found in larger set: smaller[%d] (%v)", i, item) + } + } +} + +// EXPERIMENTAL +// GetTimelineEventIDs returns the timeline event IDs in the sync response for the given room ID. If the room is missing +// this returns a 0 element slice. +func GetTimelineEventIDs(t *testing.T, topLevelSyncJSON gjson.Result, roomID string) []string { + timeline := topLevelSyncJSON.Get(fmt.Sprintf("rooms.join.%s.timeline.events", client.GjsonEscape(roomID))).Array() + eventIDs := make([]string, len(timeline)) + for i := range timeline { + eventIDs[i] = timeline[i].Get("event_id").Str + } + return eventIDs +} + +// EXPERIMENTAL // CheckOffAll checks that a list contains exactly the given items, in any order. // // if an item is not present, the test is failed. @@ -225,6 +278,7 @@ func CheckOffAll(t *testing.T, items []interface{}, wantItems []interface{}) { } } +// EXPERIMENTAL // CheckOffAllAllowUnwanted checks that a list contains all of the given items, in any order. // The updated list with the matched items removed from it is returned. // @@ -238,16 +292,17 @@ func CheckOffAllAllowUnwanted(t *testing.T, items []interface{}, wantItems []int return items } +// EXPERIMENTAL // CheckOff an item from the list. If the item is not present the test is failed. // The updated list with the matched item removed from it is returned. Items are -// compared using match.JSONDeepEqual +// compared using JSON deep equal. func CheckOff(t *testing.T, items []interface{}, wantItem interface{}) []interface{} { t.Helper() // check off the item want := -1 for i, w := range items { wBytes, _ := json.Marshal(w) - if match.JSONDeepEqual(wBytes, wantItem) { + if jsonDeepEqual(wBytes, wantItem) { want = i break } @@ -260,3 +315,13 @@ func CheckOff(t *testing.T, items []interface{}, wantItem interface{}) []interfa items = append(items[:want], items[want+1:]...) return items } + +func jsonDeepEqual(gotJson []byte, wantValue interface{}) bool { + // marshal what the test gave us + wantBytes, _ := json.Marshal(wantValue) + // re-marshal what the network gave us to acount for key ordering + var gotVal interface{} + _ = json.Unmarshal(gotJson, &gotVal) + gotBytes, _ := json.Marshal(gotVal) + return bytes.Equal(gotBytes, wantBytes) +} diff --git a/tests/csapi/account_change_password_pushers_test.go b/tests/csapi/account_change_password_pushers_test.go index 6b75d579..e7ff0c94 100644 --- a/tests/csapi/account_change_password_pushers_test.go +++ b/tests/csapi/account_change_password_pushers_test.go @@ -8,8 +8,8 @@ import ( "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" "github.com/tidwall/gjson" ) diff --git a/tests/csapi/account_change_password_test.go b/tests/csapi/account_change_password_test.go index efdaeb3c..47e780f7 100644 --- a/tests/csapi/account_change_password_test.go +++ b/tests/csapi/account_change_password_test.go @@ -7,8 +7,8 @@ import ( "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" "github.com/matrix-org/complement/internal/docker" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" "github.com/tidwall/gjson" ) diff --git a/tests/csapi/account_data_test.go b/tests/csapi/account_data_test.go index e79f5371..70680e14 100644 --- a/tests/csapi/account_data_test.go +++ b/tests/csapi/account_data_test.go @@ -4,8 +4,8 @@ import ( "testing" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) func TestAddAccountData(t *testing.T) { diff --git a/tests/csapi/account_deactivate_test.go b/tests/csapi/account_deactivate_test.go index fc3033b0..494c68b8 100644 --- a/tests/csapi/account_deactivate_test.go +++ b/tests/csapi/account_deactivate_test.go @@ -8,8 +8,8 @@ import ( "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) func TestDeactivateAccount(t *testing.T) { diff --git a/tests/csapi/admin_test.go b/tests/csapi/admin_test.go index 5b89a406..6d7d475c 100644 --- a/tests/csapi/admin_test.go +++ b/tests/csapi/admin_test.go @@ -9,8 +9,8 @@ import ( "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) // Check if this homeserver supports Synapse-style admin registration. diff --git a/tests/csapi/apidoc_device_management_test.go b/tests/csapi/apidoc_device_management_test.go index 541f3541..80baa196 100644 --- a/tests/csapi/apidoc_device_management_test.go +++ b/tests/csapi/apidoc_device_management_test.go @@ -7,8 +7,8 @@ import ( "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) func TestDeviceManagement(t *testing.T) { diff --git a/tests/csapi/apidoc_login_test.go b/tests/csapi/apidoc_login_test.go index d8a2f65a..a6bc29b0 100644 --- a/tests/csapi/apidoc_login_test.go +++ b/tests/csapi/apidoc_login_test.go @@ -7,10 +7,10 @@ import ( "github.com/tidwall/gjson" - "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/client" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) func TestLogin(t *testing.T) { @@ -145,9 +145,8 @@ func TestLogin(t *testing.T) { "password": "superuser" }`))) // extract access_token - body := must.ParseJSON(t, res.Body) + js := must.ParseJSON(t, res.Body) defer res.Body.Close() - js := gjson.ParseBytes(body) unauthedClient.UserID = js.Get("user_id").Str unauthedClient.AccessToken = js.Get("access_token").Str // check that we can successfully query /whoami diff --git a/tests/csapi/apidoc_logout_test.go b/tests/csapi/apidoc_logout_test.go index 9d883761..14925d11 100644 --- a/tests/csapi/apidoc_logout_test.go +++ b/tests/csapi/apidoc_logout_test.go @@ -8,8 +8,8 @@ import ( "github.com/tidwall/gjson" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) func TestLogout(t *testing.T) { diff --git a/tests/csapi/apidoc_presence_test.go b/tests/csapi/apidoc_presence_test.go index ec64a9f4..85457d3f 100644 --- a/tests/csapi/apidoc_presence_test.go +++ b/tests/csapi/apidoc_presence_test.go @@ -12,8 +12,8 @@ import ( "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) func TestPresence(t *testing.T) { diff --git a/tests/csapi/apidoc_profile_avatar_url_test.go b/tests/csapi/apidoc_profile_avatar_url_test.go index 06e91cb9..f7bc3d75 100644 --- a/tests/csapi/apidoc_profile_avatar_url_test.go +++ b/tests/csapi/apidoc_profile_avatar_url_test.go @@ -5,8 +5,8 @@ import ( "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) func TestProfileAvatarURL(t *testing.T) { diff --git a/tests/csapi/apidoc_profile_displayname_test.go b/tests/csapi/apidoc_profile_displayname_test.go index 7762e7fb..3b224852 100644 --- a/tests/csapi/apidoc_profile_displayname_test.go +++ b/tests/csapi/apidoc_profile_displayname_test.go @@ -5,8 +5,8 @@ import ( "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) func TestProfileDisplayName(t *testing.T) { diff --git a/tests/csapi/apidoc_register_test.go b/tests/csapi/apidoc_register_test.go index 96f65ded..34de38b2 100644 --- a/tests/csapi/apidoc_register_test.go +++ b/tests/csapi/apidoc_register_test.go @@ -13,10 +13,10 @@ import ( "github.com/tidwall/gjson" - "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/client" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) // TODO: @@ -312,9 +312,9 @@ func registerSharedSecret(t *testing.T, c *client.CSAPI, user, pass string, isAd return resp } body := must.ParseJSON(t, resp.Body) - nonce := gjson.GetBytes(body, "nonce") + nonce := body.Get("nonce") if !nonce.Exists() { - t.Fatalf("Malformed shared secret GET response: %s", string(body)) + t.Fatalf("Malformed shared secret GET response: %s", body.Raw) } mac := hmac.New(sha1.New, []byte(client.SharedSecret)) mac.Write([]byte(nonce.Str)) diff --git a/tests/csapi/apidoc_request_encoding_test.go b/tests/csapi/apidoc_request_encoding_test.go index 33534383..e180ab33 100644 --- a/tests/csapi/apidoc_request_encoding_test.go +++ b/tests/csapi/apidoc_request_encoding_test.go @@ -7,8 +7,8 @@ import ( "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) func TestRequestEncodingFails(t *testing.T) { diff --git a/tests/csapi/apidoc_room_alias_test.go b/tests/csapi/apidoc_room_alias_test.go index f157d6f0..dc134ee5 100644 --- a/tests/csapi/apidoc_room_alias_test.go +++ b/tests/csapi/apidoc_room_alias_test.go @@ -7,10 +7,10 @@ import ( "github.com/tidwall/gjson" - "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/client" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) func setRoomAliasResp(t *testing.T, c *client.CSAPI, roomID, roomAlias string) *http.Response { @@ -120,8 +120,9 @@ func TestRoomAlias(t *testing.T) { return false } eventResBody := client.ParseJSON(t, res) + parsedEventResBody := gjson.ParseBytes(eventResBody) matcher := match.JSONKeyEqual("aliases", []interface{}{roomAlias}) - err := matcher(eventResBody) + err := matcher(parsedEventResBody) if err != nil { t.Log(err) return false diff --git a/tests/csapi/apidoc_room_create_test.go b/tests/csapi/apidoc_room_create_test.go index 6e7d76d6..eefb8305 100644 --- a/tests/csapi/apidoc_room_create_test.go +++ b/tests/csapi/apidoc_room_create_test.go @@ -7,8 +7,8 @@ import ( "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) func doCreateRoom(t *testing.T, c *client.CSAPI, json map[string]interface{}, match match.HTTPResponse) { diff --git a/tests/csapi/apidoc_room_forget_test.go b/tests/csapi/apidoc_room_forget_test.go index 197a4bf7..dcce4d1f 100644 --- a/tests/csapi/apidoc_room_forget_test.go +++ b/tests/csapi/apidoc_room_forget_test.go @@ -10,8 +10,8 @@ import ( "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) // These tests ensure that forgetting about rooms works as intended diff --git a/tests/csapi/apidoc_room_history_visibility_test.go b/tests/csapi/apidoc_room_history_visibility_test.go index e6ccd18d..1dfb3022 100644 --- a/tests/csapi/apidoc_room_history_visibility_test.go +++ b/tests/csapi/apidoc_room_history_visibility_test.go @@ -8,8 +8,8 @@ import ( "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) // TODO most of this can be refactored into data-driven tests diff --git a/tests/csapi/apidoc_room_members_test.go b/tests/csapi/apidoc_room_members_test.go index 79230f54..48223d1b 100644 --- a/tests/csapi/apidoc_room_members_test.go +++ b/tests/csapi/apidoc_room_members_test.go @@ -5,10 +5,10 @@ import ( "github.com/tidwall/gjson" - "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/client" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) func TestRoomMembers(t *testing.T) { @@ -82,7 +82,7 @@ func TestRoomMembers(t *testing.T) { if ev.Get("type").Str != "m.room.member" || ev.Get("state_key").Str != bob.UserID { return false } - must.EqualStr(t, ev.Get("content").Get("membership").Str, "join", "Bob failed to join the room") + must.Equal(t, ev.Get("content").Get("membership").Str, "join", "Bob failed to join the room") return true }, )) diff --git a/tests/csapi/apidoc_room_state_test.go b/tests/csapi/apidoc_room_state_test.go index 06b7dac2..af33f6cb 100644 --- a/tests/csapi/apidoc_room_state_test.go +++ b/tests/csapi/apidoc_room_state_test.go @@ -10,8 +10,8 @@ import ( "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) func TestRoomState(t *testing.T) { diff --git a/tests/csapi/apidoc_search_test.go b/tests/csapi/apidoc_search_test.go index a2945e60..f7603301 100644 --- a/tests/csapi/apidoc_search_test.go +++ b/tests/csapi/apidoc_search_test.go @@ -9,10 +9,10 @@ import ( "github.com/matrix-org/util" "github.com/tidwall/gjson" - "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/client" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) // Note: In contrast to Sytest, we define a filter.rooms on each search request, this is to mimic @@ -263,7 +263,7 @@ func TestSearch(t *testing.T) { match.JSONKeyEqual("result.content.body", expectedEvents[eventID.(string)]), } for _, jm := range matchers { - if err := jm([]byte(result.Raw)); err != nil { + if err := jm(result); err != nil { return err } } diff --git a/tests/csapi/apidoc_server_capabilities_test.go b/tests/csapi/apidoc_server_capabilities_test.go index b7e1024b..b0ea1620 100644 --- a/tests/csapi/apidoc_server_capabilities_test.go +++ b/tests/csapi/apidoc_server_capabilities_test.go @@ -5,8 +5,8 @@ import ( "testing" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) func TestServerCapabilities(t *testing.T) { diff --git a/tests/csapi/apidoc_version_test.go b/tests/csapi/apidoc_version_test.go index ed756210..635ef318 100644 --- a/tests/csapi/apidoc_version_test.go +++ b/tests/csapi/apidoc_version_test.go @@ -8,8 +8,8 @@ import ( "github.com/tidwall/gjson" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) // https://spec.matrix.org/v1.1/#specification-versions @@ -52,8 +52,8 @@ func TestVersionStructure(t *testing.T) { return nil }), // Check when unstable_features is present if it's an object - func(body []byte) error { - res := gjson.GetBytes(body, "unstable_features") + func(body gjson.Result) error { + res := body.Get("unstable_features") if !res.Exists() { return nil } diff --git a/tests/csapi/device_lists_test.go b/tests/csapi/device_lists_test.go index 8ffecb78..6c9eb00c 100644 --- a/tests/csapi/device_lists_test.go +++ b/tests/csapi/device_lists_test.go @@ -8,8 +8,8 @@ import ( "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" "github.com/matrix-org/complement/internal/docker" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" "github.com/matrix-org/complement/runtime" "maunium.net/go/mautrix/crypto/olm" diff --git a/tests/csapi/e2e_key_backup_test.go b/tests/csapi/e2e_key_backup_test.go index fbf6c594..d61cf32f 100644 --- a/tests/csapi/e2e_key_backup_test.go +++ b/tests/csapi/e2e_key_backup_test.go @@ -4,12 +4,10 @@ import ( "fmt" "testing" - "github.com/tidwall/gjson" - - "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/client" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) type backupKey struct { @@ -40,9 +38,9 @@ func TestE2EKeyBackupReplaceRoomKeyRules(t *testing.T) { })) defer res.Body.Close() body := must.ParseJSON(t, res.Body) - backupVersion := gjson.GetBytes(body, "version").Str + backupVersion := body.Get("version").Str if backupVersion == "" { - t.Fatalf("failed to get 'version' key from response: %s", string(body)) + t.Fatalf("failed to get 'version' key from response: %s", body.Raw) } testCases := []struct { diff --git a/tests/csapi/ignored_users_test.go b/tests/csapi/ignored_users_test.go index a1f9fe80..ee75290d 100644 --- a/tests/csapi/ignored_users_test.go +++ b/tests/csapi/ignored_users_test.go @@ -12,8 +12,8 @@ import ( "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) // The Spec says here diff --git a/tests/csapi/invalid_test.go b/tests/csapi/invalid_test.go index e3f4cd6e..80d14240 100644 --- a/tests/csapi/invalid_test.go +++ b/tests/csapi/invalid_test.go @@ -6,8 +6,8 @@ import ( "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" "github.com/matrix-org/complement/runtime" ) diff --git a/tests/csapi/keychanges_test.go b/tests/csapi/keychanges_test.go index 95f9c8af..0666c6c9 100644 --- a/tests/csapi/keychanges_test.go +++ b/tests/csapi/keychanges_test.go @@ -10,8 +10,8 @@ import ( "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) func TestKeyChangesLocal(t *testing.T) { diff --git a/tests/csapi/media_misc_test.go b/tests/csapi/media_misc_test.go index 61159da0..c244abfd 100644 --- a/tests/csapi/media_misc_test.go +++ b/tests/csapi/media_misc_test.go @@ -9,8 +9,8 @@ import ( "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" "github.com/matrix-org/complement/internal/data" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" "github.com/matrix-org/complement/runtime" ) diff --git a/tests/csapi/power_levels_test.go b/tests/csapi/power_levels_test.go index dd24c8c5..772a5596 100644 --- a/tests/csapi/power_levels_test.go +++ b/tests/csapi/power_levels_test.go @@ -6,10 +6,10 @@ import ( "github.com/tidwall/gjson" - "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/client" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) // This test ensures that an authorised (PL 100) user is able to modify the users_default value @@ -92,9 +92,9 @@ func TestPowerLevels(t *testing.T) { } }), - func(body []byte) error { - userDefault := int(gjson.GetBytes(body, "users_default").Num) - thisUser := int(gjson.GetBytes(body, "users."+client.GjsonEscape(alice.UserID)).Num) + func(body gjson.Result) error { + userDefault := int(body.Get("users_default").Num) + thisUser := int(body.Get("users." + client.GjsonEscape(alice.UserID)).Num) if thisUser > userDefault { return nil diff --git a/tests/csapi/push_test.go b/tests/csapi/push_test.go index 53e63b55..d8c8c33c 100644 --- a/tests/csapi/push_test.go +++ b/tests/csapi/push_test.go @@ -9,8 +9,8 @@ import ( "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) // sytest: Getting push rules doesn't corrupt the cache SYN-390 diff --git a/tests/csapi/room_ban_test.go b/tests/csapi/room_ban_test.go index 80e838eb..b64ba97f 100644 --- a/tests/csapi/room_ban_test.go +++ b/tests/csapi/room_ban_test.go @@ -5,8 +5,8 @@ import ( "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) // This is technically a tad different from the sytest, in that it doesnt try to ban a @random_dude:test, diff --git a/tests/csapi/room_kick_test.go b/tests/csapi/room_kick_test.go index 72957fe6..9fdc4a2a 100644 --- a/tests/csapi/room_kick_test.go +++ b/tests/csapi/room_kick_test.go @@ -5,8 +5,8 @@ import ( "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) // sytest: Users cannot kick users from a room they are not in diff --git a/tests/csapi/room_leave_test.go b/tests/csapi/room_leave_test.go index 2cd7870a..30d3ac6c 100644 --- a/tests/csapi/room_leave_test.go +++ b/tests/csapi/room_leave_test.go @@ -9,8 +9,8 @@ import ( "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) func TestLeftRoomFixture(t *testing.T) { diff --git a/tests/csapi/room_members_test.go b/tests/csapi/room_members_test.go index 0419955b..8958faaa 100644 --- a/tests/csapi/room_members_test.go +++ b/tests/csapi/room_members_test.go @@ -7,10 +7,10 @@ import ( "github.com/tidwall/gjson" - "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/client" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) // Maps every object by extracting `type` and `state_key` into a "$type|$state_key" string. @@ -43,7 +43,7 @@ func TestGetRoomMembers(t *testing.T) { must.MatchResponse(t, resp, match.HTTPResponse{ JSON: []match.JSON{ match.JSONArrayEach("chunk.#.room_id", func(result gjson.Result) error { - must.EqualStr(t, result.Str, roomID, "unexpected roomID") + must.Equal(t, result.Str, roomID, "unexpected roomID") return nil }), match.JSONCheckOff("chunk", @@ -103,7 +103,7 @@ func TestGetRoomMembersAtPoint(t *testing.T) { must.MatchResponse(t, resp, match.HTTPResponse{ JSON: []match.JSON{ match.JSONArrayEach("chunk.#.room_id", func(result gjson.Result) error { - must.EqualStr(t, result.Str, roomID, "unexpected roomID") + must.Equal(t, result.Str, roomID, "unexpected roomID") return nil }), match.JSONCheckOff("chunk", @@ -150,7 +150,7 @@ func TestGetFilteredRoomMembers(t *testing.T) { must.MatchResponse(t, resp, match.HTTPResponse{ JSON: []match.JSON{ match.JSONArrayEach("chunk.#.room_id", func(result gjson.Result) error { - must.EqualStr(t, result.Str, roomID, "unexpected roomID") + must.Equal(t, result.Str, roomID, "unexpected roomID") return nil }), match.JSONCheckOff("chunk", @@ -175,7 +175,7 @@ func TestGetFilteredRoomMembers(t *testing.T) { must.MatchResponse(t, resp, match.HTTPResponse{ JSON: []match.JSON{ match.JSONArrayEach("chunk.#.room_id", func(result gjson.Result) error { - must.EqualStr(t, result.Str, roomID, "unexpected roomID") + must.Equal(t, result.Str, roomID, "unexpected roomID") return nil }), match.JSONCheckOff("chunk", @@ -200,7 +200,7 @@ func TestGetFilteredRoomMembers(t *testing.T) { must.MatchResponse(t, resp, match.HTTPResponse{ JSON: []match.JSON{ match.JSONArrayEach("chunk.#.room_id", func(result gjson.Result) error { - must.EqualStr(t, result.Str, roomID, "unexpected roomID") + must.Equal(t, result.Str, roomID, "unexpected roomID") return nil }), match.JSONCheckOff("chunk", diff --git a/tests/csapi/room_messages_relation_filter_test.go b/tests/csapi/room_messages_relation_filter_test.go index e64b0bf4..6d04cc86 100644 --- a/tests/csapi/room_messages_relation_filter_test.go +++ b/tests/csapi/room_messages_relation_filter_test.go @@ -12,8 +12,8 @@ import ( "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" "github.com/matrix-org/complement/runtime" ) diff --git a/tests/csapi/room_messages_test.go b/tests/csapi/room_messages_test.go index 8edf50c8..506a2657 100644 --- a/tests/csapi/room_messages_test.go +++ b/tests/csapi/room_messages_test.go @@ -10,8 +10,8 @@ import ( "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" "github.com/matrix-org/complement/runtime" ) diff --git a/tests/csapi/room_relations_test.go b/tests/csapi/room_relations_test.go index f2bc76b9..e5bcfd53 100644 --- a/tests/csapi/room_relations_test.go +++ b/tests/csapi/room_relations_test.go @@ -10,8 +10,8 @@ import ( "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" "github.com/matrix-org/complement/runtime" ) diff --git a/tests/csapi/room_threads_test.go b/tests/csapi/room_threads_test.go index b5938744..713b4081 100644 --- a/tests/csapi/room_threads_test.go +++ b/tests/csapi/room_threads_test.go @@ -8,8 +8,8 @@ import ( "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" "github.com/matrix-org/complement/runtime" ) diff --git a/tests/csapi/room_typing_test.go b/tests/csapi/room_typing_test.go index 0300b850..055188b8 100644 --- a/tests/csapi/room_typing_test.go +++ b/tests/csapi/room_typing_test.go @@ -3,12 +3,8 @@ package csapi_tests import ( "testing" - "github.com/tidwall/gjson" - - "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/client" ) // sytest: PUT /rooms/:room_id/typing/:user_id sets typing notification @@ -24,50 +20,17 @@ func TestTyping(t *testing.T) { bob.JoinRoom(t, roomID, nil) token := bob.MustSyncUntil(t, client.SyncReq{}, client.SyncJoinedTo(bob.UserID, roomID)) - - alice.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "typing", alice.UserID}, client.WithJSONBody(t, map[string]interface{}{ - "typing": true, - "timeout": 10000, - })) + alice.SendTyping(t, roomID, true, 10000) // sytest: Typing notification sent to local room members t.Run("Typing notification sent to local room members", func(t *testing.T) { - var usersSeenTyping []interface{} - - bob.MustSyncUntil(t, client.SyncReq{Since: token}, client.SyncEphemeralHas(roomID, func(result gjson.Result) bool { - if result.Get("type").Str != "m.typing" { - return false - } - - var res = false - - for _, item := range result.Get("content").Get("user_ids").Array() { - usersSeenTyping = append(usersSeenTyping, item.Str) - - if item.Str == alice.UserID { - res = true - } - } - - return res - })) - - must.CheckOffAll(t, usersSeenTyping, []interface{}{alice.UserID}) + bob.MustSyncUntil(t, client.SyncReq{Since: token}, client.SyncUsersTyping(roomID, []string{alice.UserID})) }) // sytest: Typing can be explicitly stopped t.Run("Typing can be explicitly stopped", func(t *testing.T) { - alice.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "typing", alice.UserID}, client.WithJSONBody(t, map[string]interface{}{ - "typing": false, - })) - - bob.MustSyncUntil(t, client.SyncReq{Since: token}, client.SyncEphemeralHas(roomID, func(result gjson.Result) bool { - if result.Get("type").Str != "m.typing" { - return false - } - - return len(result.Get("content").Get("user_ids").Array()) == 0 - })) + alice.SendTyping(t, roomID, false, 0) + bob.MustSyncUntil(t, client.SyncReq{Since: token}, client.SyncUsersTyping(roomID, []string{})) }) } @@ -89,41 +52,13 @@ func TestLeakyTyping(t *testing.T) { _, charlieToken := charlie.MustSync(t, client.SyncReq{TimeoutMillis: "0"}) // Alice types in that room. Bob should see her typing. - alice.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "typing", alice.UserID}, client.WithJSONBody(t, map[string]interface{}{ - "typing": true, - "timeout": 10000, - })) - - bob.MustSyncUntil(t, client.SyncReq{Since: bobToken}, client.SyncEphemeralHas(roomID, func(result gjson.Result) bool { - if result.Get("type").Str != "m.typing" { - return false - } - - err := match.JSONCheckOff("content.user_ids", []interface{}{ - alice.UserID, - }, func(result gjson.Result) interface{} { - return result.Str - }, nil)([]byte(result.Raw)) - - return err == nil - })) - - // Charlie is not in the room, so should not see Alice typing. - res, _ := charlie.MustSync(t, client.SyncReq{TimeoutMillis: "2000", Since: charlieToken}) - - err := client.SyncEphemeralHas(roomID, func(result gjson.Result) bool { - if result.Get("type").Str != "m.typing" { - return false - } - for _, item := range result.Get("content").Get("user_ids").Array() { - if item.Str == charlie.UserID { - return true - } - } - return false - })(charlie.UserID, res) - - if err == nil { - t.Fatalf("Received unexpected typing notification: %s", res.Raw) + alice.SendTyping(t, roomID, true, 10000) + + bob.MustSyncUntil(t, client.SyncReq{Since: bobToken}, client.SyncUsersTyping(roomID, []string{alice.UserID})) + + // Charlie is not in the room, so should not see Alice typing, or anything from that room at all. + res, _ := charlie.MustSync(t, client.SyncReq{TimeoutMillis: "1000", Since: charlieToken}) + if res.Get("rooms.join." + client.GjsonEscape(roomID)).Exists() { + t.Fatalf("Received unexpected room: %s", res.Raw) } } diff --git a/tests/csapi/rooms_invite_test.go b/tests/csapi/rooms_invite_test.go index dd33c39c..99840acf 100644 --- a/tests/csapi/rooms_invite_test.go +++ b/tests/csapi/rooms_invite_test.go @@ -6,8 +6,8 @@ import ( "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" "github.com/tidwall/gjson" ) diff --git a/tests/csapi/rooms_state_test.go b/tests/csapi/rooms_state_test.go index 6585da53..c987effb 100644 --- a/tests/csapi/rooms_state_test.go +++ b/tests/csapi/rooms_state_test.go @@ -9,9 +9,9 @@ import ( "github.com/tidwall/gjson" - "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/client" + "github.com/matrix-org/complement/must" ) func TestRoomCreationReportsEventsToMyself(t *testing.T) { @@ -32,8 +32,8 @@ func TestRoomCreationReportsEventsToMyself(t *testing.T) { if ev.Get("type").Str != "m.room.create" { return false } - must.EqualStr(t, ev.Get("sender").Str, userID, "wrong sender") - must.EqualStr(t, ev.Get("content").Get("creator").Str, userID, "wrong content.creator") + must.Equal(t, ev.Get("sender").Str, userID, "wrong sender") + must.Equal(t, ev.Get("content").Get("creator").Str, userID, "wrong content.creator") return true })) }) @@ -46,9 +46,9 @@ func TestRoomCreationReportsEventsToMyself(t *testing.T) { if ev.Get("type").Str != "m.room.member" { return false } - must.EqualStr(t, ev.Get("sender").Str, userID, "wrong sender") - must.EqualStr(t, ev.Get("state_key").Str, userID, "wrong state_key") - must.EqualStr(t, ev.Get("content").Get("membership").Str, "join", "wrong content.membership") + must.Equal(t, ev.Get("sender").Str, userID, "wrong sender") + must.Equal(t, ev.Get("state_key").Str, userID, "wrong state_key") + must.Equal(t, ev.Get("content").Get("membership").Str, "join", "wrong content.membership") return true })) }) @@ -74,8 +74,8 @@ func TestRoomCreationReportsEventsToMyself(t *testing.T) { if !ev.Get("state_key").Exists() { return false } - must.EqualStr(t, ev.Get("sender").Str, userID, "wrong sender") - must.EqualStr(t, ev.Get("content").Get("topic").Str, roomTopic, "wrong content.topic") + must.Equal(t, ev.Get("sender").Str, userID, "wrong sender") + must.Equal(t, ev.Get("content").Get("topic").Str, roomTopic, "wrong content.topic") return true })) }) @@ -136,8 +136,7 @@ func TestRoomCreationReportsEventsToMyself(t *testing.T) { func getEventIdForState(t *testing.T, client *client.CSAPI, roomID, evType, stateKey string) *string { res := client.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state"}) - jsonBody := must.ParseJSON(t, res.Body) - result := gjson.ParseBytes(jsonBody) + result := must.ParseJSON(t, res.Body) for _, ev := range result.Array() { if ev.Get("type").Str == evType && ev.Get("state_key").Str == stateKey { diff --git a/tests/csapi/sync_filter_test.go b/tests/csapi/sync_filter_test.go index 42a02bf3..de25a87b 100644 --- a/tests/csapi/sync_filter_test.go +++ b/tests/csapi/sync_filter_test.go @@ -8,8 +8,8 @@ import ( "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) func TestSyncFilter(t *testing.T) { diff --git a/tests/csapi/txnid_test.go b/tests/csapi/txnid_test.go index 82d71934..340a7fab 100644 --- a/tests/csapi/txnid_test.go +++ b/tests/csapi/txnid_test.go @@ -4,9 +4,9 @@ import ( "fmt" "testing" - "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/client" + "github.com/matrix-org/complement/must" "github.com/matrix-org/complement/runtime" "github.com/tidwall/gjson" ) @@ -44,7 +44,7 @@ func TestTxnInEvent(t *testing.T) { t.Fatalf("Event did not have a 'unsigned.transaction_id' on the GET /rooms/%s/event/%s response", roomID, eventID) } - must.EqualStr(t, unsignedTxnId.Str, txnId, fmt.Sprintf("Event had an incorrect 'unsigned.transaction_id' on GET /rooms/%s/event/%s response", eventID, roomID)) + must.Equal(t, unsignedTxnId.Str, txnId, fmt.Sprintf("Event had an incorrect 'unsigned.transaction_id' on GET /rooms/%s/event/%s response", eventID, roomID)) } func mustHaveTransactionIDForEvent(t *testing.T, roomID, eventID, expectedTxnId string) client.SyncCheckOpt { @@ -55,7 +55,7 @@ func mustHaveTransactionIDForEvent(t *testing.T, roomID, eventID, expectedTxnId t.Fatalf("Event %s in room %s should have a 'unsigned.transaction_id', but it did not", eventID, roomID) } - must.EqualStr(t, unsignedTxnId.Str, expectedTxnId, fmt.Sprintf("Event %s in room %s had an incorrect 'unsigned.transaction_id'", eventID, roomID)) + must.Equal(t, unsignedTxnId.Str, expectedTxnId, fmt.Sprintf("Event %s in room %s had an incorrect 'unsigned.transaction_id'", eventID, roomID)) return true } @@ -96,7 +96,7 @@ func TestTxnScopeOnLocalEcho(t *testing.T) { // Create a second client, inheriting the first device ID. c2 := deployment.Client(t, "hs1", "") c2.UserID, c2.AccessToken, c2.DeviceID = c2.LoginUser(t, "alice", "password", client.WithDeviceID(c1.DeviceID)) - must.EqualStr(t, c1.DeviceID, c2.DeviceID, "Device ID should be the same") + must.Equal(t, c1.DeviceID, c2.DeviceID, "Device ID should be the same") // When syncing, we should find the event and it should have the same transaction ID on the second client. c2.MustSyncUntil(t, client.SyncReq{}, mustHaveTransactionIDForEvent(t, roomID, eventID, txnId)) @@ -133,13 +133,13 @@ func TestTxnIdempotencyScopedToDevice(t *testing.T) { // Create a second client, inheriting the first device ID. c2 := deployment.Client(t, "hs1", "") c2.UserID, c2.AccessToken, c2.DeviceID = c2.LoginUser(t, "alice", "password", client.WithDeviceID(c1.DeviceID)) - must.EqualStr(t, c1.DeviceID, c2.DeviceID, "Device ID should be the same") + must.Equal(t, c1.DeviceID, c2.DeviceID, "Device ID should be the same") // send another event with the same txnId via the second client eventID2 := c2.Unsafe_SendEventUnsyncedWithTxnID(t, roomID, event, txnId) // the two events should have the same event IDs as they came from the same device - must.EqualStr(t, eventID2, eventID1, "Expected eventID1 and eventID2 to be the same from two clients sharing the same device ID") + must.Equal(t, eventID2, eventID1, "Expected eventID1 and eventID2 to be the same from two clients sharing the same device ID") } // TestTxnIdempotency tests that PUT requests idempotency follows required semantics @@ -183,17 +183,17 @@ func TestTxnIdempotency(t *testing.T) { // we send the identical event again and should get back the same event ID eventID2 := c1.Unsafe_SendEventUnsyncedWithTxnID(t, roomID1, event1, txnId) - must.EqualStr(t, eventID2, eventID1, "Expected eventID1 and eventID2 to be the same, but they were not") + must.Equal(t, eventID2, eventID1, "Expected eventID1 and eventID2 to be the same, but they were not") // even if we change the content we should still get back the same event ID as transaction ID is the same eventID3 := c1.Unsafe_SendEventUnsyncedWithTxnID(t, roomID1, event2, txnId) - must.EqualStr(t, eventID3, eventID1, "Expected eventID3 and eventID2 to be the same even with different content, but they were not") + must.Equal(t, eventID3, eventID1, "Expected eventID3 and eventID2 to be the same even with different content, but they were not") // if we change the room ID we should be able to use the same transaction ID eventID4 := c1.Unsafe_SendEventUnsyncedWithTxnID(t, roomID2, event1, txnId) - must.NotEqualStr(t, eventID4, eventID3, "Expected eventID4 and eventID3 to be different, but they were not") + must.NotEqual(t, eventID4, eventID3, "Expected eventID4 and eventID3 to be different, but they were not") } // TestTxnIdWithRefreshToken tests that when a client refreshes its access token, @@ -242,5 +242,5 @@ func TestTxnIdWithRefreshToken(t *testing.T) { }, txnId) // The event should have been deduplicated and we should get back the same event ID - must.EqualStr(t, eventID2, eventID1, "Expected eventID1 and eventID2 to be the same from a client using a refresh token") + must.Equal(t, eventID2, eventID1, "Expected eventID1 and eventID2 to be the same from a client using a refresh token") } diff --git a/tests/csapi/upload_keys_test.go b/tests/csapi/upload_keys_test.go index 362be943..4d0775a9 100644 --- a/tests/csapi/upload_keys_test.go +++ b/tests/csapi/upload_keys_test.go @@ -10,8 +10,8 @@ import ( "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" "github.com/matrix-org/complement/runtime" ) diff --git a/tests/csapi/url_preview_test.go b/tests/csapi/url_preview_test.go index a32a18ce..f9bd85f9 100644 --- a/tests/csapi/url_preview_test.go +++ b/tests/csapi/url_preview_test.go @@ -10,12 +10,12 @@ import ( "github.com/gorilla/mux" "github.com/tidwall/gjson" - "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/data" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" "github.com/matrix-org/complement/internal/web" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" "github.com/matrix-org/complement/runtime" ) @@ -80,8 +80,8 @@ func TestUrlPreview(t *testing.T) { match.JSONKeyEqual(e("matrix:image:size"), 2239.0), match.JSONKeyEqual(e("og:image:height"), 129.0), match.JSONKeyEqual(e("og:image:width"), 279.0), - func(body []byte) error { - res := gjson.GetBytes(body, e("og:image")) + func(body gjson.Result) error { + res := body.Get(e("og:image")) if !res.Exists() { return fmt.Errorf("can not find key og:image") } diff --git a/tests/csapi/user_directory_display_names_test.go b/tests/csapi/user_directory_display_names_test.go index 90730985..ba626a0c 100644 --- a/tests/csapi/user_directory_display_names_test.go +++ b/tests/csapi/user_directory_display_names_test.go @@ -9,8 +9,8 @@ import ( "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) const aliceUserID = "@alice:hs1" diff --git a/tests/csapi/user_query_keys_test.go b/tests/csapi/user_query_keys_test.go index 30452e18..8529311d 100644 --- a/tests/csapi/user_query_keys_test.go +++ b/tests/csapi/user_query_keys_test.go @@ -5,8 +5,8 @@ import ( "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) // Endpoint: https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-keys-query diff --git a/tests/direct_messaging_test.go b/tests/direct_messaging_test.go index 77b42c49..2693accb 100644 --- a/tests/direct_messaging_test.go +++ b/tests/direct_messaging_test.go @@ -6,11 +6,11 @@ import ( "testing" "time" - "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/federation" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" "github.com/matrix-org/gomatrixserverlib/fclient" "github.com/matrix-org/gomatrixserverlib/spec" @@ -42,15 +42,7 @@ func TestWriteMDirectAccountData(t *testing.T) { if r.Get("type").Str != "m.direct" { return false } - content := r.Get("content") - rooms := content.Get(bob.UserID) - if !rooms.Exists() || !rooms.IsArray() { - t.Errorf("m.direct event missing rooms array for user %s", bob.UserID) - return false - } - if rooms.Array()[0].Str != roomID { - t.Errorf("m.direct room for %s mismatch: got %v want %v", bob.UserID, rooms.Str, roomID) - } + must.MatchGJSON(t, r, match.JSONKeyEqual("content."+client.GjsonEscape(bob.UserID), []string{roomID})) return true } t.Logf("%s: global account data set; syncing until it arrives", time.Now()) // synapse#13334 diff --git a/tests/federation_acl_test.go b/tests/federation_acl_test.go index 886c52ce..74f265a3 100644 --- a/tests/federation_acl_test.go +++ b/tests/federation_acl_test.go @@ -1,13 +1,12 @@ package tests import ( - "fmt" "testing" - "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/client" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" "github.com/matrix-org/complement/runtime" ) @@ -120,30 +119,17 @@ func TestACLs(t *testing.T) { syncResp, _ := user.MustSync(t, client.SyncReq{}) // we don't expect eventID (blocked) to be in the sync response - events := syncResp.Get(fmt.Sprintf("rooms.join.%s.timeline.events", client.GjsonEscape(roomID))).Array() - for _, ev := range events { - if ev.Get("event_id").Str == eventID { - t.Fatalf("unexpected eventID from ACLed room: %s", eventID) - } - } + events := must.GetTimelineEventIDs(t, syncResp, roomID) + must.NotContainSubset(t, events, []string{eventID}) // also check that our sentinel event is present - var seenSentinelEvent bool - events = syncResp.Get(fmt.Sprintf("rooms.join.%s.timeline.events", client.GjsonEscape(sentinelRoom))).Array() - for _, ev := range events { - if ev.Get("event_id").Str == sentinelEventID { - seenSentinelEvent = true - break - } - } - - if !seenSentinelEvent { - t.Fatalf("expected to see sentinel event but didn't") - } + events = must.GetTimelineEventIDs(t, syncResp, sentinelRoom) + must.ContainSubset(t, events, []string{sentinelEventID}) // Validate the ACL event is actually in the rooms state res := user.Do(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.server_acl"}) must.MatchResponse(t, res, match.HTTPResponse{ + StatusCode: 200, JSON: []match.JSON{ match.JSONKeyEqual("allow", []string{"*"}), match.JSONKeyEqual("deny", []string{"hs2"}), diff --git a/tests/federation_event_auth_test.go b/tests/federation_event_auth_test.go index f4c75921..6404cadb 100644 --- a/tests/federation_event_auth_test.go +++ b/tests/federation_event_auth_test.go @@ -7,7 +7,7 @@ import ( "github.com/matrix-org/complement/b" "github.com/matrix-org/complement/internal/federation" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/must" "github.com/matrix-org/gomatrixserverlib/spec" "github.com/matrix-org/gomatrixserverlib" @@ -92,16 +92,11 @@ func TestEventAuth(t *testing.T) { t.Fatalf("got %d valid auth events (%d total), wanted %d.\n%s\nwant: %s", len(gotAuthEvents), len(eventAuthResp.AuthEvents), len(wantAuthEventIDs), msg, wantAuthEventIDs) } // make sure all the events match - wantIDs := map[string]bool{} - for _, id := range wantAuthEventIDs { - wantIDs[id] = true - } - for _, e := range gotAuthEvents { - delete(wantIDs, e.EventID()) - } - if len(wantIDs) > 0 { - t.Errorf("missing events %v", wantIDs) + gotIDs := make([]string, len(gotAuthEvents)) + for i := range gotIDs { + gotIDs[i] = gotAuthEvents[i].EventID() } + must.ContainSubset(t, gotIDs, wantAuthEventIDs) } t.Run("returns auth events for the requested event", func(t *testing.T) { diff --git a/tests/federation_keys_test.go b/tests/federation_keys_test.go index 61605f71..785565d6 100644 --- a/tests/federation_keys_test.go +++ b/tests/federation_keys_test.go @@ -14,8 +14,8 @@ import ( "github.com/matrix-org/complement/b" "github.com/matrix-org/complement/internal/docker" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) // TODO: @@ -56,13 +56,10 @@ func TestInboundFederationKeys(t *testing.T) { key := v.Get("key") - // Test key existence and string type - if !key.Exists() { - return fmt.Errorf("verify_keys: Key '%s' has no 'key' field", k.Str) - } - if key.Type != gjson.String { - return fmt.Errorf("verify_keys: Key '%s' has 'key' with unexpected type, expected String, got '%s'", k.Str, key.Type.String()) - } + must.MatchGJSON(t, v, + match.JSONKeyPresent("key"), + match.JSONKeyTypeEqual("key", gjson.String), + ) var keyBytes []byte keyBytes, err = base64.RawStdEncoding.DecodeString(key.Str) @@ -79,26 +76,18 @@ func TestInboundFederationKeys(t *testing.T) { return fmt.Errorf("old_verify_keys: Key '%s' has no 'ed25519:' prefix", k.Str) } - expiredTs := v.Get("expired_ts") + must.MatchGJSON(t, v, + match.JSONKeyPresent("expired_ts"), + match.JSONKeyTypeEqual("expired_ts", gjson.Number), + ) - // Test expired_ts existence and number type - if !expiredTs.Exists() { - return fmt.Errorf("old_verify_keys: Key '%s' has no 'expired_ts' field", k.Str) - } - if expiredTs.Type != gjson.Number { - return fmt.Errorf("old_verify_keys: Key '%s' has expired_ts with unexpected type, expected Number, got '%s'", k.Str, expiredTs.Type.String()) - } + must.MatchGJSON(t, v, + match.JSONKeyPresent("key"), + match.JSONKeyTypeEqual("key", gjson.String), + ) key := v.Get("key") - // Test key existence and string type - if !key.Exists() { - return fmt.Errorf("old_verify_keys: Key '%s' has no 'key' field", k.Str) - } - if key.Type != gjson.String { - return fmt.Errorf("old_verify_keys: Key '%s' has 'key' with unexpected type, expected String, got '%s'", k.Str, key.Type.String()) - } - var keyBytes []byte keyBytes, err = base64.RawStdEncoding.DecodeString(key.Str) if err != nil { @@ -193,7 +182,7 @@ func checkKeysAndSignatures(t *testing.T, body []byte, jsonObj gjson.Result, key // Test signatures for all verify_keys, these *have* to exist. for keyName, keyBytes := range keys { - sigBase64 := must.GetJSONFieldStr(t, body, fmt.Sprintf("signatures.hs1.%s", keyName)) + sigBase64 := must.GetJSONFieldStr(t, jsonObj, fmt.Sprintf("signatures.hs1.%s", keyName)) var sigBytes []byte sigBytes, err = base64.RawStdEncoding.DecodeString(sigBase64) diff --git a/tests/federation_query_profile_test.go b/tests/federation_query_profile_test.go index 739997be..db214255 100644 --- a/tests/federation_query_profile_test.go +++ b/tests/federation_query_profile_test.go @@ -12,8 +12,8 @@ import ( "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" "github.com/matrix-org/complement/internal/federation" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) // TODO: diff --git a/tests/federation_redaction_test.go b/tests/federation_redaction_test.go index 5531e3f0..00a86c87 100644 --- a/tests/federation_redaction_test.go +++ b/tests/federation_redaction_test.go @@ -6,6 +6,7 @@ import ( "github.com/matrix-org/complement/b" "github.com/matrix-org/complement/internal/federation" + "github.com/matrix-org/complement/must" "github.com/matrix-org/complement/runtime" "github.com/matrix-org/gomatrixserverlib" ) @@ -31,9 +32,7 @@ func TestFederationRedactSendsWithoutEvent(t *testing.T) { func(ev gomatrixserverlib.PDU) { defer waiter.Finish() - if ev.Type() != wantEventType { - t.Errorf("Wrong event type, got %s want %s", ev.Type(), wantEventType) - } + must.Equal(t, ev.Type(), wantEventType, "wrong event type") }, nil, ), @@ -89,8 +88,5 @@ func TestFederationRedactSendsWithoutEvent(t *testing.T) { } // check that the event id of the redaction sent by alice is the same as the redaction event in the room - if res != lastEvent.EventID() { - t.Fatalf("Incorrent event id %s, wanted %s.", res, lastEvent.EventID()) - } - + must.Equal(t, lastEvent.EventID(), res, "incorrect event id") } diff --git a/tests/federation_room_alias_test.go b/tests/federation_room_alias_test.go index d8ef6d28..6ad1e63b 100644 --- a/tests/federation_room_alias_test.go +++ b/tests/federation_room_alias_test.go @@ -5,8 +5,8 @@ import ( "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) // sytest: Remote room alias queries can handle Unicode diff --git a/tests/federation_room_ban_test.go b/tests/federation_room_ban_test.go index cb69078f..2295870c 100644 --- a/tests/federation_room_ban_test.go +++ b/tests/federation_room_ban_test.go @@ -3,16 +3,14 @@ package tests import ( "testing" - "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/runtime" + "github.com/matrix-org/complement/client" ) // Regression test for https://github.com/matrix-org/synapse/issues/1563 // Create a federation room. Bob bans Alice. Bob unbans Alice. Bob invites Alice (unbanning her). Ensure the invite is // received and can be accepted. func TestUnbanViaInvite(t *testing.T) { - runtime.SkipIf(t, runtime.Synapse) // FIXME: https://github.com/matrix-org/synapse/issues/1563 deployment := Deploy(t, b.BlueprintFederationOneToOneRoom) defer deployment.Destroy(t) diff --git a/tests/federation_room_event_auth_test.go b/tests/federation_room_event_auth_test.go index d85b07ac..923a53fe 100644 --- a/tests/federation_room_event_auth_test.go +++ b/tests/federation_room_event_auth_test.go @@ -20,7 +20,7 @@ import ( "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" "github.com/matrix-org/complement/internal/federation" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/must" ) func TestInboundFederationRejectsEventsWithRejectedAuthEvents(t *testing.T) { diff --git a/tests/federation_room_get_missing_events_test.go b/tests/federation_room_get_missing_events_test.go index 966b8570..e93d0f70 100644 --- a/tests/federation_room_get_missing_events_test.go +++ b/tests/federation_room_get_missing_events_test.go @@ -14,11 +14,11 @@ import ( "github.com/matrix-org/util" "github.com/tidwall/gjson" - "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/federation" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) // TODO: @@ -417,7 +417,7 @@ func TestInboundCanReturnMissingEvents(t *testing.T) { events := result.Events.UntrustedEvents(roomVersion) verifyMsgEvent := func(ev gomatrixserverlib.PDU) { - must.EqualStr(t, ev.Type(), "m.room.message", "not a message event") + must.Equal(t, ev.Type(), "m.room.message", "not a message event") // if the history vis is 'joined' or 'invite', we should get redacted // copies of the events before we joined. if visibility == gomatrixserverlib.HistoryVisibilityJoined || visibility == gomatrixserverlib.HistoryVisibilityInvited { @@ -434,20 +434,20 @@ func TestInboundCanReturnMissingEvents(t *testing.T) { } for i, ev := range events { - must.EqualStr(t, ev.RoomID().String(), roomID, "unexpected roomID") + must.Equal(t, ev.RoomID().String(), roomID, "unexpected roomID") switch i { case 0: - must.EqualStr(t, ev.Type(), "m.room.member", "not a membership event") - must.EqualStr(t, *ev.StateKey(), alice.UserID, "unexpected creator") + must.Equal(t, ev.Type(), "m.room.member", "not a membership event") + must.Equal(t, *ev.StateKey(), alice.UserID, "unexpected creator") case 1: - must.EqualStr(t, ev.Type(), spec.MRoomPowerLevels, "not a powerlevel event") + must.Equal(t, ev.Type(), spec.MRoomPowerLevels, "not a powerlevel event") case 2: - must.EqualStr(t, ev.Type(), spec.MRoomJoinRules, "not a join_rules event") + must.Equal(t, ev.Type(), spec.MRoomJoinRules, "not a join_rules event") case 3: - must.EqualStr(t, ev.Type(), spec.MRoomHistoryVisibility, "not a history_visiblity event") + must.Equal(t, ev.Type(), spec.MRoomHistoryVisibility, "not a history_visiblity event") case 4: if visibility != gomatrixserverlib.HistoryVisibilityShared { // shared -> shared no-ops - must.EqualStr(t, ev.Type(), spec.MRoomHistoryVisibility, "not a history_visiblity event") + must.Equal(t, ev.Type(), spec.MRoomHistoryVisibility, "not a history_visiblity event") } else { verifyMsgEvent(ev) } diff --git a/tests/federation_room_join_partial_state_test.go b/tests/federation_room_join_partial_state_test.go index d6f93631..8f83164d 100644 --- a/tests/federation_room_join_partial_state_test.go +++ b/tests/federation_room_join_partial_state_test.go @@ -30,12 +30,12 @@ import ( "github.com/matrix-org/gomatrixserverlib/fclient" "github.com/matrix-org/gomatrixserverlib/spec" - "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/docker" "github.com/matrix-org/complement/internal/federation" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) type server struct { @@ -357,7 +357,7 @@ func TestPartialStateJoin(t *testing.T) { return strings.Join([]string{result.Map()["type"].Str, result.Map()["state_key"].Str}, "|") }, nil, ) - if err := matcher([]byte(roomRes.Raw)); err != nil { + if err := matcher(roomRes); err != nil { t.Errorf("Did not find expected state events in /sync response: %s", err) } } @@ -527,16 +527,7 @@ func TestPartialStateJoin(t *testing.T) { client.SyncReq{ Filter: buildLazyLoadingSyncFilter(nil), }, - client.SyncEphemeralHas(serverRoom.RoomID, func(result gjson.Result) bool { - if result.Get("type").Str != "m.typing" { - return false - } - user_ids := result.Get("content.user_ids").Array() - if len(user_ids) != 1 { - return false - } - return user_ids[0].Str == derekUserId - }), + client.SyncUsersTyping(serverRoom.RoomID, []string{derekUserId}), ) // Alice should still be able to see incoming PDUs in the room during @@ -568,10 +559,7 @@ func TestPartialStateJoin(t *testing.T) { Filter: buildLazyLoadingSyncFilter(nil), Since: aliceNextBatch, }, - client.SyncEphemeralHas(serverRoom.RoomID, func(result gjson.Result) bool { - return (result.Get("type").Str == "m.typing" && - result.Get("content.user_ids.#").Int() == 0) - }), + client.SyncUsersTyping(serverRoom.RoomID, []string{}), ) }) @@ -774,7 +762,7 @@ func TestPartialStateJoin(t *testing.T) { func(r gjson.Result) interface{} { return r.Str }, nil, ) - return matcher([]byte(res.Raw)) + return matcher(res) }, ) }) @@ -1377,10 +1365,10 @@ func TestPartialStateJoin(t *testing.T) { return strings.Join([]string{result.Map()["type"].Str, result.Map()["state_key"].Str}, "|") }, nil, ) - if err := timelineMatcher([]byte(roomRes.Raw)); err != nil { + if err := timelineMatcher(roomRes); err != nil { t.Errorf("Unexpected timeline events found in gappy /sync response: %s", err) } - if err := stateMatcher([]byte(roomRes.Raw)); err != nil { + if err := stateMatcher(roomRes); err != nil { t.Errorf("Did not find derek's m.room.member event in gappy /sync response: %s", err) } }) @@ -1805,10 +1793,7 @@ func TestPartialStateJoin(t *testing.T) { if httpError.Code != 404 { t.Errorf("expected 404, got %d", httpError.Code) } - errcode := must.GetJSONFieldStr(t, httpError.Contents, "errcode") - if errcode != "M_NOT_FOUND" { - t.Errorf("errcode: got %s, want M_NOT_FOUND", errcode) - } + must.MatchGJSON(t, gjson.ParseBytes(httpError.Contents), match.JSONKeyEqual("errcode", "M_NOT_FOUND")) } else { t.Errorf("MakeJoin: non-HTTPError: %v", err) } @@ -1876,10 +1861,7 @@ func TestPartialStateJoin(t *testing.T) { if httpError.Code != 404 { t.Errorf("expected 404, got %d", httpError.Code) } - errcode := must.GetJSONFieldStr(t, httpError.Contents, "errcode") - if errcode != "M_NOT_FOUND" { - t.Errorf("errcode: got %s, want M_NOT_FOUND", errcode) - } + must.MatchGJSON(t, gjson.ParseBytes(httpError.Contents), match.JSONKeyEqual("errcode", "M_NOT_FOUND")) } else { t.Errorf("SendJoin: non-HTTPError: %v", err) } @@ -1983,10 +1965,7 @@ func TestPartialStateJoin(t *testing.T) { if httpError.Code != 404 { t.Errorf("expected 404, got %d", httpError.Code) } - errcode := must.GetJSONFieldStr(t, httpError.Contents, "errcode") - if errcode != "M_NOT_FOUND" { - t.Errorf("errcode: got %s, want M_NOT_FOUND", errcode) - } + must.MatchGJSON(t, gjson.ParseBytes(httpError.Contents), match.JSONKeyEqual("errcode", "M_NOT_FOUND")) } else { t.Errorf("MakeKnock: non-HTTPError: %v", err) } @@ -2054,10 +2033,7 @@ func TestPartialStateJoin(t *testing.T) { if httpError.Code != 404 { t.Errorf("expected 404, got %d", httpError.Code) } - errcode := must.GetJSONFieldStr(t, httpError.Contents, "errcode") - if errcode != "M_NOT_FOUND" { - t.Errorf("errcode: got %s, want M_NOT_FOUND", errcode) - } + must.MatchGJSON(t, gjson.ParseBytes(httpError.Contents), match.JSONKeyEqual("errcode", "M_NOT_FOUND")) } else { t.Errorf("SendKnock: non-HTTPError: %v", err) } @@ -4072,7 +4048,8 @@ func TestPartialStateJoin(t *testing.T) { []string{"_matrix", "client", "v3", "sync"}, client.WithQueries(queryParams), client.WithRetryUntil(5*time.Second, func(res *http.Response) bool { - body := client.ParseJSON(t, res) + body := must.ParseJSON(t, res.Body) + res.Body.Close() err := matcher(body) return err == nil }), diff --git a/tests/federation_room_join_test.go b/tests/federation_room_join_test.go index 0ae833fd..a6942c69 100644 --- a/tests/federation_room_join_test.go +++ b/tests/federation_room_join_test.go @@ -19,11 +19,11 @@ import ( "github.com/tidwall/gjson" "github.com/tidwall/sjson" - "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/federation" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" "github.com/matrix-org/complement/runtime" ) @@ -352,10 +352,7 @@ func TestBannedUserCannotSendJoin(t *testing.T) { if httpError.Code != 403 { t.Errorf("expected 403, got %d", httpError.Code) } - errcode := must.GetJSONFieldStr(t, httpError.Contents, "errcode") - if errcode != "M_FORBIDDEN" { - t.Errorf("errcode: got %s, want M_FORBIDDEN", errcode) - } + must.MatchJSONBytes(t, httpError.Contents, match.JSONKeyEqual("errcode", "M_FORBIDDEN")) } else { t.Errorf("SendJoin: non-HTTPError: %v", err) } @@ -366,9 +363,10 @@ func TestBannedUserCannotSendJoin(t *testing.T) { "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.member", charlie}, ) - stateResp := client.ParseJSON(t, res) + stateResp := must.ParseJSON(t, res.Body) + res.Body.Close() membership := must.GetJSONFieldStr(t, stateResp, "membership") - must.EqualStr(t, membership, "ban", "membership of charlie") + must.Equal(t, membership, "ban", "membership of charlie") } // This test checks that we cannot submit anything via /v1/send_join except a join. diff --git a/tests/federation_room_typing_test.go b/tests/federation_room_typing_test.go index d072a135..8f84d727 100644 --- a/tests/federation_room_typing_test.go +++ b/tests/federation_room_typing_test.go @@ -3,28 +3,10 @@ package tests import ( "testing" - "github.com/tidwall/gjson" - - "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" + "github.com/matrix-org/complement/client" ) -func awaitTyping(userId string) func(result gjson.Result) bool { - return func(result gjson.Result) bool { - if result.Get("type").Str != "m.typing" { - return false - } - - for _, item := range result.Get("content").Get("user_ids").Array() { - if item.Str == userId { - return true - } - } - - return false - } -} - // sytest: Typing notifications also sent to remote room members func TestRemoteTyping(t *testing.T) { deployment := Deploy(t, b.BlueprintFederationTwoLocalOneRemote) @@ -41,12 +23,9 @@ func TestRemoteTyping(t *testing.T) { bobToken := bob.MustSyncUntil(t, client.SyncReq{}, client.SyncJoinedTo(bob.UserID, roomID)) charlieToken := charlie.MustSyncUntil(t, client.SyncReq{}, client.SyncJoinedTo(charlie.UserID, roomID)) - alice.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "typing", alice.UserID}, client.WithJSONBody(t, map[string]interface{}{ - "typing": true, - "timeout": 10000, - })) + alice.SendTyping(t, roomID, true, 10000) - bob.MustSyncUntil(t, client.SyncReq{Since: bobToken}, client.SyncEphemeralHas(roomID, awaitTyping(alice.UserID))) + bob.MustSyncUntil(t, client.SyncReq{Since: bobToken}, client.SyncUsersTyping(roomID, []string{alice.UserID})) - charlie.MustSyncUntil(t, client.SyncReq{Since: charlieToken}, client.SyncEphemeralHas(roomID, awaitTyping(alice.UserID))) + charlie.MustSyncUntil(t, client.SyncReq{Since: charlieToken}, client.SyncUsersTyping(roomID, []string{alice.UserID})) } diff --git a/tests/federation_rooms_invite_test.go b/tests/federation_rooms_invite_test.go index a4e808c5..5da77328 100644 --- a/tests/federation_rooms_invite_test.go +++ b/tests/federation_rooms_invite_test.go @@ -8,8 +8,8 @@ import ( "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) func TestFederationRoomsInvite(t *testing.T) { diff --git a/tests/federation_upload_keys_test.go b/tests/federation_upload_keys_test.go index acc3add8..f1cc422b 100644 --- a/tests/federation_upload_keys_test.go +++ b/tests/federation_upload_keys_test.go @@ -10,8 +10,8 @@ import ( "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) func TestFederationKeyUploadQuery(t *testing.T) { diff --git a/tests/knocking_test.go b/tests/knocking_test.go index e51d4e71..372cdc60 100644 --- a/tests/knocking_test.go +++ b/tests/knocking_test.go @@ -19,11 +19,11 @@ import ( "github.com/matrix-org/gomatrixserverlib" "github.com/tidwall/gjson" - "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/federation" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) // A reason to include in the request body when testing knock reason parameters @@ -167,8 +167,8 @@ func knockingBetweenTwoUsersTest(t *testing.T, roomID string, inRoomUser, knocki if ev.Get("type").Str != "m.room.member" || ev.Get("sender").Str != knockingUser.UserID { return false } - must.EqualStr(t, ev.Get("content").Get("reason").Str, testKnockReason, "incorrect reason for knock") - must.EqualStr(t, ev.Get("content").Get("membership").Str, "knock", "incorrect membership for knocking user") + must.Equal(t, ev.Get("content").Get("reason").Str, testKnockReason, "incorrect reason for knock") + must.Equal(t, ev.Get("content").Get("membership").Str, "knock", "incorrect membership for knocking user") return true })) }) @@ -201,7 +201,7 @@ func knockingBetweenTwoUsersTest(t *testing.T, roomID string, inRoomUser, knocki if ev.Get("type").Str != "m.room.member" || ev.Get("sender").Str != knockingUser.UserID { continue } - must.EqualStr(t, ev.Get("content").Get("membership").Str, "leave", "expected leave membership after rescinding a knock") + must.Equal(t, ev.Get("content").Get("membership").Str, "leave", "expected leave membership after rescinding a knock") return nil } return fmt.Errorf("leave timeline for %s doesn't have leave event for %s", roomID, knockingUser.UserID) diff --git a/tests/media_nofilename_test.go b/tests/media_nofilename_test.go index 24aa0165..e7bb61fe 100644 --- a/tests/media_nofilename_test.go +++ b/tests/media_nofilename_test.go @@ -8,7 +8,7 @@ import ( "github.com/matrix-org/complement/b" "github.com/matrix-org/complement/internal/federation" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/must" ) // Can handle uploads and remote/local downloads without a file name @@ -43,14 +43,14 @@ func TestMediaWithoutFileName(t *testing.T) { t.Run("Can upload without a file name", func(t *testing.T) { t.Parallel() mxc := alice.UploadContent(t, file, fileName, contentType) - must.NotEqualStr(t, mxc, "", "did not return an MXC URI") + must.NotEqual(t, mxc, "", "did not return an MXC URI") must.StartWithStr(t, mxc, "mxc://", "returned invalid MXC URI") }) // sytest: Can download without a file name locally t.Run("Can download without a file name locally", func(t *testing.T) { t.Parallel() mxc := alice.UploadContent(t, file, fileName, contentType) - must.NotEqualStr(t, mxc, "", "did not return an MXC URI") + must.NotEqual(t, mxc, "", "did not return an MXC URI") must.StartWithStr(t, mxc, "mxc://", "returned invalid MXC URI") b, ct := alice.DownloadContent(t, mxc) @@ -62,14 +62,14 @@ func TestMediaWithoutFileName(t *testing.T) { // For now, we're operating under the assumption that homeservers are free to add other // directives. All we're going to check is the mime-type. mimeType := strings.Split(ct, ";")[0] - must.EqualStr( + must.Equal( t, mimeType, contentType, fmt.Sprintf( "Wrong mime-type returned in Content-Type returned. got Content-Type '%s', extracted mime-type '%s', expected mime-type: '%s'", ct, mimeType, contentType, ), ) - must.EqualStr(t, string(b), string(file), "wrong file content returned") + must.Equal(t, string(b), string(file), "wrong file content returned") }) // sytest: Can download without a file name over federation t.Run("Can download without a file name over federation", func(t *testing.T) { @@ -84,14 +84,14 @@ func TestMediaWithoutFileName(t *testing.T) { // For now, we're operating under the assumption that homeservers are free to add other // directives. All we're going to check is the mime-type. mimeType := strings.Split(ct, ";")[0] - must.EqualStr( + must.Equal( t, mimeType, contentType, fmt.Sprintf( "Wrong mime-type returned in Content-Type returned. got Content-Type '%s', extracted mime-type '%s', expected mime-type: '%s'", ct, mimeType, contentType, ), ) - must.EqualStr(t, string(b), string(remoteFile), "wrong file content returned") + must.Equal(t, string(b), string(remoteFile), "wrong file content returned") }) }) } diff --git a/tests/media_thumbnail_test.go b/tests/media_thumbnail_test.go index a067483b..8d6d0e63 100644 --- a/tests/media_thumbnail_test.go +++ b/tests/media_thumbnail_test.go @@ -4,13 +4,13 @@ import ( "bytes" "image/jpeg" "image/png" - "io/ioutil" + "io" "net/url" "strings" "testing" - "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/data" ) @@ -62,7 +62,7 @@ func fetchAndValidateThumbnail(t *testing.T, c *client.CSAPI, mxcUri string) { t.Fatalf("thumbnail request for uploaded file failed") } - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) if err != nil { t.Fatalf("thumbnail request for uploaded file failed: %s", err) diff --git a/tests/msc2836_test.go b/tests/msc2836_test.go index ac469326..582d3392 100644 --- a/tests/msc2836_test.go +++ b/tests/msc2836_test.go @@ -16,13 +16,14 @@ import ( "time" "github.com/matrix-org/gomatrixserverlib" + "github.com/matrix-org/gomatrixserverlib/spec" "github.com/tidwall/gjson" - "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/b" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/federation" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) // This test checks that federated threading works when the remote server joins after the messages @@ -323,9 +324,9 @@ func TestFederatedEventRelationships(t *testing.T) { fedClient := srv.FederationClient(deployment) _, err := fedClient.SendTransaction(context.Background(), gomatrixserverlib.Transaction{ TransactionID: "complement", - Origin: gomatrixserverlib.ServerName(srv.ServerName()), - Destination: gomatrixserverlib.ServerName("hs1"), - OriginServerTS: gomatrixserverlib.AsTimestamp(time.Now()), + Origin: spec.ServerName(srv.ServerName()), + Destination: spec.ServerName("hs1"), + OriginServerTS: spec.AsTimestamp(time.Now()), PDUs: []json.RawMessage{ eventE.JSON(), }, diff --git a/tests/msc3391_test.go b/tests/msc3391_test.go index 92da974a..86754120 100644 --- a/tests/msc3391_test.go +++ b/tests/msc3391_test.go @@ -13,8 +13,8 @@ import ( "github.com/matrix-org/complement/b" "github.com/matrix-org/complement/client" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" "github.com/tidwall/gjson" ) @@ -81,17 +81,7 @@ func createUserAccountData(t *testing.T, c *client.CSAPI) { res := c.GetGlobalAccountData(t, testAccountDataType) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ - func(body []byte) error { - if !match.JSONDeepEqual(body, testAccountDataContent) { - return fmt.Errorf( - "Expected %s for room account data content, got '%s'", - testAccountDataType, - string(body), - ) - } - - return nil - }, + match.JSONKeyEqual("", testAccountDataContent), }, }) } @@ -121,17 +111,7 @@ func createRoomAccountData(t *testing.T, c *client.CSAPI, roomID string) { res := c.GetRoomAccountData(t, roomID, testAccountDataType) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ - func(body []byte) error { - if !match.JSONDeepEqual(body, testAccountDataContent) { - return fmt.Errorf( - "Expected %s for room account data content, got '%s'", - testAccountDataType, - string(body), - ) - } - - return nil - }, + match.JSONKeyEqual("", testAccountDataContent), }, }) } @@ -259,10 +239,7 @@ func checkAccountDataContent(r gjson.Result) bool { if r.Get("type").Str != testAccountDataType { return false } - content := r.Get("content") - - // Ensure the content of this account data type is as we expect - return match.JSONDeepEqual([]byte(content.Raw), testAccountDataContent) + return match.JSONKeyEqual("content", testAccountDataContent)(r) == nil } // checkEmptyAccountData checks that the content of a user or account data object @@ -272,11 +249,9 @@ func checkEmptyAccountData(r gjson.Result) bool { if r.Get("type").Str != testAccountDataType { return false } - content := r.Get("content") - // Ensure the content of this account data type is an empty map. // This means that it has been deleted. - return match.JSONDeepEqual([]byte(content.Raw), map[string]interface{}{}) + return match.JSONKeyEqual("content", map[string]interface{}{})(r) == nil } // checkAccountDataTypeNotPresent checks that a given account data event type is not present @@ -291,4 +266,4 @@ func checkAccountDataTypeNotPresent(r gjson.Result) error { // We did not see our test type. return nil -} \ No newline at end of file +} diff --git a/tests/msc3890_test.go b/tests/msc3890_test.go index 4c61d86b..dab5d15a 100644 --- a/tests/msc3890_test.go +++ b/tests/msc3890_test.go @@ -12,8 +12,8 @@ import ( "github.com/matrix-org/complement/b" "github.com/matrix-org/complement/client" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" "github.com/tidwall/gjson" ) @@ -53,10 +53,7 @@ func TestDeletingDeviceRemovesDeviceLocalNotificationSettings(t *testing.T) { if r.Get("type").Str != accountDataType { return false } - content := r.Get("content") - - // Ensure the content of this account data type is as we expect - return match.JSONDeepEqual([]byte(content.Raw), accountDataContent) + return match.JSONKeyEqual("content", accountDataContent)(r) == nil } // Check that the content of the user account data for this type has been set successfully diff --git a/tests/msc3930_test.go b/tests/msc3930_test.go index 3e2a9c3a..27200b75 100644 --- a/tests/msc3930_test.go +++ b/tests/msc3930_test.go @@ -18,8 +18,8 @@ import ( "testing" "github.com/matrix-org/complement/b" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) const pollResponseRuleID = ".org.matrix.msc3930.rule.poll_response" diff --git a/tests/restricted_room_hierarchy_test.go b/tests/restricted_room_hierarchy_test.go index c067c654..285c8ba6 100644 --- a/tests/restricted_room_hierarchy_test.go +++ b/tests/restricted_room_hierarchy_test.go @@ -9,8 +9,8 @@ import ( "github.com/matrix-org/complement/b" "github.com/matrix-org/complement/client" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) // Request the room summary and ensure the expected rooms are in the response. diff --git a/tests/restricted_rooms_test.go b/tests/restricted_rooms_test.go index fd601e48..64cc5b1b 100644 --- a/tests/restricted_rooms_test.go +++ b/tests/restricted_rooms_test.go @@ -11,8 +11,8 @@ import ( "github.com/matrix-org/complement/b" "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/docker" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" "github.com/matrix-org/complement/runtime" ) @@ -299,8 +299,8 @@ func doTestRestrictedRoomsRemoteJoinLocalUser(t *testing.T, roomVersion string, if ev.Get("type").Str != "m.room.member" || ev.Get("state_key").Str != bob.UserID { return false } - must.EqualStr(t, ev.Get("sender").Str, bob.UserID, "Bob should have joined by himself") - must.EqualStr(t, ev.Get("content").Get("membership").Str, "join", "Bob failed to join the room") + must.Equal(t, ev.Get("sender").Str, bob.UserID, "Bob should have joined by himself") + must.Equal(t, ev.Get("content").Get("membership").Str, "join", "Bob failed to join the room") return true }, @@ -328,7 +328,7 @@ func doTestRestrictedRoomsRemoteJoinLocalUser(t *testing.T, roomVersion string, if ev.Get("type").Str != "m.room.member" || ev.Get("state_key").Str != charlie.UserID { return false } - must.EqualStr(t, ev.Get("content").Get("membership").Str, "leave", "Charlie failed to leave the room") + must.Equal(t, ev.Get("content").Get("membership").Str, "leave", "Charlie failed to leave the room") return true }, @@ -436,8 +436,8 @@ func doTestRestrictedRoomsRemoteJoinFailOver(t *testing.T, roomVersion string, j if ev.Get("type").Str != "m.room.member" || ev.Get("state_key").Str != charlie.UserID { return false } - must.EqualStr(t, ev.Get("content").Get("membership").Str, "join", "Charlie failed to join the room") - must.EqualStr(t, ev.Get("content").Get("join_authorised_via_users_server").Str, alice.UserID, "Join authorised via incorrect server") + must.Equal(t, ev.Get("content").Get("membership").Str, "join", "Charlie failed to join the room") + must.Equal(t, ev.Get("content").Get("join_authorised_via_users_server").Str, alice.UserID, "Join authorised via incorrect server") return true }, @@ -487,9 +487,10 @@ func doTestRestrictedRoomsRemoteJoinFailOver(t *testing.T, roomVersion string, j if ev.Get("type").Str != "m.room.member" || ev.Get("state_key").Str != charlie.UserID { return false } - must.EqualStr(t, ev.Get("content").Get("membership").Str, "join", "Charlie failed to join the room") - must.EqualStr(t, ev.Get("content").Get("join_authorised_via_users_server").Str, alice.UserID, "Join authorised via incorrect server") - + must.MatchGJSON(t, ev, + match.JSONKeyEqual("content.membership", "join"), + match.JSONKeyEqual("content.join_authorised_via_users_server", alice.UserID), + ) return true }, )) diff --git a/tests/room_hierarchy_test.go b/tests/room_hierarchy_test.go index c5fe56e4..90522aaf 100644 --- a/tests/room_hierarchy_test.go +++ b/tests/room_hierarchy_test.go @@ -22,8 +22,8 @@ import ( "github.com/matrix-org/complement/b" "github.com/matrix-org/complement/client" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) var ( diff --git a/tests/room_timestamp_to_event_test.go b/tests/room_timestamp_to_event_test.go index f0decbec..21f8297e 100644 --- a/tests/room_timestamp_to_event_test.go +++ b/tests/room_timestamp_to_event_test.go @@ -17,9 +17,10 @@ import ( "github.com/matrix-org/complement/b" "github.com/matrix-org/complement/client" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" "github.com/tidwall/gjson" + "golang.org/x/exp/slices" ) func TestJumpToDateEndpoint(t *testing.T) { @@ -395,7 +396,8 @@ func getDebugMessageListFromMessagesResponse(t *testing.T, c *client.CSAPI, room } // Make the events go from oldest-in-time -> newest-in-time - events := reverseGjsonArray(keyRes.Array()) + events := keyRes.Array() + slices.Reverse(events) if len(events) == 0 { t.Fatalf( "getDebugMessageListFromMessagesResponse found no messages in the room(%s).", @@ -464,11 +466,3 @@ const AnsiColorYellow string = "33" func decorateStringWithAnsiColor(inputString, decorationColor string) string { return fmt.Sprintf("\033[%sm%s\033[0m", decorationColor, inputString) } - -func reverseGjsonArray(in []gjson.Result) []gjson.Result { - out := make([]gjson.Result, len(in)) - for i := 0; i < len(in); i++ { - out[i] = in[len(in)-i-1] - } - return out -} diff --git a/tests/unknown_endpoints_test.go b/tests/unknown_endpoints_test.go index cdac1805..024cd611 100644 --- a/tests/unknown_endpoints_test.go +++ b/tests/unknown_endpoints_test.go @@ -6,8 +6,8 @@ import ( "github.com/matrix-org/complement/b" "github.com/matrix-org/complement/client" - "github.com/matrix-org/complement/internal/match" - "github.com/matrix-org/complement/internal/must" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" ) func queryUnknownEndpoint(t *testing.T, user *client.CSAPI, paths []string) {