1
0
mirror of https://github.com/MontFerret/ferret.git synced 2024-12-23 01:24:30 +02:00
ferret/pkg/runtime/core/scope_test.go
Tim Voronov 1af8b37a0f
New type system (#232)
* New type system

* Fixed dot notation for HTML elements
2019-02-13 12:31:18 -05:00

253 lines
5.1 KiB
Go

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) {
Convey(".SetVariable", t, func() {
Convey("Should set a new variable", func() {
rs, cf := core.NewRootScope()
So(cf, ShouldNotBeNil)
err := rs.SetVariable("foo", values.NewString("bar"))
So(err, ShouldBeNil)
})
Convey("Should return an error when a variable is already defined", func() {
rs, cf := core.NewRootScope()
So(cf, ShouldNotBeNil)
err := rs.SetVariable("foo", values.NewString("bar"))
So(err, ShouldBeNil)
err = rs.SetVariable("foo", values.NewString("bar"))
So(err, ShouldHaveSameTypeAs, core.ErrNotUnique)
})
})
Convey(".GetVariable", t, func() {
Convey("Should set and get a variable", func() {
rs, cf := core.NewRootScope()
So(cf, ShouldNotBeNil)
err := rs.SetVariable("foo", values.NewString("bar"))
So(err, ShouldBeNil)
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)
})
})
})
}
func BenchmarkScope(b *testing.B) {
root, _ := core.NewRootScope()
for n := 0; n < b.N; n++ {
root.Fork()
}
}
type (
TestCloserType struct{}
TestCloserValue struct {
closed bool
}
)
func (tct TestCloserType) ID() int64 {
return 99
}
func (tct TestCloserType) String() string {
return "TestCloser"
}
func (tct TestCloserType) Equals(other core.Type) bool {
return other.ID() == tct.ID()
}
func (tc *TestCloserValue) MarshalJSON() ([]byte, error) {
return nil, core.ErrNotImplemented
}
func (tc *TestCloserValue) Type() core.Type {
return TestCloserType{}
}
func (tc *TestCloserValue) String() string {
return ""
}
func (tc *TestCloserValue) Compare(other core.Value) int64 {
return 0
}
func (tc *TestCloserValue) Unwrap() interface{} {
return tc
}
func (tc *TestCloserValue) Hash() uint64 {
return 0
}
func (tc *TestCloserValue) Copy() core.Value {
return &TestCloserValue{}
}
func (tc *TestCloserValue) 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() {
rs, cf := core.NewRootScope()
tc := &TestCloserValue{}
rs.SetVariable("disposable", tc)
So(tc.closed, ShouldBeFalse)
err := cf()
So(err, ShouldBeNil)
So(tc.closed, ShouldBeTrue)
})
Convey("Should return error if it's already closed", t, func() {
rs, cf := core.NewRootScope()
tc := &TestCloserValue{}
rs.SetVariable("disposable", tc)
So(tc.closed, ShouldBeFalse)
err := cf()
So(err, ShouldBeNil)
So(tc.closed, ShouldBeTrue)
err = cf()
So(err, ShouldHaveSameTypeAs, core.ErrInvalidOperation)
})
}