| // Copyright 2011 Aaron Jacobs. All Rights Reserved. |
| // Author: [email protected] (Aaron Jacobs) |
| // |
| // 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 oglematchers |
| |
| import ( |
| "errors" |
| "fmt" |
| "reflect" |
| "strings" |
| ) |
| |
| // AnyOf accepts a set of values S and returns a matcher that follows the |
| // algorithm below when considering a candidate c: |
| // |
| // 1. If there exists a value m in S such that m implements the Matcher |
| // interface and m matches c, return true. |
| // |
| // 2. Otherwise, if there exists a value v in S such that v does not implement |
| // the Matcher interface and the matcher Equals(v) matches c, return true. |
| // |
| // 3. Otherwise, if there is a value m in S such that m implements the Matcher |
| // interface and m returns a fatal error for c, return that fatal error. |
| // |
| // 4. Otherwise, return false. |
| // |
| // This is akin to a logical OR operation for matchers, with non-matchers x |
| // being treated as Equals(x). |
| func AnyOf(vals ...interface{}) Matcher { |
| // Get ahold of a type variable for the Matcher interface. |
| var dummy *Matcher |
| matcherType := reflect.TypeOf(dummy).Elem() |
| |
| // Create a matcher for each value, or use the value itself if it's already a |
| // matcher. |
| wrapped := make([]Matcher, len(vals)) |
| for i, v := range vals { |
| t := reflect.TypeOf(v) |
| if t != nil && t.Implements(matcherType) { |
| wrapped[i] = v.(Matcher) |
| } else { |
| wrapped[i] = Equals(v) |
| } |
| } |
| |
| return &anyOfMatcher{wrapped} |
| } |
| |
| type anyOfMatcher struct { |
| wrapped []Matcher |
| } |
| |
| func (m *anyOfMatcher) Description() string { |
| wrappedDescs := make([]string, len(m.wrapped)) |
| for i, matcher := range m.wrapped { |
| wrappedDescs[i] = matcher.Description() |
| } |
| |
| return fmt.Sprintf("or(%s)", strings.Join(wrappedDescs, ", ")) |
| } |
| |
| func (m *anyOfMatcher) Matches(c interface{}) (err error) { |
| err = errors.New("") |
| |
| // Try each matcher in turn. |
| for _, matcher := range m.wrapped { |
| wrappedErr := matcher.Matches(c) |
| |
| // Return immediately if there's a match. |
| if wrappedErr == nil { |
| err = nil |
| return |
| } |
| |
| // Note the fatal error, if any. |
| if _, isFatal := wrappedErr.(*FatalError); isFatal { |
| err = wrappedErr |
| } |
| } |
| |
| return |
| } |