mirror of
https://github.com/gravitational/teleport
synced 2024-10-19 08:43:58 +00:00
vendor dependencies
This commit is contained in:
parent
393c67f04b
commit
ee80f947e0
8
Gopkg.lock
generated
8
Gopkg.lock
generated
|
@ -321,6 +321,12 @@
|
|||
packages = ["connlimit","ratelimit","utils"]
|
||||
revision = "5725fecc9a4f3aa6fdc3ffd29cef771241809add"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/vulcand/predicate"
|
||||
packages = ["."]
|
||||
revision = "939c094524d124c55fa8afe0e077701db4a865e2"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/xeipuuv/gojsonpointer"
|
||||
packages = ["."]
|
||||
|
@ -388,6 +394,6 @@
|
|||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "b95b2baa7e996bc32da399192180a50cf289a0b9718f85b57e14a86f46e25048"
|
||||
inputs-digest = "451ff02b1741edaebc95ff6dde7beabbe4d721e179cba379452fa312df4a9f7a"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
|
|
@ -20,6 +20,10 @@
|
|||
# name = "github.com/x/y"
|
||||
# version = "2.4.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/vulcand/predicate"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/docker/docker"
|
||||
revision = "1009e6a40b295187e038b67e184e9c0384d95538"
|
||||
|
|
24
vendor/github.com/vulcand/predicate/.gitignore
generated
vendored
Normal file
24
vendor/github.com/vulcand/predicate/.gitignore
generated
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
*.prof
|
202
vendor/github.com/vulcand/predicate/LICENSE
generated
vendored
Normal file
202
vendor/github.com/vulcand/predicate/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,202 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
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.
|
||||
|
13
vendor/github.com/vulcand/predicate/Makefile
generated
vendored
Normal file
13
vendor/github.com/vulcand/predicate/Makefile
generated
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
|
||||
test: clean
|
||||
go test -v ./... -cover
|
||||
|
||||
clean:
|
||||
find . -name flymake_* -delete
|
||||
|
||||
cover: clean
|
||||
go test -v . -coverprofile=/tmp/coverage.out
|
||||
go tool cover -html=/tmp/coverage.out
|
||||
|
||||
sloccount:
|
||||
find . -name "*.go" -print0 | xargs -0 wc -l
|
53
vendor/github.com/vulcand/predicate/README.md
generated
vendored
Normal file
53
vendor/github.com/vulcand/predicate/README.md
generated
vendored
Normal file
|
@ -0,0 +1,53 @@
|
|||
Predicate
|
||||
=========
|
||||
|
||||
Predicate package used to create interpreted mini languages with Go syntax - mostly to define
|
||||
various predicates for configuration, e.g.
|
||||
|
||||
```
|
||||
Latency() > 40 || ErrorRate() > 0.5.
|
||||
```
|
||||
|
||||
Here's an example of fully functional predicate language to deal with division remainders:
|
||||
|
||||
```go
|
||||
// takes number and returns true or false
|
||||
type numberPredicate func(v int) bool
|
||||
|
||||
// Converts one number to another
|
||||
type numberMapper func(v int) int
|
||||
|
||||
// Function that creates predicate to test if the remainder is 0
|
||||
func divisibleBy(divisor int) numberPredicate {
|
||||
return func(v int) bool {
|
||||
return v%divisor == 0
|
||||
}
|
||||
}
|
||||
|
||||
// Function - logical operator AND that combines predicates
|
||||
func numberAND(a, b numberPredicate) numberPredicate {
|
||||
return func(v int) bool {
|
||||
return a(v) && b(v)
|
||||
}
|
||||
}
|
||||
|
||||
func main(){
|
||||
// Create a new parser and define the supported operators and methods
|
||||
p, err := NewParser(Def{
|
||||
Operators: Operators{
|
||||
AND: numberAND,
|
||||
},
|
||||
Functions: map[string]interface{}{
|
||||
"DivisibleBy": divisibleBy,
|
||||
},
|
||||
})
|
||||
|
||||
pr, err := p.Parse("DivisibleBy(2) && DivisibleBy(3)")
|
||||
if err == nil {
|
||||
fmt.Fatalf("Error: %v", err)
|
||||
}
|
||||
pr.(numberPredicate)(2) // false
|
||||
pr.(numberPredicate)(3) // false
|
||||
pr.(numberPredicate)(6) // true
|
||||
}
|
||||
```
|
150
vendor/github.com/vulcand/predicate/lib.go
generated
vendored
Normal file
150
vendor/github.com/vulcand/predicate/lib.go
generated
vendored
Normal file
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
Copyright 2016 Vulcand Authors
|
||||
|
||||
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 predicate
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
)
|
||||
|
||||
// GetStringMapValue is a helper function that returns property
|
||||
// from map[string]string or map[string][]string
|
||||
// the function returns empty value in case if key not found
|
||||
// In case if map is nil, returns empty value as well
|
||||
func GetStringMapValue(mapVal, keyVal interface{}) (interface{}, error) {
|
||||
key, ok := keyVal.(string)
|
||||
if !ok {
|
||||
return nil, trace.BadParameter("only string keys are supported")
|
||||
}
|
||||
switch m := mapVal.(type) {
|
||||
case map[string][]string:
|
||||
if len(m) == 0 {
|
||||
// to return nil with a proper type
|
||||
var n []string
|
||||
return n, nil
|
||||
}
|
||||
return m[key], nil
|
||||
case map[string]string:
|
||||
if len(m) == 0 {
|
||||
return "", nil
|
||||
}
|
||||
return m[key], nil
|
||||
default:
|
||||
return nil, trace.BadParameter("type %T is not supported", m)
|
||||
}
|
||||
}
|
||||
|
||||
// BoolPredicate is a function without arguments that returns
|
||||
// boolean value when called
|
||||
type BoolPredicate func() bool
|
||||
|
||||
// Equals can compare complex objects, e.g. arrays of strings
|
||||
// and strings together
|
||||
func Equals(a interface{}, b interface{}) BoolPredicate {
|
||||
return func() bool {
|
||||
switch aval := a.(type) {
|
||||
case string:
|
||||
bval, ok := b.(string)
|
||||
return ok && aval == bval
|
||||
case []string:
|
||||
bval, ok := b.([]string)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if len(aval) != len(bval) {
|
||||
return false
|
||||
}
|
||||
for i := range aval {
|
||||
if aval[i] != bval[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Contains checks if string slice contains a string
|
||||
// Contains([]string{"a", "b"}, "b") -> true
|
||||
func Contains(a interface{}, b interface{}) BoolPredicate {
|
||||
return func() bool {
|
||||
aval, ok := a.([]string)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
bval, ok := b.(string)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
for _, v := range aval {
|
||||
if v == bval {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// And is a boolean predicate that calls two boolean predicates
|
||||
// and returns result of && operation on their return values
|
||||
func And(a, b BoolPredicate) BoolPredicate {
|
||||
return func() bool {
|
||||
return a() && b()
|
||||
}
|
||||
}
|
||||
|
||||
// Or is a boolean predicate that calls two boolean predicates
|
||||
// and returns result of || operation on their return values
|
||||
func Or(a, b BoolPredicate) BoolPredicate {
|
||||
return func() bool {
|
||||
return a() || b()
|
||||
}
|
||||
}
|
||||
|
||||
// GetFieldByTag returns a field from the object based on the tag
|
||||
func GetFieldByTag(ival interface{}, tagName string, fieldNames []string) (interface{}, error) {
|
||||
if len(fieldNames) == 0 {
|
||||
return nil, trace.BadParameter("missing field names")
|
||||
}
|
||||
val := reflect.ValueOf(ival)
|
||||
if val.Kind() == reflect.Interface || val.Kind() == reflect.Ptr {
|
||||
val = val.Elem()
|
||||
}
|
||||
if val.Kind() != reflect.Struct {
|
||||
return nil, trace.NotFound("field name %v is not found", strings.Join(fieldNames, "."))
|
||||
}
|
||||
fieldName := fieldNames[0]
|
||||
rest := fieldNames[1:]
|
||||
|
||||
valType := val.Type()
|
||||
for i := 0; i < valType.NumField(); i++ {
|
||||
tagValue := valType.Field(i).Tag.Get(tagName)
|
||||
parts := strings.Split(tagValue, ",")
|
||||
if parts[0] == fieldName {
|
||||
value := val.Field(i).Interface()
|
||||
if len(rest) == 0 {
|
||||
return value, nil
|
||||
}
|
||||
return GetFieldByTag(value, tagName, rest)
|
||||
}
|
||||
}
|
||||
return nil, trace.NotFound("field name %v is not found", strings.Join(fieldNames, "."))
|
||||
}
|
256
vendor/github.com/vulcand/predicate/parse.go
generated
vendored
Normal file
256
vendor/github.com/vulcand/predicate/parse.go
generated
vendored
Normal file
|
@ -0,0 +1,256 @@
|
|||
package predicate
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
)
|
||||
|
||||
func NewParser(d Def) (Parser, error) {
|
||||
return &predicateParser{d: d}, nil
|
||||
}
|
||||
|
||||
type predicateParser struct {
|
||||
d Def
|
||||
}
|
||||
|
||||
func (p *predicateParser) Parse(in string) (interface{}, error) {
|
||||
expr, err := parser.ParseExpr(in)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return p.parseNode(expr)
|
||||
}
|
||||
|
||||
func (p *predicateParser) parseNode(node ast.Node) (interface{}, error) {
|
||||
switch n := node.(type) {
|
||||
case *ast.BasicLit:
|
||||
return literalToValue(n)
|
||||
case *ast.BinaryExpr:
|
||||
x, err := p.parseNode(n.X)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
y, err := p.parseNode(n.Y)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return p.joinPredicates(n.Op, x, y)
|
||||
case *ast.CallExpr:
|
||||
// We expect function that will return predicate
|
||||
name, err := getIdentifier(n.Fun)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fn, err := p.getFunction(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
arguments, err := p.evaluateArguments(n.Args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return callFunction(fn, arguments)
|
||||
case *ast.ParenExpr:
|
||||
return p.parseNode(n.X)
|
||||
}
|
||||
return nil, trace.BadParameter("unsupported %T", node)
|
||||
}
|
||||
|
||||
func (p *predicateParser) evaluateArguments(nodes []ast.Expr) ([]interface{}, error) {
|
||||
out := make([]interface{}, len(nodes))
|
||||
for i, n := range nodes {
|
||||
val, err := p.evaluateExpr(n)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
out[i] = val
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (p *predicateParser) evaluateExpr(n ast.Expr) (interface{}, error) {
|
||||
switch l := n.(type) {
|
||||
case *ast.BasicLit:
|
||||
val, err := literalToValue(l)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return val, nil
|
||||
case *ast.IndexExpr:
|
||||
if p.d.GetProperty == nil {
|
||||
return nil, trace.NotFound("properties are not supported")
|
||||
}
|
||||
mapVal, err := p.evaluateExpr(l.X)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
keyVal, err := p.evaluateExpr(l.Index)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
val, err := p.d.GetProperty(mapVal, keyVal)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
return val, nil
|
||||
case *ast.SelectorExpr:
|
||||
fields, err := evaluateSelector(l, []string{})
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
if p.d.GetIdentifier == nil {
|
||||
return nil, trace.NotFound("%v is not defined", strings.Join(fields, "."))
|
||||
}
|
||||
val, err := p.d.GetIdentifier(fields)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
return val, nil
|
||||
case *ast.Ident:
|
||||
if p.d.GetIdentifier == nil {
|
||||
return nil, trace.NotFound("%v is not defined", l.Name)
|
||||
}
|
||||
val, err := p.d.GetIdentifier([]string{l.Name})
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
return val, nil
|
||||
default:
|
||||
return nil, trace.BadParameter("%T is not supported", n)
|
||||
}
|
||||
}
|
||||
|
||||
// evaluateSelector recursively evaluates the selector field and returns a list
|
||||
// of properties at the end
|
||||
func evaluateSelector(sel *ast.SelectorExpr, fields []string) ([]string, error) {
|
||||
fields = append([]string{sel.Sel.Name}, fields...)
|
||||
switch l := sel.X.(type) {
|
||||
case *ast.SelectorExpr:
|
||||
return evaluateSelector(l, fields)
|
||||
case *ast.Ident:
|
||||
fields = append([]string{l.Name}, fields...)
|
||||
return fields, nil
|
||||
default:
|
||||
return nil, trace.BadParameter("unsupported selector type: %T", l)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *predicateParser) getFunction(name string) (interface{}, error) {
|
||||
v, ok := p.d.Functions[name]
|
||||
if !ok {
|
||||
return nil, trace.BadParameter("unsupported function: %s", name)
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (p *predicateParser) joinPredicates(op token.Token, a, b interface{}) (interface{}, error) {
|
||||
joinFn, err := p.getJoinFunction(op)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return callFunction(joinFn, []interface{}{a, b})
|
||||
}
|
||||
|
||||
func (p *predicateParser) getJoinFunction(op token.Token) (interface{}, error) {
|
||||
var fn interface{}
|
||||
switch op {
|
||||
case token.LAND:
|
||||
fn = p.d.Operators.AND
|
||||
case token.LOR:
|
||||
fn = p.d.Operators.OR
|
||||
case token.GTR:
|
||||
fn = p.d.Operators.GT
|
||||
case token.GEQ:
|
||||
fn = p.d.Operators.GE
|
||||
case token.LSS:
|
||||
fn = p.d.Operators.LT
|
||||
case token.LEQ:
|
||||
fn = p.d.Operators.LE
|
||||
case token.EQL:
|
||||
fn = p.d.Operators.EQ
|
||||
case token.NEQ:
|
||||
fn = p.d.Operators.NEQ
|
||||
}
|
||||
if fn == nil {
|
||||
return nil, trace.BadParameter("%v is not supported", op)
|
||||
}
|
||||
return fn, nil
|
||||
}
|
||||
|
||||
func getIdentifier(node ast.Node) (string, error) {
|
||||
sexpr, ok := node.(*ast.SelectorExpr)
|
||||
if ok {
|
||||
id, ok := sexpr.X.(*ast.Ident)
|
||||
if !ok {
|
||||
return "", trace.BadParameter("expected selector identifier, got: %T", sexpr.X)
|
||||
}
|
||||
return fmt.Sprintf("%s.%s", id.Name, sexpr.Sel.Name), nil
|
||||
}
|
||||
|
||||
id, ok := node.(*ast.Ident)
|
||||
if !ok {
|
||||
return "", trace.BadParameter("expected identifier, got: %T", node)
|
||||
}
|
||||
return id.Name, nil
|
||||
}
|
||||
|
||||
func literalToValue(a *ast.BasicLit) (interface{}, error) {
|
||||
switch a.Kind {
|
||||
case token.FLOAT:
|
||||
value, err := strconv.ParseFloat(a.Value, 64)
|
||||
if err != nil {
|
||||
return nil, trace.BadParameter("failed to parse argument: %s, error: %s", a.Value, err)
|
||||
}
|
||||
return value, nil
|
||||
case token.INT:
|
||||
value, err := strconv.Atoi(a.Value)
|
||||
if err != nil {
|
||||
return nil, trace.BadParameter("failed to parse argument: %s, error: %s", a.Value, err)
|
||||
}
|
||||
return value, nil
|
||||
case token.STRING:
|
||||
value, err := strconv.Unquote(a.Value)
|
||||
if err != nil {
|
||||
return nil, trace.BadParameter("failed to parse argument: %s, error: %s", a.Value, err)
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
return nil, trace.BadParameter("unsupported function argument type: '%v'", a.Kind)
|
||||
}
|
||||
|
||||
func callFunction(f interface{}, args []interface{}) (v interface{}, err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = trace.BadParameter("%s", r)
|
||||
}
|
||||
}()
|
||||
arguments := make([]reflect.Value, len(args))
|
||||
for i, a := range args {
|
||||
arguments[i] = reflect.ValueOf(a)
|
||||
}
|
||||
fn := reflect.ValueOf(f)
|
||||
|
||||
ret := fn.Call(arguments)
|
||||
switch len(ret) {
|
||||
case 1:
|
||||
return ret[0].Interface(), nil
|
||||
case 2:
|
||||
v, e := ret[0].Interface(), ret[1].Interface()
|
||||
if e == nil {
|
||||
return v, nil
|
||||
}
|
||||
err, ok := e.(error)
|
||||
if !ok {
|
||||
return nil, trace.BadParameter("expected error as a second return value, got %T", e)
|
||||
}
|
||||
return v, err
|
||||
}
|
||||
return nil, trace.BadParameter("expected at least one return argument for '%v'", fn)
|
||||
}
|
477
vendor/github.com/vulcand/predicate/parse_test.go
generated
vendored
Normal file
477
vendor/github.com/vulcand/predicate/parse_test.go
generated
vendored
Normal file
|
@ -0,0 +1,477 @@
|
|||
package predicate
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
"gopkg.in/check.v1"
|
||||
)
|
||||
|
||||
func Test(t *testing.T) { check.TestingT(t) }
|
||||
|
||||
type PredicateSuite struct {
|
||||
}
|
||||
|
||||
var _ = check.Suite(&PredicateSuite{})
|
||||
|
||||
func (s *PredicateSuite) getParser(c *check.C) Parser {
|
||||
return s.getParserWithOpts(c, nil, nil)
|
||||
}
|
||||
|
||||
func (s *PredicateSuite) getParserWithOpts(c *check.C, getID GetIdentifierFn, getProperty GetPropertyFn) Parser {
|
||||
p, err := NewParser(Def{
|
||||
Operators: Operators{
|
||||
AND: numberAND,
|
||||
OR: numberOR,
|
||||
GT: numberGT,
|
||||
LT: numberLT,
|
||||
EQ: numberEQ,
|
||||
NEQ: numberNEQ,
|
||||
LE: numberLE,
|
||||
GE: numberGE,
|
||||
},
|
||||
Functions: map[string]interface{}{
|
||||
"DivisibleBy": divisibleBy,
|
||||
"Remainder": numberRemainder,
|
||||
"Len": stringLength,
|
||||
"number.DivisibleBy": divisibleBy,
|
||||
"Equals": Equals,
|
||||
"Contains": Contains,
|
||||
},
|
||||
GetIdentifier: getID,
|
||||
GetProperty: getProperty,
|
||||
})
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(p, check.NotNil)
|
||||
return p
|
||||
}
|
||||
|
||||
func (s *PredicateSuite) TestSinglePredicate(c *check.C) {
|
||||
p := s.getParser(c)
|
||||
|
||||
pr, err := p.Parse("DivisibleBy(2)")
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(pr, check.FitsTypeOf, divisibleBy(2))
|
||||
fn := pr.(numberPredicate)
|
||||
c.Assert(fn(2), check.Equals, true)
|
||||
c.Assert(fn(3), check.Equals, false)
|
||||
}
|
||||
|
||||
func (s *PredicateSuite) TestModulePredicate(c *check.C) {
|
||||
p := s.getParser(c)
|
||||
|
||||
pr, err := p.Parse("number.DivisibleBy(2)")
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(pr, check.FitsTypeOf, divisibleBy(2))
|
||||
fn := pr.(numberPredicate)
|
||||
c.Assert(fn(2), check.Equals, true)
|
||||
c.Assert(fn(3), check.Equals, false)
|
||||
}
|
||||
|
||||
func (s *PredicateSuite) TestJoinAND(c *check.C) {
|
||||
p := s.getParser(c)
|
||||
|
||||
pr, err := p.Parse("DivisibleBy(2) && DivisibleBy(3)")
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(pr, check.FitsTypeOf, divisibleBy(1))
|
||||
fn := pr.(numberPredicate)
|
||||
c.Assert(fn(2), check.Equals, false)
|
||||
c.Assert(fn(3), check.Equals, false)
|
||||
c.Assert(fn(6), check.Equals, true)
|
||||
}
|
||||
|
||||
func (s *PredicateSuite) TestJoinOR(c *check.C) {
|
||||
p := s.getParser(c)
|
||||
|
||||
pr, err := p.Parse("DivisibleBy(2) || DivisibleBy(3)")
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(pr, check.FitsTypeOf, divisibleBy(1))
|
||||
fn := pr.(numberPredicate)
|
||||
c.Assert(fn(2), check.Equals, true)
|
||||
c.Assert(fn(3), check.Equals, true)
|
||||
c.Assert(fn(5), check.Equals, false)
|
||||
}
|
||||
|
||||
func (s *PredicateSuite) TestGT(c *check.C) {
|
||||
p := s.getParser(c)
|
||||
|
||||
pr, err := p.Parse("Remainder(3) > 1")
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(pr, check.FitsTypeOf, divisibleBy(1))
|
||||
fn := pr.(numberPredicate)
|
||||
c.Assert(fn(1), check.Equals, false)
|
||||
c.Assert(fn(2), check.Equals, true)
|
||||
c.Assert(fn(3), check.Equals, false)
|
||||
c.Assert(fn(4), check.Equals, false)
|
||||
c.Assert(fn(5), check.Equals, true)
|
||||
}
|
||||
|
||||
func (s *PredicateSuite) TestGTE(c *check.C) {
|
||||
p := s.getParser(c)
|
||||
|
||||
pr, err := p.Parse("Remainder(3) >= 1")
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(pr, check.FitsTypeOf, divisibleBy(1))
|
||||
fn := pr.(numberPredicate)
|
||||
c.Assert(fn(1), check.Equals, true)
|
||||
c.Assert(fn(2), check.Equals, true)
|
||||
c.Assert(fn(3), check.Equals, false)
|
||||
c.Assert(fn(4), check.Equals, true)
|
||||
c.Assert(fn(5), check.Equals, true)
|
||||
}
|
||||
|
||||
func (s *PredicateSuite) TestLT(c *check.C) {
|
||||
p := s.getParser(c)
|
||||
|
||||
pr, err := p.Parse("Remainder(3) < 2")
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(pr, check.FitsTypeOf, divisibleBy(1))
|
||||
fn := pr.(numberPredicate)
|
||||
c.Assert(fn(1), check.Equals, true)
|
||||
c.Assert(fn(2), check.Equals, false)
|
||||
c.Assert(fn(3), check.Equals, true)
|
||||
c.Assert(fn(4), check.Equals, true)
|
||||
c.Assert(fn(5), check.Equals, false)
|
||||
}
|
||||
|
||||
func (s *PredicateSuite) TestLE(c *check.C) {
|
||||
p := s.getParser(c)
|
||||
|
||||
pr, err := p.Parse("Remainder(3) <= 2")
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(pr, check.FitsTypeOf, divisibleBy(1))
|
||||
fn := pr.(numberPredicate)
|
||||
c.Assert(fn(1), check.Equals, true)
|
||||
c.Assert(fn(2), check.Equals, true)
|
||||
c.Assert(fn(3), check.Equals, true)
|
||||
c.Assert(fn(4), check.Equals, true)
|
||||
c.Assert(fn(5), check.Equals, true)
|
||||
}
|
||||
|
||||
func (s *PredicateSuite) TestEQ(c *check.C) {
|
||||
p := s.getParser(c)
|
||||
|
||||
pr, err := p.Parse("Remainder(3) == 2")
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(pr, check.FitsTypeOf, divisibleBy(1))
|
||||
fn := pr.(numberPredicate)
|
||||
c.Assert(fn(1), check.Equals, false)
|
||||
c.Assert(fn(2), check.Equals, true)
|
||||
c.Assert(fn(3), check.Equals, false)
|
||||
c.Assert(fn(4), check.Equals, false)
|
||||
c.Assert(fn(5), check.Equals, true)
|
||||
}
|
||||
|
||||
func (s *PredicateSuite) TestNEQ(c *check.C) {
|
||||
p := s.getParser(c)
|
||||
|
||||
pr, err := p.Parse("Remainder(3) != 2")
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(pr, check.FitsTypeOf, divisibleBy(1))
|
||||
fn := pr.(numberPredicate)
|
||||
c.Assert(fn(1), check.Equals, true)
|
||||
c.Assert(fn(2), check.Equals, false)
|
||||
c.Assert(fn(3), check.Equals, true)
|
||||
c.Assert(fn(4), check.Equals, true)
|
||||
c.Assert(fn(5), check.Equals, false)
|
||||
}
|
||||
|
||||
func (s *PredicateSuite) TestParen(c *check.C) {
|
||||
p := s.getParser(c)
|
||||
|
||||
pr, err := p.Parse("(Remainder(3) != 1) && (Remainder(3) != 0)")
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(pr, check.FitsTypeOf, divisibleBy(1))
|
||||
fn := pr.(numberPredicate)
|
||||
c.Assert(fn(0), check.Equals, false)
|
||||
c.Assert(fn(1), check.Equals, false)
|
||||
c.Assert(fn(2), check.Equals, true)
|
||||
}
|
||||
|
||||
func (s *PredicateSuite) TestStrings(c *check.C) {
|
||||
p := s.getParser(c)
|
||||
|
||||
pr, err := p.Parse(`Remainder(3) == Len("hi")`)
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(pr, check.FitsTypeOf, divisibleBy(1))
|
||||
fn := pr.(numberPredicate)
|
||||
c.Assert(fn(0), check.Equals, false)
|
||||
c.Assert(fn(1), check.Equals, false)
|
||||
c.Assert(fn(2), check.Equals, true)
|
||||
}
|
||||
|
||||
func (s *PredicateSuite) TestGTFloat64(c *check.C) {
|
||||
p := s.getParser(c)
|
||||
|
||||
pr, err := p.Parse("Remainder(3) > 1.2")
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(pr, check.FitsTypeOf, divisibleBy(1))
|
||||
fn := pr.(numberPredicate)
|
||||
c.Assert(fn(1), check.Equals, false)
|
||||
c.Assert(fn(2), check.Equals, true)
|
||||
c.Assert(fn(3), check.Equals, false)
|
||||
c.Assert(fn(4), check.Equals, false)
|
||||
c.Assert(fn(5), check.Equals, true)
|
||||
}
|
||||
|
||||
func (s *PredicateSuite) TestIdentifier(c *check.C) {
|
||||
getID := func(fields []string) (interface{}, error) {
|
||||
c.Assert(fields, check.DeepEquals, []string{"first", "second", "third"})
|
||||
return 2, nil
|
||||
}
|
||||
p := s.getParserWithOpts(c, getID, nil)
|
||||
|
||||
pr, err := p.Parse("DivisibleBy(first.second.third)")
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(pr, check.FitsTypeOf, divisibleBy(2))
|
||||
fn := pr.(numberPredicate)
|
||||
c.Assert(fn(2), check.Equals, true)
|
||||
c.Assert(fn(3), check.Equals, false)
|
||||
}
|
||||
|
||||
func (s *PredicateSuite) TestMap(c *check.C) {
|
||||
getID := func(fields []string) (interface{}, error) {
|
||||
c.Assert(fields, check.DeepEquals, []string{"first", "second"})
|
||||
return map[string]int{"key": 2}, nil
|
||||
}
|
||||
getProperty := func(mapVal, keyVal interface{}) (interface{}, error) {
|
||||
m := mapVal.(map[string]int)
|
||||
k := keyVal.(string)
|
||||
return m[k], nil
|
||||
}
|
||||
|
||||
p := s.getParserWithOpts(c, getID, getProperty)
|
||||
|
||||
pr, err := p.Parse(`DivisibleBy(first.second["key"])`)
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(pr, check.FitsTypeOf, divisibleBy(2))
|
||||
fn := pr.(numberPredicate)
|
||||
c.Assert(fn(2), check.Equals, true)
|
||||
c.Assert(fn(3), check.Equals, false)
|
||||
}
|
||||
|
||||
func (s *PredicateSuite) TestIdentifierAndFunction(c *check.C) {
|
||||
getID := func(fields []string) (interface{}, error) {
|
||||
switch fields[0] {
|
||||
case "firstSlice":
|
||||
return []string{"a"}, nil
|
||||
case "secondSlice":
|
||||
return []string{"b"}, nil
|
||||
case "a":
|
||||
return "a", nil
|
||||
case "b":
|
||||
return "b", nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
p := s.getParserWithOpts(c, getID, nil)
|
||||
|
||||
pr, err := p.Parse("Equals(firstSlice, firstSlice)")
|
||||
c.Assert(err, check.IsNil)
|
||||
fn := pr.(BoolPredicate)
|
||||
c.Assert(fn(), check.Equals, true)
|
||||
|
||||
pr, err = p.Parse("Equals(a, a)")
|
||||
c.Assert(err, check.IsNil)
|
||||
fn = pr.(BoolPredicate)
|
||||
c.Assert(fn(), check.Equals, true)
|
||||
|
||||
pr, err = p.Parse("Equals(firstSlice, secondSlice)")
|
||||
c.Assert(err, check.IsNil)
|
||||
fn = pr.(BoolPredicate)
|
||||
c.Assert(fn(), check.Equals, false)
|
||||
}
|
||||
|
||||
func (s *PredicateSuite) TestContains(c *check.C) {
|
||||
val := TestStruct{}
|
||||
val.Param.Key1 = map[string][]string{"key": []string{"a", "b", "c"}}
|
||||
|
||||
getID := func(fields []string) (interface{}, error) {
|
||||
return GetFieldByTag(val, "json", fields[1:])
|
||||
}
|
||||
p := s.getParserWithOpts(c, getID, GetStringMapValue)
|
||||
|
||||
pr, err := p.Parse(`Contains(val.param.key1["key"], "a")`)
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(pr.(BoolPredicate)(), check.Equals, true)
|
||||
|
||||
pr, err = p.Parse(`Contains(val.param.key1["key"], "z")`)
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(pr.(BoolPredicate)(), check.Equals, false)
|
||||
|
||||
pr, err = p.Parse(`Contains(val.param.key1["missing"], "a")`)
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(pr.(BoolPredicate)(), check.Equals, false)
|
||||
}
|
||||
|
||||
func (s *PredicateSuite) TestEquals(c *check.C) {
|
||||
val := TestStruct{}
|
||||
val.Param.Key2 = map[string]string{"key": "a"}
|
||||
|
||||
getID := func(fields []string) (interface{}, error) {
|
||||
return GetFieldByTag(val, "json", fields[1:])
|
||||
}
|
||||
p := s.getParserWithOpts(c, getID, GetStringMapValue)
|
||||
|
||||
pr, err := p.Parse(`Equals(val.param.key2["key"], "a")`)
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(pr.(BoolPredicate)(), check.Equals, true)
|
||||
|
||||
pr, err = p.Parse(`Equals(val.param.key2["key"], "b")`)
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(pr.(BoolPredicate)(), check.Equals, false)
|
||||
|
||||
pr, err = p.Parse(`Contains(val.param.key2["missing"], "z")`)
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(pr.(BoolPredicate)(), check.Equals, false)
|
||||
|
||||
pr, err = p.Parse(`Contains(val.param.key1["missing"], "z")`)
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(pr.(BoolPredicate)(), check.Equals, false)
|
||||
}
|
||||
|
||||
// TestStruct is a test sturcture with json tags
|
||||
type TestStruct struct {
|
||||
Param struct {
|
||||
Key1 map[string][]string `json:"key1,omitempty"`
|
||||
Key2 map[string]string `json:"key2,omitempty"`
|
||||
} `json:"param,omitempty"`
|
||||
}
|
||||
|
||||
func (s *PredicateSuite) TestGetTagField(c *check.C) {
|
||||
val := TestStruct{}
|
||||
val.Param.Key1 = map[string][]string{"key": []string{"val"}}
|
||||
|
||||
type testCase struct {
|
||||
tag string
|
||||
fields []string
|
||||
val interface{}
|
||||
expect interface{}
|
||||
err error
|
||||
}
|
||||
testCases := []testCase{
|
||||
// nested field
|
||||
{tag: "json", val: val, fields: []string{"param", "key1"}, expect: val.Param.Key1},
|
||||
// pointer to struct
|
||||
{tag: "json", val: &val, fields: []string{"param", "key1"}, expect: val.Param.Key1},
|
||||
// not found field
|
||||
{tag: "json", val: &val, fields: []string{"param", "key3"}, err: trace.NotFound("not found")},
|
||||
// nil pointer
|
||||
{tag: "json", val: nil, fields: []string{"param", "key1"}, err: trace.BadParameter("bad param")},
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
comment := check.Commentf("test case %v", i)
|
||||
out, err := GetFieldByTag(tc.val, tc.tag, tc.fields)
|
||||
if tc.err != nil {
|
||||
c.Assert(err, check.FitsTypeOf, tc.err, comment)
|
||||
} else {
|
||||
c.Assert(err, check.IsNil, comment)
|
||||
c.Assert(out, check.DeepEquals, tc.expect, comment)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *PredicateSuite) TestUnhappyCases(c *check.C) {
|
||||
cases := []string{
|
||||
")(", // invalid expression
|
||||
"SomeFunc", // unsupported id
|
||||
"Remainder(banana)", // unsupported argument
|
||||
"Remainder(1, 2)", // unsupported arguments count
|
||||
"Remainder(Len)", // unsupported argument
|
||||
`Remainder(Len("Ho"))`, // unsupported argument
|
||||
"Bla(1)", // unknown method call
|
||||
"0.2 && Remainder(1)", // unsupported value
|
||||
`Len("Ho") && 0.2`, // unsupported value
|
||||
"func(){}()", // function call
|
||||
"Remainder(3) >> 3", // unsupported operator
|
||||
`Remainder(3) > "banana"`, // unsupported comparison type
|
||||
}
|
||||
p := s.getParser(c)
|
||||
for _, expr := range cases {
|
||||
pr, err := p.Parse(expr)
|
||||
c.Assert(err, check.NotNil)
|
||||
c.Assert(pr, check.IsNil)
|
||||
}
|
||||
}
|
||||
|
||||
type numberPredicate func(v int) bool
|
||||
type numberMapper func(v int) int
|
||||
|
||||
func divisibleBy(divisor int) numberPredicate {
|
||||
return func(v int) bool {
|
||||
return v%divisor == 0
|
||||
}
|
||||
}
|
||||
|
||||
func numberAND(a, b numberPredicate) numberPredicate {
|
||||
return func(v int) bool {
|
||||
return a(v) && b(v)
|
||||
}
|
||||
}
|
||||
|
||||
func numberOR(a, b numberPredicate) numberPredicate {
|
||||
return func(v int) bool {
|
||||
return a(v) || b(v)
|
||||
}
|
||||
}
|
||||
|
||||
func numberRemainder(divideBy int) numberMapper {
|
||||
return func(v int) int {
|
||||
return v % divideBy
|
||||
}
|
||||
}
|
||||
|
||||
func numberGT(m numberMapper, value interface{}) (numberPredicate, error) {
|
||||
switch value.(type) {
|
||||
case int:
|
||||
case float64:
|
||||
default:
|
||||
return nil, fmt.Errorf("GT: unsupported argument type: %T", value)
|
||||
}
|
||||
return func(v int) bool {
|
||||
switch val := value.(type) {
|
||||
case int:
|
||||
return m(v) > val
|
||||
case float64:
|
||||
return m(v) > int(val)
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
func numberGE(m numberMapper, value int) (numberPredicate, error) {
|
||||
return func(v int) bool {
|
||||
return m(v) >= value
|
||||
}, nil
|
||||
}
|
||||
|
||||
func numberLE(m numberMapper, value int) (numberPredicate, error) {
|
||||
return func(v int) bool {
|
||||
return m(v) <= value
|
||||
}, nil
|
||||
}
|
||||
|
||||
func numberLT(m numberMapper, value int) numberPredicate {
|
||||
return func(v int) bool {
|
||||
return m(v) < value
|
||||
}
|
||||
}
|
||||
|
||||
func numberEQ(m numberMapper, value int) numberPredicate {
|
||||
return func(v int) bool {
|
||||
return m(v) == value
|
||||
}
|
||||
}
|
||||
|
||||
func numberNEQ(m numberMapper, value int) numberPredicate {
|
||||
return func(v int) bool {
|
||||
return m(v) != value
|
||||
}
|
||||
}
|
||||
|
||||
func stringLength(v string) int {
|
||||
return len(v)
|
||||
}
|
84
vendor/github.com/vulcand/predicate/predicate.go
generated
vendored
Normal file
84
vendor/github.com/vulcand/predicate/predicate.go
generated
vendored
Normal file
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
Predicate package used to create interpreted mini languages with Go syntax - mostly to define
|
||||
various predicates for configuration, e.g. Latency() > 40 || ErrorRate() > 0.5.
|
||||
|
||||
Here's an example of fully functional predicate language to deal with division remainders:
|
||||
|
||||
// takes number and returns true or false
|
||||
type numberPredicate func(v int) bool
|
||||
|
||||
// Converts one number to another
|
||||
type numberMapper func(v int) int
|
||||
|
||||
// Function that creates predicate to test if the remainder is 0
|
||||
func divisibleBy(divisor int) numberPredicate {
|
||||
return func(v int) bool {
|
||||
return v%divisor == 0
|
||||
}
|
||||
}
|
||||
|
||||
// Function - logical operator AND that combines predicates
|
||||
func numberAND(a, b numberPredicate) numberPredicate {
|
||||
return func(v int) bool {
|
||||
return a(v) && b(v)
|
||||
}
|
||||
}
|
||||
|
||||
p, err := NewParser(Def{
|
||||
Operators: Operators{
|
||||
AND: numberAND,
|
||||
},
|
||||
Functions: map[string]interface{}{
|
||||
"DivisibleBy": divisibleBy,
|
||||
},
|
||||
})
|
||||
|
||||
pr, err := p.Parse("DivisibleBy(2) && DivisibleBy(3)")
|
||||
if err == nil {
|
||||
fmt.Fatalf("Error: %v", err)
|
||||
}
|
||||
pr.(numberPredicate)(2) // false
|
||||
pr.(numberPredicate)(3) // false
|
||||
pr.(numberPredicate)(6) // true
|
||||
*/
|
||||
package predicate
|
||||
|
||||
// Def contains supported operators (e.g. LT, GT) and functions passed in as a map.
|
||||
type Def struct {
|
||||
Operators Operators
|
||||
// Function matching is case sensitive, e.g. Len is different from len
|
||||
Functions map[string]interface{}
|
||||
// GetIdentifier returns value of any identifier passed in
|
||||
// in the form []string{"id", "field", "subfield"}
|
||||
GetIdentifier GetIdentifierFn
|
||||
// GetProperty returns property from a map
|
||||
GetProperty GetPropertyFn
|
||||
}
|
||||
|
||||
// GetIdentifierFn function returns identifier based on selector
|
||||
// e.g. id.field.subfield will be passed as.
|
||||
// GetIdentifierFn([]string{"id", "field", "subfield"})
|
||||
type GetIdentifierFn func(selector []string) (interface{}, error)
|
||||
|
||||
// GetPropertyFn reuturns property from a mapVal by key keyVal
|
||||
type GetPropertyFn func(mapVal, keyVal interface{}) (interface{}, error)
|
||||
|
||||
// Operators contain functions for equality and logical comparison.
|
||||
type Operators struct {
|
||||
EQ interface{}
|
||||
NEQ interface{}
|
||||
|
||||
LT interface{}
|
||||
GT interface{}
|
||||
|
||||
LE interface{}
|
||||
GE interface{}
|
||||
|
||||
OR interface{}
|
||||
AND interface{}
|
||||
}
|
||||
|
||||
// Parser takes the string with expression and calls the operators and functions.
|
||||
type Parser interface {
|
||||
Parse(string) (interface{}, error)
|
||||
}
|
Loading…
Reference in a new issue