blob: 1a5484bad2851915be5da3160797f1b3933f6bfd [file] [log] [blame]
// Copyright (C) 2016 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fsm_test
import (
"testing"
"time"
"android.googlesource.com/platform/tools/gpu/framework/assert"
"android.googlesource.com/platform/tools/gpu/framework/fsm"
"android.googlesource.com/platform/tools/gpu/framework/log"
"android.googlesource.com/platform/tools/gpu/framework/task"
)
func stateChecker(name fsm.StateID) fsm.State {
return fsm.Builder(name, func(ctx log.Context, data interface{}) (task.Task, error) {
return func(ctx log.Context) error {
assert.For(ctx, "state").That(fsm.Get(ctx).State()).Equals(name)
return nil
}, nil
})
}
func TestCurrentState(t *testing.T) {
ctx := assert.Context(t)
fsm.Run(ctx, fsm.MustCompile(fsm.FSM{
States: []fsm.State{
stateChecker("A"),
stateChecker("B"),
fsm.Exit("C"),
},
Transitions: []fsm.Transition{
{From: "A", To: "B"},
{From: "B", To: "C"},
},
}))
}
func TestTeardown(t *testing.T) {
ctx := assert.Context(t)
running, release := task.NewSignal()
inner, cancel := task.WithCancel(ctx)
handle := task.Go(ctx, func(ctx log.Context) error {
return fsm.Run(inner, fsm.MustCompile(fsm.FSM{
Controller: func(ctx log.Context) error {
release(ctx)
return nil
},
States: []fsm.State{
fsm.Idle("Init"),
},
}))
})
running.Wait()
cancel()
assert.For(ctx, "FSM complete").That(handle.TryWait(time.Second)).Equals(true)
}
func TestControllerFail(t *testing.T) {
ctx := assert.Context(t)
handle := task.Go(ctx, func(ctx log.Context) error {
return fsm.Run(ctx, fsm.MustCompile(fsm.FSM{
Controller: func(ctx log.Context) error {
return ctx.AsError("Controller error")
},
States: []fsm.State{
fsm.Idle("Init"),
},
}))
})
if !handle.TryWait(time.Second) {
ctx.Error().Log("FSM did not complete")
return
}
assert.With(ctx).ThatError(handle.Result()).HasMessage("Error:Controller error")
}
func TestTriggerOverride(t *testing.T) {
ctx := assert.Context(t)
did := "?"
fsm.Run(ctx, fsm.MustCompile(fsm.FSM{
States: []fsm.State{
fsm.Do("A", func(ctx log.Context) error {
fsm.Get(ctx).Trigger(ctx, "dob")
fsm.Get(ctx).Trigger(ctx, "doc")
return nil
}),
fsm.Do("B", func(ctx log.Context) error { did = "b"; return nil }),
fsm.Do("C", func(ctx log.Context) error { did = "c"; return nil }),
},
Transitions: []fsm.Transition{
{From: "A", Event: "dob", To: "B"},
{From: "A", Event: "doc", To: "C"},
},
}))
assert.With(ctx).That(did).Equals("c")
}
func TestBadTrigger(t *testing.T) {
ctx := assert.Context(t)
fsm.Run(ctx, fsm.MustCompile(fsm.FSM{
States: []fsm.State{
fsm.Do("A", func(ctx log.Context) error {
_, err := fsm.Get(ctx).Trigger(ctx, "bad")
assert.With(ctx).ThatError(err).HasMessage("Error:Invalid event")
return nil
}),
},
}))
}
func TestNotRunningTrigger(t *testing.T) {
ctx := assert.Context(t)
var instance *fsm.Instance
fsm.Run(ctx, fsm.MustCompile(fsm.FSM{
States: []fsm.State{
fsm.Do("A", func(ctx log.Context) error {
instance = fsm.Get(ctx)
return nil
}),
},
}))
_, err := instance.Trigger(ctx, nil)
assert.With(ctx).ThatError(err).HasMessage("Error:Transition when not running")
}
func TestData(t *testing.T) {
ctx := assert.Context(t)
myData := 4
fsm.RunWith(ctx, myData, fsm.MustCompile(fsm.FSM{
States: []fsm.State{
fsm.Do("A", func(ctx log.Context) error {
assert.With(ctx).That(fsm.Get(ctx).Data()).Equals(myData)
return nil
}),
},
}))
}