URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [testing/] [script/] [script.go] - Rev 747
Compare with Previous | Blame | View Log
// Copyright 2009 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.// Package script aids in the testing of code that uses channels.package scriptimport ("fmt""math/rand""reflect""strings")// An Event is an element in a partially ordered set that either sends a value// to a channel or expects a value from a channel.type Event struct {name stringoccurred boolpredecessors []*Eventaction action}type action interface {// getSend returns nil if the action is not a send action.getSend() sendAction// getRecv returns nil if the action is not a receive action.getRecv() recvAction// getChannel returns the channel that the action operates on.getChannel() interface{}}type recvAction interface {recvMatch(interface{}) bool}type sendAction interface {send()}// isReady returns true if all the predecessors of an Event have occurred.func (e Event) isReady() bool {for _, predecessor := range e.predecessors {if !predecessor.occurred {return false}}return true}// A Recv action reads a value from a channel and uses reflect.DeepMatch to// compare it with an expected value.type Recv struct {Channel interface{}Expected interface{}}func (r Recv) getRecv() recvAction { return r }func (Recv) getSend() sendAction { return nil }func (r Recv) getChannel() interface{} { return r.Channel }func (r Recv) recvMatch(chanEvent interface{}) bool {c, ok := chanEvent.(channelRecv)if !ok || c.channel != r.Channel {return false}return reflect.DeepEqual(c.value, r.Expected)}// A RecvMatch action reads a value from a channel and calls a function to// determine if the value matches.type RecvMatch struct {Channel interface{}Match func(interface{}) bool}func (r RecvMatch) getRecv() recvAction { return r }func (RecvMatch) getSend() sendAction { return nil }func (r RecvMatch) getChannel() interface{} { return r.Channel }func (r RecvMatch) recvMatch(chanEvent interface{}) bool {c, ok := chanEvent.(channelRecv)if !ok || c.channel != r.Channel {return false}return r.Match(c.value)}// A Closed action matches if the given channel is closed. The closing is// treated as an event, not a state, thus Closed will only match once for a// given channel.type Closed struct {Channel interface{}}func (r Closed) getRecv() recvAction { return r }func (Closed) getSend() sendAction { return nil }func (r Closed) getChannel() interface{} { return r.Channel }func (r Closed) recvMatch(chanEvent interface{}) bool {c, ok := chanEvent.(channelClosed)if !ok || c.channel != r.Channel {return false}return true}// A Send action sends a value to a channel. The value must match the// type of the channel exactly unless the channel if of type chan interface{}.type Send struct {Channel interface{}Value interface{}}func (Send) getRecv() recvAction { return nil }func (s Send) getSend() sendAction { return s }func (s Send) getChannel() interface{} { return s.Channel }type empty struct {x interface{}}func newEmptyInterface(e empty) reflect.Value {return reflect.ValueOf(e).Field(0)}func (s Send) send() {// With reflect.ChanValue.Send, we must match the types exactly. So, if// s.Channel is a chan interface{} we convert s.Value to an interface{}// first.c := reflect.ValueOf(s.Channel)var v reflect.Valueif iface := c.Type().Elem(); iface.Kind() == reflect.Interface && iface.NumMethod() == 0 {v = newEmptyInterface(empty{s.Value})} else {v = reflect.ValueOf(s.Value)}c.Send(v)}// A Close action closes the given channel.type Close struct {Channel interface{}}func (Close) getRecv() recvAction { return nil }func (s Close) getSend() sendAction { return s }func (s Close) getChannel() interface{} { return s.Channel }func (s Close) send() { reflect.ValueOf(s.Channel).Close() }// A ReceivedUnexpected error results if no active Events match a value// received from a channel.type ReceivedUnexpected struct {Value interface{}ready []*Event}func (r ReceivedUnexpected) Error() string {names := make([]string, len(r.ready))for i, v := range r.ready {names[i] = v.name}return fmt.Sprintf("received unexpected value on one of the channels: %#v. Runnable events: %s", r.Value, strings.Join(names, ", "))}// A SetupError results if there is a error with the configuration of a set of// Events.type SetupError stringfunc (s SetupError) Error() string { return string(s) }func NewEvent(name string, predecessors []*Event, action action) *Event {e := &Event{name, false, predecessors, action}return e}// Given a set of Events, Perform repeatedly iterates over the set and finds the// subset of ready Events (that is, all of their predecessors have// occurred). From that subset, it pseudo-randomly selects an Event to perform.// If the Event is a send event, the send occurs and Perform recalculates the ready// set. If the event is a receive event, Perform waits for a value from any of the// channels that are contained in any of the events. That value is then matched// against the ready events. The first event that matches is considered to// have occurred and Perform recalculates the ready set.//// Perform continues this until all Events have occurred.//// Note that uncollected goroutines may still be reading from any of the// channels read from after Perform returns.//// For example, consider the problem of testing a function that reads values on// one channel and echos them to two output channels. To test this we would// create three events: a send event and two receive events. Each of the// receive events must list the send event as a predecessor but there is no// ordering between the receive events.//// send := NewEvent("send", nil, Send{c, 1})// recv1 := NewEvent("recv 1", []*Event{send}, Recv{c, 1})// recv2 := NewEvent("recv 2", []*Event{send}, Recv{c, 1})// Perform(0, []*Event{send, recv1, recv2})//// At first, only the send event would be in the ready set and thus Perform will// send a value to the input channel. Now the two receive events are ready and// Perform will match each of them against the values read from the output channels.//// It would be invalid to list one of the receive events as a predecessor of// the other. At each receive step, all the receive channels are considered,// thus Perform may see a value from a channel that is not in the current ready// set and fail.func Perform(seed int64, events []*Event) (err error) {r := rand.New(rand.NewSource(seed))channels, err := getChannels(events)if err != nil {return}multiplex := make(chan interface{})for _, channel := range channels {go recvValues(multiplex, channel)}Outer:for {ready, err := readyEvents(events)if err != nil {return err}if len(ready) == 0 {// All events occurred.break}event := ready[r.Intn(len(ready))]if send := event.action.getSend(); send != nil {send.send()event.occurred = truecontinue}v := <-multiplexfor _, event := range ready {if recv := event.action.getRecv(); recv != nil && recv.recvMatch(v) {event.occurred = truecontinue Outer}}return ReceivedUnexpected{v, ready}}return nil}// getChannels returns all the channels listed in any receive events.func getChannels(events []*Event) ([]interface{}, error) {channels := make([]interface{}, len(events))j := 0for _, event := range events {if recv := event.action.getRecv(); recv == nil {continue}c := event.action.getChannel()if reflect.ValueOf(c).Kind() != reflect.Chan {return nil, SetupError("one of the channel values is not a channel")}duplicate := falsefor _, other := range channels[0:j] {if c == other {duplicate = truebreak}}if !duplicate {channels[j] = cj++}}return channels[0:j], nil}// recvValues is a multiplexing helper function. It reads values from the given// channel repeatedly, wrapping them up as either a channelRecv or// channelClosed structure, and forwards them to the multiplex channel.func recvValues(multiplex chan<- interface{}, channel interface{}) {c := reflect.ValueOf(channel)for {v, ok := c.Recv()if !ok {multiplex <- channelClosed{channel}return}multiplex <- channelRecv{channel, v.Interface()}}}type channelClosed struct {channel interface{}}type channelRecv struct {channel interface{}value interface{}}// readyEvents returns the subset of events that are ready.func readyEvents(events []*Event) ([]*Event, error) {ready := make([]*Event, len(events))j := 0eventsWaiting := falsefor _, event := range events {if event.occurred {continue}eventsWaiting = trueif event.isReady() {ready[j] = eventj++}}if j == 0 && eventsWaiting {names := make([]string, len(events))for _, event := range events {if event.occurred {continue}names[j] = event.name}return nil, SetupError("dependency cycle in events. These events are waiting to run but cannot: " + strings.Join(names, ", "))}return ready[0:j], nil}
