From f916f65a80d4e94c1c0eca43a50a42bba01a0550 Mon Sep 17 00:00:00 2001 From: Tim Voronov Date: Fri, 15 Mar 2019 00:06:55 -0400 Subject: [PATCH] =?UTF-8?q?parent=20b45f8895348b319647c198cdea7032f7f40cec?= =?UTF-8?q?aa=20author=20Tim=20Voronov=20=201552622815?= =?UTF-8?q?=20-0400=20committer=20=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC?= =?UTF-8?q?=D0=B8=D1=80=20=D0=A4=D0=B5=D1=82=D0=B8=D1=81=D0=BE=D0=B2=20=201554919032=20+0300?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit parent b45f8895348b319647c198cdea7032f7f40cecaa author Tim Voronov 1552622815 -0400 committer Владимир Фетисов 1554919029 +0300 Updated style template Feature/#236 cookies (#242) * Added KeepCookies option to CDP driver * Added LoadDocumentParams * Added COOKIE_GET and COOKIE_SET methods Updated CHANGELOG Updated nav example fix order of arguments (#269) Updated RAND function (#271) * Updated RAND function * renamed a func Linter Cleanup (#276) * linter cleanup * fix default case Bump github.com/mafredri/cdp from 0.22.0 to 0.23.0 (#278) Bumps [github.com/mafredri/cdp](https://github.com/mafredri/cdp) from 0.22.0 to 0.23.0. - [Release notes](https://github.com/mafredri/cdp/releases) - [Commits](https://github.com/mafredri/cdp/compare/v0.22.0...v0.23.0) Signed-off-by: dependabot[bot] fix diff --- cli/repl.go | 2 - pkg/drivers/cdp/document.go | 123 +++++++++++++++++- pkg/drivers/cdp/events/wait.go | 61 ++++++--- pkg/drivers/cdp/options.go | 29 +++-- pkg/drivers/http/document.go | 44 ++++++- pkg/drivers/value.go | 6 - pkg/runtime/expressions/body_test.go | 147 ++++++++++------------ pkg/runtime/expressions/body_test.go~HEAD | 147 ---------------------- pkg/runtime/expressions/param_test.go | 1 - pkg/runtime/values/array.go | 15 --- 10 files changed, 293 insertions(+), 282 deletions(-) delete mode 100644 pkg/runtime/expressions/body_test.go~HEAD diff --git a/cli/repl.go b/cli/repl.go index af7c9cd4e..cd50472ee 100644 --- a/cli/repl.go +++ b/cli/repl.go @@ -9,8 +9,6 @@ import ( "github.com/MontFerret/ferret/pkg/parser/fql" - "github.com/MontFerret/ferret/pkg/parser/fql" - "github.com/MontFerret/ferret/pkg/compiler" "github.com/MontFerret/ferret/pkg/runtime" "github.com/MontFerret/ferret/pkg/runtime/logging" diff --git a/pkg/drivers/cdp/document.go b/pkg/drivers/cdp/document.go index d3971dd72..682d2469f 100644 --- a/pkg/drivers/cdp/document.go +++ b/pkg/drivers/cdp/document.go @@ -2,6 +2,7 @@ package cdp import ( "context" + "encoding/json" "fmt" "hash/fnv" "sync" @@ -19,6 +20,7 @@ import ( "github.com/mafredri/cdp" "github.com/mafredri/cdp/protocol/dom" "github.com/mafredri/cdp/protocol/input" + "github.com/mafredri/cdp/protocol/network" "github.com/mafredri/cdp/protocol/page" "github.com/mafredri/cdp/rpcc" "github.com/pkg/errors" @@ -49,7 +51,7 @@ func LoadHTMLDocument( ctx context.Context, conn *rpcc.Conn, client *cdp.Client, - url string, + params drivers.LoadDocumentParams, ) (drivers.HTMLDocument, error) { logger := logging.FromContext(ctx) @@ -57,13 +59,61 @@ func LoadHTMLDocument( return nil, core.Error(core.ErrMissedArgument, "connection") } - if url == "" { + if params.URL == "" { return nil, core.Error(core.ErrMissedArgument, "url") } + if params.Cookies != nil { + cookies := make([]network.CookieParam, 0, len(params.Cookies)) + + for _, c := range params.Cookies { + cookies = append(cookies, fromDriverCookie(params.URL, c)) + + logger. + Debug(). + Timestamp(). + Str("cookie", c.Name). + Msg("set cookie") + } + + err := client.Network.SetCookies( + ctx, + network.NewSetCookiesArgs(cookies), + ) + + if err != nil { + return nil, err + } + } + + if params.Header != nil { + j, err := json.Marshal(params.Header) + + if err != nil { + return nil, err + } + + for k := range params.Header { + logger. + Debug(). + Timestamp(). + Str("header", k). + Msg("set header") + } + + err = client.Network.SetExtraHTTPHeaders( + ctx, + network.NewSetExtraHTTPHeadersArgs(network.Headers(j)), + ) + + if err != nil { + return nil, err + } + } + var err error - if url != BlankPageURL { + if params.URL != BlankPageURL { err = waitForLoadEvent(ctx, client) if err != nil { @@ -109,7 +159,7 @@ func LoadHTMLDocument( conn, client, broker, - values.NewString(url), + values.NewString(params.URL), rootElement, ), nil } @@ -316,6 +366,67 @@ func (doc *HTMLDocument) GetURL() core.Value { return doc.url } +func (doc *HTMLDocument) GetCookies(ctx context.Context) (*values.Array, error) { + doc.Lock() + defer doc.Unlock() + + repl, err := doc.client.Network.GetAllCookies(ctx) + + if err != nil { + return values.NewArray(0), err + } + + if repl.Cookies == nil { + return values.NewArray(0), nil + } + + cookies := values.NewArray(len(repl.Cookies)) + + for _, c := range repl.Cookies { + cookies.Push(toDriverCookie(c)) + } + + return cookies, nil +} + +func (doc *HTMLDocument) SetCookies(ctx context.Context, cookies ...drivers.HTTPCookie) error { + doc.Lock() + defer doc.Unlock() + + if len(cookies) == 0 { + return nil + } + + params := make([]network.CookieParam, 0, len(cookies)) + + for _, c := range cookies { + params = append(params, fromDriverCookie(doc.url.String(), c)) + } + + return doc.client.Network.SetCookies(ctx, network.NewSetCookiesArgs(params)) +} + +func (doc *HTMLDocument) DeleteCookies(ctx context.Context, cookies ...drivers.HTTPCookie) error { + doc.Lock() + defer doc.Unlock() + + if len(cookies) == 0 { + return nil + } + + var err error + + for _, c := range cookies { + err = doc.client.Network.DeleteCookies(ctx, fromDriverCookieDelete(doc.url.String(), c)) + + if err != nil { + break + } + } + + return err +} + func (doc *HTMLDocument) SetURL(ctx context.Context, url values.String) error { return doc.Navigate(ctx, url) } @@ -852,6 +963,10 @@ func (doc *HTMLDocument) PrintToPDF(ctx context.Context, params drivers.PDFParam func (doc *HTMLDocument) CaptureScreenshot(ctx context.Context, params drivers.ScreenshotParams) (values.Binary, error) { metrics, err := doc.client.Page.GetLayoutMetrics(ctx) + if err != nil { + return values.NewBinary(nil), err + } + if params.Format == drivers.ScreenshotFormatJPEG && params.Quality < 0 && params.Quality > 100 { params.Quality = 100 } diff --git a/pkg/drivers/cdp/events/wait.go b/pkg/drivers/cdp/events/wait.go index 3e1e6d11e..4cafdf5f5 100644 --- a/pkg/drivers/cdp/events/wait.go +++ b/pkg/drivers/cdp/events/wait.go @@ -1,8 +1,10 @@ package events import ( + "context" "time" + "github.com/MontFerret/ferret/pkg/drivers" "github.com/MontFerret/ferret/pkg/drivers/cdp/eval" "github.com/MontFerret/ferret/pkg/runtime/core" "github.com/MontFerret/ferret/pkg/runtime/values" @@ -10,10 +12,10 @@ import ( ) type ( - Function func() (core.Value, error) + Function func(ctx context.Context) (core.Value, error) + WaitTask struct { fun Function - timeout time.Duration polling time.Duration } ) @@ -22,39 +24,31 @@ const DefaultPolling = time.Millisecond * time.Duration(200) func NewWaitTask( fun Function, - timeout time.Duration, polling time.Duration, ) *WaitTask { return &WaitTask{ fun, - timeout, polling, } } -func (task *WaitTask) Run() (core.Value, error) { - timer := time.NewTimer(task.timeout) - +func (task *WaitTask) Run(ctx context.Context) (core.Value, error) { for { select { - case <-timer.C: + case <-ctx.Done(): return values.None, core.ErrTimeout default: - out, err := task.fun() + out, err := task.fun(ctx) // expression failed // terminating if err != nil { - timer.Stop() - return values.None, err } // output is not empty // terminating if out != values.None { - timer.Stop() - return out, nil } @@ -67,19 +61,54 @@ func (task *WaitTask) Run() (core.Value, error) { func NewEvalWaitTask( client *cdp.Client, predicate string, - timeout time.Duration, polling time.Duration, ) *WaitTask { return NewWaitTask( - func() (core.Value, error) { + func(ctx context.Context) (core.Value, error) { return eval.Eval( + ctx, client, predicate, true, false, ) }, - timeout, polling, ) } + +func NewValueWaitTask( + when drivers.WaitEvent, + value core.Value, + getter Function, + polling time.Duration, +) *WaitTask { + return &WaitTask{ + func(ctx context.Context) (core.Value, error) { + current, err := getter(ctx) + + if err != nil { + return values.None, err + } + + if when == drivers.WaitEventPresence { + // Values appeared, exit + if current.Compare(value) == 0 { + // The value does not really matter if it's not None + // None indicates that operation needs to be repeated + return values.True, nil + } + } else { + // Value disappeared, exit + if current.Compare(value) != 0 { + // The value does not really matter if it's not None + // None indicates that operation needs to be repeated + return values.True, nil + } + } + + return values.None, nil + }, + polling, + } +} diff --git a/pkg/drivers/cdp/options.go b/pkg/drivers/cdp/options.go index bd240ba17..422705231 100644 --- a/pkg/drivers/cdp/options.go +++ b/pkg/drivers/cdp/options.go @@ -2,9 +2,11 @@ package cdp type ( Options struct { - proxy string - userAgent string - address string + Name string + Proxy string + UserAgent string + Address string + KeepCookies bool } Option func(opts *Options) @@ -14,7 +16,8 @@ const DefaultAddress = "http://127.0.0.1:9222" func newOptions(setters []Option) *Options { opts := new(Options) - opts.address = DefaultAddress + opts.Name = DriverName + opts.Address = DefaultAddress for _, setter := range setters { setter(opts) @@ -26,19 +29,31 @@ func newOptions(setters []Option) *Options { func WithAddress(address string) Option { return func(opts *Options) { if address != "" { - opts.address = address + opts.Address = address } } } func WithProxy(address string) Option { return func(opts *Options) { - opts.proxy = address + opts.Proxy = address } } func WithUserAgent(value string) Option { return func(opts *Options) { - opts.userAgent = value + opts.UserAgent = value + } +} + +func WithKeepCookies() Option { + return func(opts *Options) { + opts.KeepCookies = true + } +} + +func WithCustomName(name string) Option { + return func(opts *Options) { + opts.Name = name } } diff --git a/pkg/drivers/http/document.go b/pkg/drivers/http/document.go index 56a884a30..88f3709ae 100644 --- a/pkg/drivers/http/document.go +++ b/pkg/drivers/http/document.go @@ -12,14 +12,16 @@ import ( ) type HTMLDocument struct { - url values.String docNode *goquery.Document element drivers.HTMLElement + url values.String + cookies []drivers.HTTPCookie } func NewHTMLDocument( - url string, node *goquery.Document, + url string, + cookies []drivers.HTTPCookie, ) (drivers.HTMLDocument, error) { if url == "" { return nil, core.Error(core.ErrMissedArgument, "document url") @@ -35,7 +37,7 @@ func NewHTMLDocument( return nil, err } - return &HTMLDocument{values.NewString(url), node, el}, nil + return &HTMLDocument{node, el, values.NewString(url), cookies}, nil } func (doc *HTMLDocument) MarshalJSON() ([]byte, error) { @@ -82,7 +84,7 @@ func (doc *HTMLDocument) Hash() uint64 { } func (doc *HTMLDocument) Copy() core.Value { - cp, err := NewHTMLDocument(string(doc.url), doc.docNode) + cp, err := NewHTMLDocument(doc.docNode, string(doc.url), doc.cookies) if err != nil { return values.None @@ -92,7 +94,17 @@ func (doc *HTMLDocument) Copy() core.Value { } func (doc *HTMLDocument) Clone() core.Value { - cp, err := NewHTMLDocument(string(doc.url), goquery.CloneDocument(doc.docNode)) + var cookies []drivers.HTTPCookie + + if doc.cookies != nil { + cookies = make([]drivers.HTTPCookie, 0, len(doc.cookies)) + + for i, c := range doc.cookies { + cookies[i] = c + } + } + + cp, err := NewHTMLDocument(goquery.CloneDocument(doc.docNode), string(doc.url), cookies) if err != nil { return values.None @@ -161,6 +173,28 @@ func (doc *HTMLDocument) SetURL(_ context.Context, _ values.String) error { return core.ErrInvalidOperation } +func (doc *HTMLDocument) GetCookies(_ context.Context) (*values.Array, error) { + if doc.cookies == nil { + return values.NewArray(0), nil + } + + arr := values.NewArray(len(doc.cookies)) + + for _, c := range doc.cookies { + arr.Push(c) + } + + return arr, nil +} + +func (doc *HTMLDocument) SetCookies(_ context.Context, _ ...drivers.HTTPCookie) error { + return core.ErrNotSupported +} + +func (doc *HTMLDocument) DeleteCookies(_ context.Context, _ ...drivers.HTTPCookie) error { + return core.ErrNotSupported +} + func (doc *HTMLDocument) Navigate(_ context.Context, _ values.String) error { return core.ErrNotSupported } diff --git a/pkg/drivers/value.go b/pkg/drivers/value.go index ad309fed3..6cea92108 100644 --- a/pkg/drivers/value.go +++ b/pkg/drivers/value.go @@ -96,8 +96,6 @@ type ( WaitForStyle(ctx context.Context, name values.String, value core.Value, when WaitEvent) error WaitForClass(ctx context.Context, class values.String, when WaitEvent) error - - WaitForAttribute(ctx context.Context, name values.String, value core.Value, when WaitEvent) error } // The Document interface represents any web page loaded in the browser @@ -162,10 +160,6 @@ type ( WaitForClassBySelector(ctx context.Context, selector, class values.String, when WaitEvent) error WaitForClassBySelectorAll(ctx context.Context, selector, class values.String, when WaitEvent) error - - WaitForAttributeBySelector(ctx context.Context, selector, name values.String, value core.Value, when WaitEvent) error - - WaitForAttributeBySelectorAll(ctx context.Context, selector, name values.String, value core.Value, when WaitEvent) error } ) diff --git a/pkg/runtime/expressions/body_test.go b/pkg/runtime/expressions/body_test.go index b3a02fd13..fd4a28404 100644 --- a/pkg/runtime/expressions/body_test.go +++ b/pkg/runtime/expressions/body_test.go @@ -2,7 +2,6 @@ package expressions_test import ( "context" - "github.com/MontFerret/ferret/pkg/runtime/collections" "testing" "github.com/MontFerret/ferret/pkg/runtime/core" @@ -11,79 +10,67 @@ import ( . "github.com/smartystreets/goconvey/convey" ) -type IterableFn func(ctx context.Context, scope *core.Scope) (collections.Iterator, error) - -func (f IterableFn) Iterate(ctx context.Context, scope *core.Scope) (collections.Iterator, error) { - return f(ctx, scope) -} - -type ExpressionFn func(ctx context.Context, scope *core.Scope) (core.Value, error) - -func (f ExpressionFn) Exec(ctx context.Context, scope *core.Scope) (core.Value, error) { - return f(ctx, scope) -} - -func TestBlock(t *testing.T) { - newExp := func(values []core.Value) (*expressions.BlockExpression, error) { - iter, err := collections.NewDefaultSliceIterator(values) - - if err != nil { - return nil, err - } - - return expressions.NewBlockExpression(IterableFn(func(ctx context.Context, scope *core.Scope) (collections.Iterator, error) { - return iter, nil - })) - } - +func TestBody(t *testing.T) { Convey("Should create a block expression", t, func() { - s, err := newExp(make([]core.Value, 0, 10)) + s := expressions.NewBodyExpression(1) - So(err, ShouldBeNil) - So(s, ShouldHaveSameTypeAs, &expressions.BlockExpression{}) + So(s, ShouldHaveSameTypeAs, &expressions.BodyExpression{}) }) Convey("Should add a new expression of a default type", t, func() { - s, _ := newExp(make([]core.Value, 0, 10)) + s := expressions.NewBodyExpression(0) sourceMap := core.NewSourceMap("test", 1, 1) exp, err := expressions.NewVariableExpression(sourceMap, "testExp") So(err, ShouldBeNil) - s.Add(exp) + err = s.Add(exp) + So(err, ShouldBeNil) }) - Convey("Should exec a block expression", t, func() { - s, _ := newExp(make([]core.Value, 0, 10)) + Convey("Should add a new Return expression", t, func() { + s := expressions.NewBodyExpression(0) sourceMap := core.NewSourceMap("test", 1, 1) - exp, err := expressions.NewVariableDeclarationExpression(sourceMap, "test", ExpressionFn(func(ctx context.Context, scope *core.Scope) (core.Value, error) { - return values.NewString("value"), nil - })) + predicate, err := expressions.NewVariableExpression(sourceMap, "testExp") So(err, ShouldBeNil) - s.Add(exp) + exp, err := expressions.NewReturnExpression(sourceMap, predicate) + So(err, ShouldBeNil) - rootScope, _ := core.NewRootScope() - scope := rootScope.Fork() + err = s.Add(exp) + So(err, ShouldBeNil) + }) + + Convey("Should not add an already defined Return expression", t, func() { + s := expressions.NewBodyExpression(0) - _, err = s.Exec(context.Background(), scope) + sourceMap := core.NewSourceMap("test", 1, 1) + predicate, err := expressions.NewVariableExpression(sourceMap, "testExp") So(err, ShouldBeNil) - val, err := scope.GetVariable("test") + exp, err := expressions.NewReturnExpression(sourceMap, predicate) So(err, ShouldBeNil) - So(val, ShouldEqual, "value") + err = s.Add(exp) + So(err, ShouldBeNil) + + err = s.Add(exp) + So(err, ShouldBeError) + So(err.Error(), ShouldEqual, "invalid operation: return expression is already defined") }) - Convey("Should not exec a nil block expression", t, func() { - s, _ := newExp(make([]core.Value, 0, 10)) + Convey("Should exec a block expression", t, func() { + s := expressions.NewBodyExpression(1) sourceMap := core.NewSourceMap("test", 1, 1) - exp, err := expressions.NewVariableExpression(sourceMap, "test") + predicate, err := expressions.NewVariableExpression(sourceMap, "test") So(err, ShouldBeNil) - s.Add(exp) + retexp, err := expressions.NewReturnExpression(sourceMap, predicate) + So(err, ShouldBeNil) + + err = s.Add(retexp) So(err, ShouldBeNil) rootScope, fn := core.NewRootScope() @@ -93,54 +80,56 @@ func TestBlock(t *testing.T) { value, err := s.Exec(context.Background(), scope) So(err, ShouldBeNil) - So(value, ShouldHaveSameTypeAs, values.None) + So(value, ShouldNotBeNil) + So(value, ShouldEqual, "value") }) - Convey("Should return an iterator", t, func() { - s, _ := newExp([]core.Value{ - values.NewInt(1), - values.NewInt(2), - values.NewInt(3), - }) - sourceMap := core.NewSourceMap("test", 1, 1) - exp, _ := expressions.NewVariableExpression(sourceMap, "test") - s.Add(exp) + Convey("Should not found a missing statement", t, func() { + s := expressions.NewBodyExpression(1) - rootScope, _ := core.NewRootScope() - scope := rootScope.Fork() - scope.SetVariable("test", values.NewString("value")) + sourceMap := core.NewSourceMap("test", 1, 1) + predicate, err := expressions.NewVariableExpression(sourceMap, "testExp") + So(err, ShouldBeNil) - iter, err := s.Iterate(context.Background(), scope) + exp, err := expressions.NewReturnExpression(sourceMap, predicate) So(err, ShouldBeNil) - items, err := collections.ToSlice(context.Background(), scope, iter) + err = s.Add(exp) So(err, ShouldBeNil) - So(items, ShouldHaveLength, 3) + + rootScope, fn := core.NewRootScope() + scope := rootScope.Fork() + scope.SetVariable("test", values.NewString("value")) + fn() + + value, err := s.Exec(context.Background(), scope) + So(err, ShouldNotBeNil) + So(err, ShouldHaveSameTypeAs, core.ErrNotFound) + So(value, ShouldHaveSameTypeAs, values.None) }) - Convey("Should stop an execution when context is cancelled", t, func() { - s, _ := newExp(make([]core.Value, 0, 10)) + Convey("Should not exec a nil block expression", t, func() { + s := expressions.NewBodyExpression(1) + sourceMap := core.NewSourceMap("test", 1, 1) - exp, _ := expressions.NewVariableExpression(sourceMap, "test") - s.Add(exp) + exp, err := expressions.NewVariableExpression(sourceMap, "test") + So(err, ShouldBeNil) - rootScope, _ := core.NewRootScope() + err = s.Add(exp) + So(err, ShouldBeNil) + + rootScope, fn := core.NewRootScope() scope := rootScope.Fork() scope.SetVariable("test", values.NewString("value")) + fn() - ctx, cancel := context.WithCancel(context.Background()) - cancel() - - _, err := s.Exec(ctx, scope) - So(err, ShouldEqual, core.ErrTerminated) + value, err := s.Exec(context.Background(), scope) + So(err, ShouldBeNil) + So(value, ShouldHaveSameTypeAs, values.None) }) - Convey("Should stop an execution when context is cancelled 2", t, func() { - s, _ := newExp([]core.Value{ - values.NewInt(1), - values.NewInt(2), - values.NewInt(3), - }) + Convey("Should stop an execution when context is cancelled", t, func() { + s := expressions.NewBodyExpression(1) sourceMap := core.NewSourceMap("test", 1, 1) exp, _ := expressions.NewVariableExpression(sourceMap, "test") s.Add(exp) @@ -152,7 +141,7 @@ func TestBlock(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) cancel() - _, err := s.Iterate(ctx, scope) + _, err := s.Exec(ctx, scope) So(err, ShouldEqual, core.ErrTerminated) }) } diff --git a/pkg/runtime/expressions/body_test.go~HEAD b/pkg/runtime/expressions/body_test.go~HEAD deleted file mode 100644 index fd4a28404..000000000 --- a/pkg/runtime/expressions/body_test.go~HEAD +++ /dev/null @@ -1,147 +0,0 @@ -package expressions_test - -import ( - "context" - "testing" - - "github.com/MontFerret/ferret/pkg/runtime/core" - "github.com/MontFerret/ferret/pkg/runtime/expressions" - "github.com/MontFerret/ferret/pkg/runtime/values" - . "github.com/smartystreets/goconvey/convey" -) - -func TestBody(t *testing.T) { - Convey("Should create a block expression", t, func() { - s := expressions.NewBodyExpression(1) - - So(s, ShouldHaveSameTypeAs, &expressions.BodyExpression{}) - }) - - Convey("Should add a new expression of a default type", t, func() { - s := expressions.NewBodyExpression(0) - - sourceMap := core.NewSourceMap("test", 1, 1) - exp, err := expressions.NewVariableExpression(sourceMap, "testExp") - So(err, ShouldBeNil) - - err = s.Add(exp) - So(err, ShouldBeNil) - }) - - Convey("Should add a new Return expression", t, func() { - s := expressions.NewBodyExpression(0) - - sourceMap := core.NewSourceMap("test", 1, 1) - predicate, err := expressions.NewVariableExpression(sourceMap, "testExp") - So(err, ShouldBeNil) - - exp, err := expressions.NewReturnExpression(sourceMap, predicate) - So(err, ShouldBeNil) - - err = s.Add(exp) - So(err, ShouldBeNil) - }) - - Convey("Should not add an already defined Return expression", t, func() { - s := expressions.NewBodyExpression(0) - - sourceMap := core.NewSourceMap("test", 1, 1) - predicate, err := expressions.NewVariableExpression(sourceMap, "testExp") - So(err, ShouldBeNil) - - exp, err := expressions.NewReturnExpression(sourceMap, predicate) - So(err, ShouldBeNil) - - err = s.Add(exp) - So(err, ShouldBeNil) - - err = s.Add(exp) - So(err, ShouldBeError) - So(err.Error(), ShouldEqual, "invalid operation: return expression is already defined") - }) - - Convey("Should exec a block expression", t, func() { - s := expressions.NewBodyExpression(1) - - sourceMap := core.NewSourceMap("test", 1, 1) - predicate, err := expressions.NewVariableExpression(sourceMap, "test") - So(err, ShouldBeNil) - - retexp, err := expressions.NewReturnExpression(sourceMap, predicate) - So(err, ShouldBeNil) - - err = s.Add(retexp) - So(err, ShouldBeNil) - - rootScope, fn := core.NewRootScope() - scope := rootScope.Fork() - scope.SetVariable("test", values.NewString("value")) - fn() - - value, err := s.Exec(context.Background(), scope) - So(err, ShouldBeNil) - So(value, ShouldNotBeNil) - So(value, ShouldEqual, "value") - }) - - Convey("Should not found a missing statement", t, func() { - s := expressions.NewBodyExpression(1) - - sourceMap := core.NewSourceMap("test", 1, 1) - predicate, err := expressions.NewVariableExpression(sourceMap, "testExp") - So(err, ShouldBeNil) - - exp, err := expressions.NewReturnExpression(sourceMap, predicate) - So(err, ShouldBeNil) - - err = s.Add(exp) - So(err, ShouldBeNil) - - rootScope, fn := core.NewRootScope() - scope := rootScope.Fork() - scope.SetVariable("test", values.NewString("value")) - fn() - - value, err := s.Exec(context.Background(), scope) - So(err, ShouldNotBeNil) - So(err, ShouldHaveSameTypeAs, core.ErrNotFound) - So(value, ShouldHaveSameTypeAs, values.None) - }) - - Convey("Should not exec a nil block expression", t, func() { - s := expressions.NewBodyExpression(1) - - sourceMap := core.NewSourceMap("test", 1, 1) - exp, err := expressions.NewVariableExpression(sourceMap, "test") - So(err, ShouldBeNil) - - err = s.Add(exp) - So(err, ShouldBeNil) - - rootScope, fn := core.NewRootScope() - scope := rootScope.Fork() - scope.SetVariable("test", values.NewString("value")) - fn() - - value, err := s.Exec(context.Background(), scope) - So(err, ShouldBeNil) - So(value, ShouldHaveSameTypeAs, values.None) - }) - - Convey("Should stop an execution when context is cancelled", t, func() { - s := expressions.NewBodyExpression(1) - sourceMap := core.NewSourceMap("test", 1, 1) - exp, _ := expressions.NewVariableExpression(sourceMap, "test") - s.Add(exp) - - rootScope, _ := core.NewRootScope() - scope := rootScope.Fork() - scope.SetVariable("test", values.NewString("value")) - - ctx, cancel := context.WithCancel(context.Background()) - cancel() - - _, err := s.Exec(ctx, scope) - So(err, ShouldEqual, core.ErrTerminated) - }) -} diff --git a/pkg/runtime/expressions/param_test.go b/pkg/runtime/expressions/param_test.go index 9aac59156..063fdb480 100644 --- a/pkg/runtime/expressions/param_test.go +++ b/pkg/runtime/expressions/param_test.go @@ -2,7 +2,6 @@ package expressions_test import ( "context" - "github.com/MontFerret/ferret/pkg/runtime/values/types" "testing" "github.com/MontFerret/ferret/pkg/runtime/values/types" diff --git a/pkg/runtime/values/array.go b/pkg/runtime/values/array.go index 0712e6ffc..fa3b7dac9 100644 --- a/pkg/runtime/values/array.go +++ b/pkg/runtime/values/array.go @@ -258,18 +258,3 @@ func (t *Array) SortWith(sorter ArraySorter) *Array { return res } - -func (t *Array) Clone() core.Cloneable { - cloned := NewArray(0) - - var value core.Value - for idx := NewInt(0); idx < t.Length(); idx++ { - value = t.Get(idx) - if IsCloneable(value) { - value = value.(core.Cloneable).Clone() - } - cloned.Push(value) - } - - return cloned -}