| 
									
										
										
										
											2018-10-11 09:39:52 -06:00
										 |  |  | package core_test | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"testing" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/MontFerret/ferret/pkg/runtime/core" | 
					
						
							|  |  |  | 	"github.com/MontFerret/ferret/pkg/runtime/values" | 
					
						
							|  |  |  | 	. "github.com/smartystreets/goconvey/convey" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestScope(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2018-10-28 01:45:26 -04:00
										 |  |  | 	Convey(".SetVariable", t, func() { | 
					
						
							|  |  |  | 		Convey("Should set a new variable", func() { | 
					
						
							|  |  |  | 			rs, cf := core.NewRootScope() | 
					
						
							| 
									
										
										
										
											2018-10-11 09:39:52 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 01:45:26 -04:00
										 |  |  | 			So(cf, ShouldNotBeNil) | 
					
						
							| 
									
										
										
										
											2018-10-11 09:39:52 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 01:45:26 -04:00
										 |  |  | 			err := rs.SetVariable("foo", values.NewString("bar")) | 
					
						
							| 
									
										
										
										
											2018-10-11 09:39:52 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 01:45:26 -04:00
										 |  |  | 			So(err, ShouldBeNil) | 
					
						
							|  |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2018-10-11 09:39:52 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 01:45:26 -04:00
										 |  |  | 		Convey("Should return an error when a variable is already defined", func() { | 
					
						
							|  |  |  | 			rs, cf := core.NewRootScope() | 
					
						
							| 
									
										
										
										
											2018-10-11 09:39:52 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 01:45:26 -04:00
										 |  |  | 			So(cf, ShouldNotBeNil) | 
					
						
							| 
									
										
										
										
											2018-10-11 09:39:52 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 01:45:26 -04:00
										 |  |  | 			err := rs.SetVariable("foo", values.NewString("bar")) | 
					
						
							|  |  |  | 			So(err, ShouldBeNil) | 
					
						
							| 
									
										
										
										
											2018-10-11 09:39:52 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 01:45:26 -04:00
										 |  |  | 			err = rs.SetVariable("foo", values.NewString("bar")) | 
					
						
							|  |  |  | 			So(err, ShouldHaveSameTypeAs, core.ErrNotUnique) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2018-10-11 09:39:52 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 01:45:26 -04:00
										 |  |  | 	Convey(".GetVariable", t, func() { | 
					
						
							|  |  |  | 		Convey("Should set and get a variable", func() { | 
					
						
							|  |  |  | 			rs, cf := core.NewRootScope() | 
					
						
							| 
									
										
										
										
											2018-10-11 09:39:52 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 01:45:26 -04:00
										 |  |  | 			So(cf, ShouldNotBeNil) | 
					
						
							| 
									
										
										
										
											2018-10-11 09:39:52 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 01:45:26 -04:00
										 |  |  | 			err := rs.SetVariable("foo", values.NewString("bar")) | 
					
						
							|  |  |  | 			So(err, ShouldBeNil) | 
					
						
							| 
									
										
										
										
											2018-10-11 09:39:52 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 01:45:26 -04:00
										 |  |  | 			v, err := rs.GetVariable("foo") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			So(err, ShouldBeNil) | 
					
						
							|  |  |  | 			So(v, ShouldEqual, "bar") | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		Convey("Should return an error when variable is not defined", func() { | 
					
						
							|  |  |  | 			rs, cf := core.NewRootScope() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			So(cf, ShouldNotBeNil) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			_, err := rs.GetVariable("foo") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			So(err, ShouldNotBeNil) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Convey(".HasVariable", t, func() { | 
					
						
							|  |  |  | 		Convey("Should return TRUE when a variable exists", func() { | 
					
						
							|  |  |  | 			rs, cf := core.NewRootScope() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			So(cf, ShouldNotBeNil) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			err := rs.SetVariable("foo", values.NewString("bar")) | 
					
						
							|  |  |  | 			So(err, ShouldBeNil) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			exists := rs.HasVariable("foo") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			So(exists, ShouldBeTrue) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		Convey("Should return FALSE when a variable exists", func() { | 
					
						
							|  |  |  | 			rs, cf := core.NewRootScope() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			So(cf, ShouldNotBeNil) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			exists := rs.HasVariable("foo") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			So(exists, ShouldBeFalse) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Convey(".Fork", t, func() { | 
					
						
							|  |  |  | 		Convey("Should create a nested scope", func() { | 
					
						
							|  |  |  | 			Convey("Should set a variable only in a child scope", func() { | 
					
						
							|  |  |  | 				rs, cf := core.NewRootScope() | 
					
						
							|  |  |  | 				So(cf, ShouldNotBeNil) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				cs := rs.Fork() | 
					
						
							|  |  |  | 				cs.SetVariable("foo", values.NewString("bar")) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				exists := rs.HasVariable("foo") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				So(exists, ShouldBeFalse) | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			Convey("Should return a variable defined only in a child scope", func() { | 
					
						
							|  |  |  | 				rs, cf := core.NewRootScope() | 
					
						
							|  |  |  | 				So(cf, ShouldNotBeNil) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				cs := rs.Fork() | 
					
						
							|  |  |  | 				err := cs.SetVariable("foo", values.NewString("bar")) | 
					
						
							|  |  |  | 				So(err, ShouldBeNil) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				v, err := cs.GetVariable("foo") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				So(err, ShouldBeNil) | 
					
						
							|  |  |  | 				So(v, ShouldEqual, "bar") | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			Convey("Should return a variable defined only in a parent scope", func() { | 
					
						
							|  |  |  | 				rs, cf := core.NewRootScope() | 
					
						
							|  |  |  | 				So(cf, ShouldNotBeNil) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				cs := rs.Fork() | 
					
						
							|  |  |  | 				err := cs.SetVariable("foo", values.NewString("bar")) | 
					
						
							|  |  |  | 				So(err, ShouldBeNil) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				err = rs.SetVariable("faz", values.NewString("qaz")) | 
					
						
							|  |  |  | 				So(err, ShouldBeNil) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				v, err := cs.GetVariable("faz") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				So(err, ShouldBeNil) | 
					
						
							|  |  |  | 				So(v, ShouldEqual, "qaz") | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			Convey("Should set a new variable with a same name defined in a parent scope", func() { | 
					
						
							|  |  |  | 				rs, cf := core.NewRootScope() | 
					
						
							|  |  |  | 				So(cf, ShouldNotBeNil) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				err := rs.SetVariable("foo", values.NewString("bar")) | 
					
						
							|  |  |  | 				So(err, ShouldBeNil) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				cs := rs.Fork() | 
					
						
							|  |  |  | 				err = cs.SetVariable("foo", values.NewString("faz")) | 
					
						
							|  |  |  | 				So(err, ShouldBeNil) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				rsV, err := rs.GetVariable("foo") | 
					
						
							|  |  |  | 				So(err, ShouldBeNil) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				csV, err := cs.GetVariable("foo") | 
					
						
							|  |  |  | 				So(err, ShouldBeNil) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				So(csV, ShouldNotEqual, rsV) | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2018-10-11 09:39:52 -06:00
										 |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 01:45:26 -04:00
										 |  |  | func BenchmarkScope(b *testing.B) { | 
					
						
							|  |  |  | 	root, _ := core.NewRootScope() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for n := 0; n < b.N; n++ { | 
					
						
							|  |  |  | 		root.Fork() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type TestCloser struct { | 
					
						
							|  |  |  | 	closed bool | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (tc *TestCloser) MarshalJSON() ([]byte, error) { | 
					
						
							|  |  |  | 	return nil, core.ErrNotImplemented | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (tc *TestCloser) Type() core.Type { | 
					
						
							|  |  |  | 	return core.NoneType | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (tc *TestCloser) String() string { | 
					
						
							|  |  |  | 	return "" | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (tc *TestCloser) Compare(other core.Value) int { | 
					
						
							|  |  |  | 	return 0 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (tc *TestCloser) Unwrap() interface{} { | 
					
						
							|  |  |  | 	return tc | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (tc *TestCloser) Hash() uint64 { | 
					
						
							|  |  |  | 	return 0 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (tc *TestCloser) Copy() core.Value { | 
					
						
							|  |  |  | 	return &TestCloser{} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (tc *TestCloser) Close() error { | 
					
						
							|  |  |  | 	if tc.closed { | 
					
						
							|  |  |  | 		return core.Error(core.ErrInvalidOperation, "already closed") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tc.closed = true | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestCloseFunc(t *testing.T) { | 
					
						
							|  |  |  | 	Convey("Should close root scope and close all io.Closer values", t, func() { | 
					
						
							| 
									
										
										
										
											2018-10-11 09:39:52 -06:00
										 |  |  | 		rs, cf := core.NewRootScope() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 01:45:26 -04:00
										 |  |  | 		tc := &TestCloser{} | 
					
						
							| 
									
										
										
										
											2018-10-11 09:39:52 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 01:45:26 -04:00
										 |  |  | 		rs.SetVariable("disposable", tc) | 
					
						
							|  |  |  | 		So(tc.closed, ShouldBeFalse) | 
					
						
							| 
									
										
										
										
											2018-10-11 09:39:52 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 01:45:26 -04:00
										 |  |  | 		err := cf() | 
					
						
							| 
									
										
										
										
											2018-10-11 09:39:52 -06:00
										 |  |  | 		So(err, ShouldBeNil) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 01:45:26 -04:00
										 |  |  | 		So(tc.closed, ShouldBeTrue) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Convey("Should return error if it's already closed", t, func() { | 
					
						
							|  |  |  | 		rs, cf := core.NewRootScope() | 
					
						
							| 
									
										
										
										
											2018-10-11 09:39:52 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 01:45:26 -04:00
										 |  |  | 		tc := &TestCloser{} | 
					
						
							| 
									
										
										
										
											2018-10-11 09:39:52 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 01:45:26 -04:00
										 |  |  | 		rs.SetVariable("disposable", tc) | 
					
						
							|  |  |  | 		So(tc.closed, ShouldBeFalse) | 
					
						
							| 
									
										
										
										
											2018-10-11 09:39:52 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 01:45:26 -04:00
										 |  |  | 		err := cf() | 
					
						
							| 
									
										
										
										
											2018-10-11 09:39:52 -06:00
										 |  |  | 		So(err, ShouldBeNil) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 01:45:26 -04:00
										 |  |  | 		So(tc.closed, ShouldBeTrue) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		err = cf() | 
					
						
							|  |  |  | 		So(err, ShouldHaveSameTypeAs, core.ErrInvalidOperation) | 
					
						
							| 
									
										
										
										
											2018-10-11 09:39:52 -06:00
										 |  |  | 	}) | 
					
						
							|  |  |  | } |