Skip to content
Snippets Groups Projects
Commit 4045e760 authored by Jono Wenger's avatar Jono Wenger
Browse files

Merge branch 'XX-4568/removteKvBindings' into 'projects/AccountSync'

Write bindings for sync.go

See merge request !90
parents 0d8ea2a5 25d3f41f
No related branches found
No related tags found
2 merge requests!109Project/haven beta,!90Write bindings for sync.go
...@@ -10,7 +10,7 @@ require ( ...@@ -10,7 +10,7 @@ require (
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/spf13/cobra v1.5.0 github.com/spf13/cobra v1.5.0
github.com/spf13/jwalterweatherman v1.1.0 github.com/spf13/jwalterweatherman v1.1.0
gitlab.com/elixxir/client/v4 v4.6.1 gitlab.com/elixxir/client/v4 v4.6.2-0.20230321163910-1bfc802768bd
gitlab.com/elixxir/crypto v0.0.7-0.20230214180106-72841fd1e426 gitlab.com/elixxir/crypto v0.0.7-0.20230214180106-72841fd1e426
gitlab.com/elixxir/primitives v0.0.3-0.20230214180039-9a25e2d3969c gitlab.com/elixxir/primitives v0.0.3-0.20230214180039-9a25e2d3969c
gitlab.com/xx_network/crypto v0.0.5-0.20230214003943-8a09396e95dd gitlab.com/xx_network/crypto v0.0.5-0.20230214003943-8a09396e95dd
...@@ -27,12 +27,10 @@ require ( ...@@ -27,12 +27,10 @@ require (
github.com/cloudflare/circl v1.2.0 // indirect github.com/cloudflare/circl v1.2.0 // indirect
github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect
github.com/elliotchance/orderedmap v1.4.0 // indirect github.com/elliotchance/orderedmap v1.4.0 // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/gobwas/ws v1.1.0 // indirect github.com/gobwas/ws v1.1.0 // indirect
github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3 // indirect github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3 // indirect
github.com/golang/protobuf v1.5.2 // indirect github.com/golang/protobuf v1.5.2 // indirect
github.com/gorilla/websocket v1.5.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/improbable-eng/grpc-web v0.15.0 // indirect github.com/improbable-eng/grpc-web v0.15.0 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect
...@@ -40,27 +38,18 @@ require ( ...@@ -40,27 +38,18 @@ require (
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.15.9 // indirect github.com/klauspost/compress v1.15.9 // indirect
github.com/klauspost/cpuid/v2 v2.1.0 // indirect github.com/klauspost/cpuid/v2 v2.1.0 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-sqlite3 v1.14.15 // indirect github.com/mattn/go-sqlite3 v1.14.15 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
github.com/oasisprotocol/curve25519-voi v0.0.0-20221003100820-41fad3beba17 // indirect github.com/oasisprotocol/curve25519-voi v0.0.0-20221003100820-41fad3beba17 // indirect
github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/pelletier/go-toml/v2 v2.0.2 // indirect
github.com/pkg/profile v1.6.0 // indirect
github.com/rivo/uniseg v0.4.3 // indirect github.com/rivo/uniseg v0.4.3 // indirect
github.com/rs/cors v1.8.2 // indirect github.com/rs/cors v1.8.2 // indirect
github.com/sethvargo/go-diceware v0.3.0 // indirect github.com/sethvargo/go-diceware v0.3.0 // indirect
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
github.com/soheilhy/cmux v0.1.5 // indirect github.com/soheilhy/cmux v0.1.5 // indirect
github.com/spf13/afero v1.9.2 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.12.0 // indirect
github.com/subosito/gotenv v1.4.0 // indirect
github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2 // indirect github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2 // indirect
github.com/ttacon/libphonenumber v1.2.1 // indirect github.com/ttacon/libphonenumber v1.2.1 // indirect
github.com/tyler-smith/go-bip39 v1.1.0 // indirect github.com/tyler-smith/go-bip39 v1.1.0 // indirect
...@@ -81,9 +70,6 @@ require ( ...@@ -81,9 +70,6 @@ require (
google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc // indirect google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc // indirect
google.golang.org/grpc v1.49.0 // indirect google.golang.org/grpc v1.49.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/ini.v1 v1.66.6 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gorm.io/driver/sqlite v1.4.4 // indirect gorm.io/driver/sqlite v1.4.4 // indirect
gorm.io/gorm v1.24.3 // indirect gorm.io/gorm v1.24.3 // indirect
nhooyr.io/websocket v1.8.7 // indirect nhooyr.io/websocket v1.8.7 // indirect
......
This diff is collapsed.
...@@ -187,6 +187,12 @@ func main() { ...@@ -187,6 +187,12 @@ func main() {
js.Global().Set("TransmitSingleUse", js.FuncOf(wasm.TransmitSingleUse)) js.Global().Set("TransmitSingleUse", js.FuncOf(wasm.TransmitSingleUse))
js.Global().Set("Listen", js.FuncOf(wasm.Listen)) js.Global().Set("Listen", js.FuncOf(wasm.Listen))
// wasm/sync.go
js.Global().Set("NewFileSystemRemoteStorage",
js.FuncOf(wasm.NewFileSystemRemoteStorage))
js.Global().Set("NewOrLoadSyncRemoteKV",
js.FuncOf(wasm.NewOrLoadSyncRemoteKV))
// wasm/timeNow.go // wasm/timeNow.go
js.Global().Set("SetTimeSource", js.FuncOf(wasm.SetTimeSource)) js.Global().Set("SetTimeSource", js.FuncOf(wasm.SetTimeSource))
js.Global().Set("SetOffset", js.FuncOf(wasm.SetOffset)) js.Global().Set("SetOffset", js.FuncOf(wasm.SetOffset))
......
...@@ -104,3 +104,21 @@ func Await(awaitable js.Value) (result []js.Value, err []js.Value) { ...@@ -104,3 +104,21 @@ func Await(awaitable js.Value) (result []js.Value, err []js.Value) {
return nil, err return nil, err
} }
} }
// RunAndCatch runs the specified function and catches any errors thrown by
// Javascript. The errors should be of type Error.
func RunAndCatch(fn func() js.Value) (js.Value, error) {
var err error
defer func() {
if r := recover(); r != nil {
switch x := r.(type) {
case js.Value:
err = js.Error{Value: x}
default:
panic(r)
}
}
}()
return fn(), err
}
////////////////////////////////////////////////////////////////////////////////
// Copyright © 2022 xx foundation //
// //
// Use of this source code is governed by a license that can be found in the //
// LICENSE file. //
////////////////////////////////////////////////////////////////////////////////
//go:build js && wasm
package wasm
import (
"syscall/js"
"gitlab.com/elixxir/client/v4/bindings"
"gitlab.com/elixxir/xxdk-wasm/utils"
)
// TODO: add tests
////////////////////////////////////////////////////////////////////////////////
// Remote Storage Interface and Implementation(s) //
////////////////////////////////////////////////////////////////////////////////
// RemoteStoreFileSystem wraps the [bindings.RemoteStoreFileSystem] object so
// its methods can be wrapped to be Javascript compatible.
type RemoteStoreFileSystem struct {
api *bindings.RemoteStoreFileSystem
}
// newRemoteStoreFileSystemJS creates a new Javascript compatible object
// (map[string]any) that matches the [RemoteStoreFileSystem] structure.
func newRemoteStoreFileSystemJS(api *bindings.RemoteStoreFileSystem) map[string]any {
rsf := RemoteStoreFileSystem{api}
rsfMap := map[string]any{
"Read": js.FuncOf(rsf.Read),
"Write": js.FuncOf(rsf.Write),
"GetLastModified": js.FuncOf(rsf.GetLastModified),
"GetLastWrite": js.FuncOf(rsf.GetLastWrite),
}
return rsfMap
}
// NewFileSystemRemoteStorage is a constructor for [RemoteStoreFileSystem].
//
// Parameters:
// - args[0] - The base directory that all file operations will be performed.
// It must contain a file delimiter (i.e., `/`) (string).
//
// Returns:
// - A Javascript representation of the [RemoteStoreFileSystem] object.
func NewFileSystemRemoteStorage(_ js.Value, args []js.Value) any {
baseDir := args[0].String()
api := bindings.NewFileSystemRemoteStorage(baseDir)
return newRemoteStoreFileSystemJS(api)
}
// Read reads from the provided file path and returns the data at that path.
// An error is returned if it failed to read the file.
//
// Parameters:
// - args[0] - The file path to read from (string).
//
// Returns a promise:
// - Resolves to the file data (Uint8Array)
// - Rejected with an error if reading from the file fails.
func (rsf *RemoteStoreFileSystem) Read(_ js.Value, args []js.Value) any {
path := args[0].String()
promiseFn := func(resolve, reject func(args ...any) js.Value) {
data, err := rsf.api.Read(path)
if err != nil {
reject(utils.JsTrace(err))
} else {
resolve(utils.CopyBytesToJS(data))
}
}
return utils.CreatePromise(promiseFn)
}
// Write writes to the file path the provided data. An error is returned if it
// fails to write to file.
//
// Parameters:
// - args[0] - The file path to write to (string).
// - args[1] - The file data to write (Uint8Array).
//
// Returns a promise:
// - Resolves on success (void).
// - Rejected with an error if writing to the file fails.
func (rsf *RemoteStoreFileSystem) Write(_ js.Value, args []js.Value) any {
path := args[0].String()
data := utils.CopyBytesToGo(args[1])
promiseFn := func(resolve, reject func(args ...any) js.Value) {
err := rsf.api.Write(path, data)
if err != nil {
reject(utils.JsTrace(err))
} else {
resolve()
}
}
return utils.CreatePromise(promiseFn)
}
// GetLastModified returns when the file at the given file path was last
// modified. If the implementation that adheres to this interface does not
// support this, [Write] or [Read] should be implemented to either write a
// separate timestamp file or add a prefix.
//
// Parameters:
// - args[0] - The file path (string).
//
// Returns a promise:
// - Resolves to the JSON of [bindings.RemoteStoreReport] (Uint8Array).
// - Rejected with an error on failure.
func (rsf *RemoteStoreFileSystem) GetLastModified(_ js.Value, args []js.Value) any {
path := args[0].String()
promiseFn := func(resolve, reject func(args ...any) js.Value) {
report, err := rsf.api.GetLastModified(path)
if err != nil {
reject(utils.JsTrace(err))
} else {
resolve(utils.CopyBytesToJS(report))
}
}
return utils.CreatePromise(promiseFn)
}
// GetLastWrite retrieves the most recent successful write operation that was
// received by [RemoteStoreFileSystem].
//
// Returns a promise:
// - Resolves to the JSON of [bindings.RemoteStoreReport] (Uint8Array).
// - Rejected with an error on failure.
func (rsf *RemoteStoreFileSystem) GetLastWrite(js.Value, []js.Value) any {
promiseFn := func(resolve, reject func(args ...any) js.Value) {
report, err := rsf.api.GetLastWrite()
if err != nil {
reject(utils.JsTrace(err))
} else {
resolve(utils.CopyBytesToJS(report))
}
}
return utils.CreatePromise(promiseFn)
}
////////////////////////////////////////////////////////////////////////////////
// RemoteKV Methods //
////////////////////////////////////////////////////////////////////////////////
// RemoteKV wraps the [bindings.RemoteKV] object so its methods can be wrapped
// to be Javascript compatible.
type RemoteKV struct {
api *bindings.RemoteKV
}
// newRemoteKvJS creates a new Javascript compatible object (map[string]any)
// that matches the [RemoteKV] structure.
func newRemoteKvJS(api *bindings.RemoteKV) map[string]any {
rkv := RemoteKV{api}
rkvMap := map[string]any{
"Write": js.FuncOf(rkv.Write),
"Read": js.FuncOf(rkv.Read),
"GetList": js.FuncOf(rkv.GetList),
}
return rkvMap
}
// NewOrLoadSyncRemoteKV constructs a [RemoteKV].
//
// Parameters:
// - args[0] - ID of [E2e] object in tracker (int).
// - args[1] - A Javascript object that implements the functions on
// [RemoteKVCallbacks]. These will be the callbacks that are called for
// [bindings.RemoteStore] operations.
// - args[2] - A [RemoteStoreCallbacks]. This will be a structure the consumer
// implements. This acts as a wrapper around the remote storage API
// (e.g., Google Drive's API, DropBox's API, etc.).
//
// Returns a promise:
// - Resolves to a Javascript representation of the [RemoteKV] object.
// - Rejected with an error if initialising the remote KV fails.
func NewOrLoadSyncRemoteKV(_ js.Value, args []js.Value) any {
e2eID := args[0].Int()
remoteKvCallbacks := newRemoteKVCallbacks(args[1])
remote := newRemoteStoreCallbacks(args[2])
promiseFn := func(resolve, reject func(args ...any) js.Value) {
api, err :=
bindings.NewOrLoadSyncRemoteKV(e2eID, remoteKvCallbacks, remote)
if err != nil {
reject(utils.JsTrace(err))
} else {
resolve(newRemoteKvJS(api))
}
}
return utils.CreatePromise(promiseFn)
}
// Write writes a transaction to the remote and local store.
//
// Parameters:
// - args[0] - The key that this data will be written to (i.e., the device
// name, the channel name, etc.). Certain keys should follow a pattern and
// contain special characters (see [RemoteKV.GetList] for details) (string).
// - args[1] - The data that will be stored (i.e., state data) (Uint8Array).
// - args[2] - A Javascript object that implements the functions on
// [RemoteKVCallbacks]. This may be nil if you do not care about the network
// report.
//
// Returns a promise:
// - Resolves on success (void).
// - Rejected with an error if writing to the file fails.
func (rkv *RemoteKV) Write(_ js.Value, args []js.Value) any {
path := args[0].String()
data := utils.CopyBytesToGo(args[1])
cb := newRemoteKVCallbacks(args[1])
promiseFn := func(resolve, reject func(args ...any) js.Value) {
err := rkv.api.Write(path, data, cb)
if err != nil {
reject(utils.JsTrace(err))
} else {
resolve()
}
}
return utils.CreatePromise(promiseFn)
}
// Read retrieves the data stored in the underlying KV. Returns an error if the
// data at this key cannot be retrieved.
//
// Parameters:
// - args[0] - The path that this data will be written to (i.e., the device
// name) (string).
//
// Returns a promise:
// - Resolves to the file data (Uint8Array)
// - Rejected with an error if reading from the file fails.
func (rkv *RemoteKV) Read(_ js.Value, args []js.Value) any {
path := args[0].String()
promiseFn := func(resolve, reject func(args ...any) js.Value) {
data, err := rkv.api.Read(path)
if err != nil {
reject(utils.JsTrace(err))
} else {
resolve(utils.CopyBytesToJS(data))
}
}
return utils.CreatePromise(promiseFn)
}
// GetList returns all entries for a path (or key) that contain the name
// parameter from the local store.
//
// For example, assuming the usage of the [sync.LocalStoreKeyDelimiter], if both
// "channels-123" and "channels-abc" are written to [RemoteKV], then
// GetList("channels") will retrieve the data for both channels. All data that
// contains no [sync.LocalStoreKeyDelimiter] can be retrieved using GetList("").
//
// Parameters:
// - args[0] - Some prefix to a Write operation. If no prefix applies, simply
// use the empty string. (string).
//
// Returns:
// - The file data (Uint8Array)
// - Throws a TypeError if getting the list fails.
func (rkv *RemoteKV) GetList(_ js.Value, args []js.Value) any {
name := args[0].String()
data, err := rkv.api.GetList(name)
if err != nil {
utils.Throw(utils.TypeError, err)
return nil
}
return utils.CopyBytesToJS(data)
}
// RemoteStoreCallbacks wraps Javascript callbacks to adhere to the
// [bindings.RemoteStore] interface.
type RemoteStoreCallbacks struct {
read func(args ...any) js.Value
write func(args ...any) js.Value
getLastModified func(args ...any) js.Value
getLastWrite func(args ...any) js.Value
}
// newRemoteStoreCallbacks maps the functions of the Javascript object matching
// [bindings.RemoteStore] to a RemoteStoreCallbacks.
func newRemoteStoreCallbacks(arg js.Value) *RemoteStoreCallbacks {
return &RemoteStoreCallbacks{
read: utils.WrapCB(arg, "Read"),
write: utils.WrapCB(arg, "Write"),
getLastModified: utils.WrapCB(arg, "GetLastModified"),
getLastWrite: utils.WrapCB(arg, "GetLastWrite"),
}
}
// Read reads from the provided file path and returns the data at that path.
// An error is returned if it failed to read the file.
//
// Parameters:
// - path - The file path to read from (string).
//
// Returns:
// - The file data (Uint8Array).
// - Catches any thrown errors (of type Error) and returns it as an error.
func (rsCB *RemoteStoreCallbacks) Read(path string) ([]byte, error) {
fn := func() js.Value { return rsCB.read(path) }
v, err := utils.RunAndCatch(fn)
if err != nil {
return nil, err
}
return utils.CopyBytesToGo(v), err
}
// Write writes to the file path the provided data. An error is returned if it
// fails to write to file.
//
// Parameters:
// - path - The file path to write to (string).
// - data - The file data to write (Uint8Array).
//
// Returns:
// - Catches any thrown errors (of type Error) and returns it as an error.
func (rsCB *RemoteStoreCallbacks) Write(path string, data []byte) error {
fn := func() js.Value { return rsCB.write(path, utils.CopyBytesToJS(data)) }
_, err := utils.RunAndCatch(fn)
return err
}
// GetLastModified returns when the file at the given file path was last
// modified. If the implementation that adheres to this interface does not
// support this, [Write] or [Read] should be implemented to either write a
// separate timestamp file or add a prefix.
//
// Parameters:
// - path - The file path (string).
//
// Returns:
// - JSON of [bindings.RemoteStoreReport] (Uint8Array).
// - Catches any thrown errors (of type Error) and returns it as an error.
func (rsCB *RemoteStoreCallbacks) GetLastModified(path string) ([]byte, error) {
fn := func() js.Value { return rsCB.getLastModified(path) }
v, err := utils.RunAndCatch(fn)
if err != nil {
return nil, err
}
return utils.CopyBytesToGo(v), err
}
// GetLastWrite retrieves the most recent successful write operation that was
// received by [RemoteStoreFileSystem].
//
// Returns:
// - JSON of [bindings.RemoteStoreReport] (Uint8Array).
// - Catches any thrown errors (of type Error) and returns it as an error.
func (rsCB *RemoteStoreCallbacks) GetLastWrite() ([]byte, error) {
fn := func() js.Value { return rsCB.getLastWrite() }
v, err := utils.RunAndCatch(fn)
if err != nil {
return nil, err
}
return utils.CopyBytesToGo(v), err
}
// RemoteKVCallbacks wraps Javascript callbacks to adhere to the
// [bindings.RemoteKVCallbacks] interface.
type RemoteKVCallbacks struct {
keyUpdated func(args ...any) js.Value
remoteStoreResult func(args ...any) js.Value
}
// newRemoteKVCallbacks maps the functions of the Javascript object matching
// [bindings.RemoteKVCallbacks] to a RemoteKVCallbacks.
func newRemoteKVCallbacks(arg js.Value) *RemoteKVCallbacks {
return &RemoteKVCallbacks{
keyUpdated: utils.WrapCB(arg, "KeyUpdated"),
remoteStoreResult: utils.WrapCB(arg, "RemoteStoreResult"),
}
}
// KeyUpdated is the callback to be called any time a key is updated by another
// device tracked by the [RemoteKV] store.
//
// Parameters:
// - key - (string).
// - oldVal - (Uint8Array).
// - newVal - (Uint8Array).
// - updated - (Boolean)
func (rkvCB *RemoteKVCallbacks) KeyUpdated(
key string, oldVal, newVal []byte, updated bool) {
rkvCB.keyUpdated(
key, utils.CopyBytesToJS(oldVal), utils.CopyBytesToJS(newVal), updated)
}
// RemoteStoreResult is called to report network save results after the key has
// been updated locally.
//
// NOTE: Errors originate from the authentication and writing code in regard to
// remote which is handled by the user of this API. As a result, this callback
// provides no information in simple implementations.
//
// Parameters:
// - remoteStoreReport - JSON of [bindings.RemoteStoreReport] (Uint8Array).
func (rkvCB *RemoteKVCallbacks) RemoteStoreResult(remoteStoreReport []byte) {
rkvCB.remoteStoreResult(utils.CopyBytesToJS(remoteStoreReport))
}
////////////////////////////////////////////////////////////////////////////////
// Copyright © 2022 xx foundation //
// //
// Use of this source code is governed by a license that can be found in the //
// LICENSE file. //
////////////////////////////////////////////////////////////////////////////////
//go:build js && wasm
package wasm
import (
"reflect"
"testing"
"gitlab.com/elixxir/client/v4/bindings"
)
// Tests that the map representing RemoteStoreFileSystem returned by
// newRemoteStoreFileSystemJS contains all of the methods on
// RemoteStoreFileSystem.
func Test_newRemoteStoreFileSystemJS(t *testing.T) {
rsfType := reflect.TypeOf(&RemoteStoreFileSystem{})
rsf := newRemoteStoreFileSystemJS(&bindings.RemoteStoreFileSystem{})
if len(rsf) != rsfType.NumMethod() {
t.Errorf("RemoteStoreFileSystem JS object does not have all methods."+
"\nexpected: %d\nreceived: %d", rsfType.NumMethod(), len(rsf))
}
for i := 0; i < rsfType.NumMethod(); i++ {
method := rsfType.Method(i)
if _, exists := rsf[method.Name]; !exists {
t.Errorf("Method %s does not exist.", method.Name)
}
}
}
// Tests that RemoteStoreFileSystem has all the methods that
// [bindings.RemoteStoreFileSystem] has.
func Test_RemoteStoreFileSystemMethods(t *testing.T) {
rsfType := reflect.TypeOf(&RemoteStoreFileSystem{})
binRsfType := reflect.TypeOf(&bindings.RemoteStoreFileSystem{})
if binRsfType.NumMethod() != rsfType.NumMethod() {
t.Errorf("WASM RemoteStoreFileSystem object does not have all methods "+
"from bindings.\nexpected: %d\nreceived: %d",
binRsfType.NumMethod(), rsfType.NumMethod())
}
for i := 0; i < binRsfType.NumMethod(); i++ {
method := binRsfType.Method(i)
if _, exists := rsfType.MethodByName(method.Name); !exists {
t.Errorf("Method %s does not exist.", method.Name)
}
}
}
// Tests that the map representing RemoteKV returned by newRemoteKvJS contains
// all of the methods on RemoteKV.
func Test_newRemoteKvJS(t *testing.T) {
rkvType := reflect.TypeOf(&RemoteKV{})
rkv := newRemoteKvJS(&bindings.RemoteKV{})
if len(rkv) != rkvType.NumMethod() {
t.Errorf("RemoteKV JS object does not have all methods."+
"\nexpected: %d\nreceived: %d", rkvType.NumMethod(), len(rkv))
}
for i := 0; i < rkvType.NumMethod(); i++ {
method := rkvType.Method(i)
if _, exists := rkv[method.Name]; !exists {
t.Errorf("Method %s does not exist.", method.Name)
}
}
}
// Tests that RemoteKV has all the methods that [bindings.RemoteKV] has.
func Test_RemoteKVMethods(t *testing.T) {
rkvType := reflect.TypeOf(&RemoteKV{})
binRkvType := reflect.TypeOf(&bindings.RemoteKV{})
if binRkvType.NumMethod() != rkvType.NumMethod() {
t.Errorf("WASM RemoteKV object does not have all methods from "+
"bindings.\nexpected: %d\nreceived: %d",
binRkvType.NumMethod(), rkvType.NumMethod())
}
for i := 0; i < binRkvType.NumMethod(); i++ {
method := binRkvType.Method(i)
if _, exists := rkvType.MethodByName(method.Name); !exists {
t.Errorf("Method %s does not exist.", method.Name)
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment