github.com/MontFerret/ferret@v0.18.0/pkg/runtime/core/scope_test.go (about)

     1  package core_test
     2  
     3  import (
     4  	"testing"
     5  
     6  	. "github.com/smartystreets/goconvey/convey"
     7  
     8  	"github.com/MontFerret/ferret/pkg/runtime/core"
     9  	"github.com/MontFerret/ferret/pkg/runtime/values"
    10  )
    11  
    12  func TestScope(t *testing.T) {
    13  	Convey(".SetVariable", t, func() {
    14  		Convey("Should set a new variable", func() {
    15  			rs, cf := core.NewRootScope()
    16  
    17  			So(cf, ShouldNotBeNil)
    18  
    19  			err := rs.SetVariable("foo", values.NewString("bar"))
    20  
    21  			So(err, ShouldBeNil)
    22  		})
    23  
    24  		Convey("Should return an error when a variable is already defined", func() {
    25  			rs, cf := core.NewRootScope()
    26  
    27  			So(cf, ShouldNotBeNil)
    28  
    29  			err := rs.SetVariable("foo", values.NewString("bar"))
    30  			So(err, ShouldBeNil)
    31  
    32  			err = rs.SetVariable("foo", values.NewString("bar"))
    33  			So(err, ShouldHaveSameTypeAs, core.ErrNotUnique)
    34  		})
    35  	})
    36  
    37  	Convey(".GetVariable", t, func() {
    38  		Convey("Should set and get a variable", func() {
    39  			rs, cf := core.NewRootScope()
    40  
    41  			So(cf, ShouldNotBeNil)
    42  
    43  			err := rs.SetVariable("foo", values.NewString("bar"))
    44  			So(err, ShouldBeNil)
    45  
    46  			v, err := rs.GetVariable("foo")
    47  
    48  			So(err, ShouldBeNil)
    49  			So(v, ShouldEqual, "bar")
    50  		})
    51  
    52  		Convey("Should return an error when variable is not defined", func() {
    53  			rs, cf := core.NewRootScope()
    54  
    55  			So(cf, ShouldNotBeNil)
    56  
    57  			_, err := rs.GetVariable("foo")
    58  
    59  			So(err, ShouldNotBeNil)
    60  		})
    61  	})
    62  
    63  	Convey(".HasVariable", t, func() {
    64  		Convey("Should return TRUE when a variable exists", func() {
    65  			rs, cf := core.NewRootScope()
    66  
    67  			So(cf, ShouldNotBeNil)
    68  
    69  			err := rs.SetVariable("foo", values.NewString("bar"))
    70  			So(err, ShouldBeNil)
    71  
    72  			exists := rs.HasVariable("foo")
    73  
    74  			So(exists, ShouldBeTrue)
    75  		})
    76  
    77  		Convey("Should return FALSE when a variable exists", func() {
    78  			rs, cf := core.NewRootScope()
    79  
    80  			So(cf, ShouldNotBeNil)
    81  
    82  			exists := rs.HasVariable("foo")
    83  
    84  			So(exists, ShouldBeFalse)
    85  		})
    86  	})
    87  
    88  	Convey(".Fork", t, func() {
    89  		Convey("Should create a nested scope", func() {
    90  			Convey("Should set a variable only in a child scope", func() {
    91  				rs, cf := core.NewRootScope()
    92  				So(cf, ShouldNotBeNil)
    93  
    94  				cs := rs.Fork()
    95  				cs.SetVariable("foo", values.NewString("bar"))
    96  
    97  				exists := rs.HasVariable("foo")
    98  
    99  				So(exists, ShouldBeFalse)
   100  			})
   101  
   102  			Convey("Should return a variable defined only in a child scope", func() {
   103  				rs, cf := core.NewRootScope()
   104  				So(cf, ShouldNotBeNil)
   105  
   106  				cs := rs.Fork()
   107  				err := cs.SetVariable("foo", values.NewString("bar"))
   108  				So(err, ShouldBeNil)
   109  
   110  				v, err := cs.GetVariable("foo")
   111  
   112  				So(err, ShouldBeNil)
   113  				So(v, ShouldEqual, "bar")
   114  			})
   115  
   116  			Convey("Should return a variable defined only in a parent scope", func() {
   117  				rs, cf := core.NewRootScope()
   118  				So(cf, ShouldNotBeNil)
   119  
   120  				cs := rs.Fork()
   121  				err := cs.SetVariable("foo", values.NewString("bar"))
   122  				So(err, ShouldBeNil)
   123  
   124  				err = rs.SetVariable("faz", values.NewString("qaz"))
   125  				So(err, ShouldBeNil)
   126  
   127  				v, err := cs.GetVariable("faz")
   128  
   129  				So(err, ShouldBeNil)
   130  				So(v, ShouldEqual, "qaz")
   131  			})
   132  
   133  			Convey("Should set a new variable with a same name defined in a parent scope", func() {
   134  				rs, cf := core.NewRootScope()
   135  				So(cf, ShouldNotBeNil)
   136  
   137  				err := rs.SetVariable("foo", values.NewString("bar"))
   138  				So(err, ShouldBeNil)
   139  
   140  				cs := rs.Fork()
   141  				err = cs.SetVariable("foo", values.NewString("faz"))
   142  				So(err, ShouldBeNil)
   143  
   144  				rsV, err := rs.GetVariable("foo")
   145  				So(err, ShouldBeNil)
   146  
   147  				csV, err := cs.GetVariable("foo")
   148  				So(err, ShouldBeNil)
   149  
   150  				So(csV, ShouldNotEqual, rsV)
   151  			})
   152  		})
   153  	})
   154  }
   155  
   156  func BenchmarkScope(b *testing.B) {
   157  	root, _ := core.NewRootScope()
   158  
   159  	for n := 0; n < b.N; n++ {
   160  		root.Fork()
   161  	}
   162  }
   163  
   164  type (
   165  	TestCloserType struct{}
   166  
   167  	TestCloserValue struct {
   168  		closed bool
   169  	}
   170  )
   171  
   172  func (tct TestCloserType) ID() int64 {
   173  	return 99
   174  }
   175  
   176  func (tct TestCloserType) String() string {
   177  	return "TestCloser"
   178  }
   179  
   180  func (tct TestCloserType) Equals(other core.Type) bool {
   181  	return other.ID() == tct.ID()
   182  }
   183  
   184  func (tc *TestCloserValue) MarshalJSON() ([]byte, error) {
   185  	return nil, core.ErrNotImplemented
   186  }
   187  
   188  func (tc *TestCloserValue) Type() core.Type {
   189  	return TestCloserType{}
   190  }
   191  
   192  func (tc *TestCloserValue) String() string {
   193  	return ""
   194  }
   195  
   196  func (tc *TestCloserValue) Compare(other core.Value) int64 {
   197  	return 0
   198  }
   199  
   200  func (tc *TestCloserValue) Unwrap() interface{} {
   201  	return tc
   202  }
   203  
   204  func (tc *TestCloserValue) Hash() uint64 {
   205  	return 0
   206  }
   207  
   208  func (tc *TestCloserValue) Copy() core.Value {
   209  	return &TestCloserValue{}
   210  }
   211  
   212  func (tc *TestCloserValue) Close() error {
   213  	if tc.closed {
   214  		return core.Error(core.ErrInvalidOperation, "already closed")
   215  	}
   216  
   217  	tc.closed = true
   218  
   219  	return nil
   220  }
   221  
   222  func TestCloseFunc(t *testing.T) {
   223  	Convey("Should close root scope and close all io.Closer values", t, func() {
   224  		rs, cf := core.NewRootScope()
   225  
   226  		tc := &TestCloserValue{}
   227  
   228  		rs.SetVariable("disposable", tc)
   229  		So(tc.closed, ShouldBeFalse)
   230  
   231  		err := cf()
   232  		So(err, ShouldBeNil)
   233  
   234  		So(tc.closed, ShouldBeTrue)
   235  	})
   236  
   237  	Convey("Should return error if it's already closed", t, func() {
   238  		rs, cf := core.NewRootScope()
   239  
   240  		tc := &TestCloserValue{}
   241  
   242  		rs.SetVariable("disposable", tc)
   243  		So(tc.closed, ShouldBeFalse)
   244  
   245  		err := cf()
   246  		So(err, ShouldBeNil)
   247  
   248  		So(tc.closed, ShouldBeTrue)
   249  
   250  		err = cf()
   251  		So(err, ShouldHaveSameTypeAs, core.ErrInvalidOperation)
   252  	})
   253  }