Skip to content

Commit

Permalink
rego-v1: Future-proofing ast package tests to be 1.0 compatible (#…
Browse files Browse the repository at this point in the history
…6992)

Signed-off-by: Johan Fylling <[email protected]>
  • Loading branch information
johanfylling authored Sep 18, 2024
1 parent ceeefec commit 546eeac
Show file tree
Hide file tree
Showing 16 changed files with 1,713 additions and 1,364 deletions.
33 changes: 21 additions & 12 deletions ast/annotations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -415,27 +415,28 @@ package root2`,
note: "overlapping rule paths (same module)",
modules: map[string]string{
"mod": `package test
import rego.v1
# METADATA
# title: P1
p[v] {v = 1}
p contains v if {v = 1}
# METADATA
# title: P2
p[v] {v = 2}`,
p contains v if {v = 2}`,
},
expected: []AnnotationsRef{
{
Path: MustParseRef("data.test.p"),
Location: &Location{File: "mod", Row: 5},
Location: &Location{File: "mod", Row: 6},
Annotations: &Annotations{
Scope: "rule",
Title: "P1",
},
},
{
Path: MustParseRef("data.test.p"),
Location: &Location{File: "mod", Row: 9},
Location: &Location{File: "mod", Row: 10},
Annotations: &Annotations{
Scope: "rule",
Title: "P2",
Expand All @@ -447,26 +448,30 @@ p[v] {v = 2}`,
note: "overlapping rule paths (different modules)",
modules: map[string]string{
"mod1": `package test
import rego.v1
# METADATA
# title: P1
p[v] {v = 1}`,
p contains v if {v = 1}`,
"mod2": `package test
import rego.v1
# METADATA
# title: P2
p[v] {v = 2}`,
p contains v if {v = 2}`,
},
expected: []AnnotationsRef{
{
Path: MustParseRef("data.test.p"),
Location: &Location{File: "mod1", Row: 4},
Location: &Location{File: "mod1", Row: 6},
Annotations: &Annotations{
Scope: "rule",
Title: "P1",
},
},
{
Path: MustParseRef("data.test.p"),
Location: &Location{File: "mod2", Row: 4},
Location: &Location{File: "mod2", Row: 6},
Annotations: &Annotations{
Scope: "rule",
Title: "P2",
Expand All @@ -478,26 +483,30 @@ p[v] {v = 2}`,
note: "overlapping rule paths (different modules, rule head refs)",
modules: map[string]string{
"mod1": `package test.a
import rego.v1
# METADATA
# title: P1
b.c.p[v] {v = 1}`,
b.c.p[v] if {v = 1}`,
"mod2": `package test
import rego.v1
# METADATA
# title: P2
a.b.c.p[v] {v = 2}`,
a.b.c.p[v] if {v = 2}`,
},
expected: []AnnotationsRef{
{
Path: MustParseRef("data.test.a.b.c.p"),
Location: &Location{File: "mod1", Row: 4},
Location: &Location{File: "mod1", Row: 6},
Annotations: &Annotations{
Scope: "rule",
Title: "P1",
},
},
{
Path: MustParseRef("data.test.a.b.c.p"),
Location: &Location{File: "mod2", Row: 4},
Location: &Location{File: "mod2", Row: 6},
Annotations: &Annotations{
Scope: "rule",
Title: "P2",
Expand Down
6 changes: 5 additions & 1 deletion ast/capabilities_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,11 @@ func TestCapabilitiesMinimumCompatibleVersion(t *testing.T) {

for _, tc := range tests {
t.Run(tc.note, func(t *testing.T) {
c := MustCompileModules(map[string]string{"test.rego": tc.module})
c := MustCompileModulesWithOpts(map[string]string{"test.rego": tc.module}, CompileOpts{
ParserOptions: ParserOptions{
RegoVersion: RegoV0,
},
})
minVersion, found := c.Required.MinimumCompatibleVersion()
if !found || minVersion != tc.version {
t.Fatal("expected", tc.version, "but got", minVersion)
Expand Down
83 changes: 47 additions & 36 deletions ast/check_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1225,17 +1225,19 @@ func TestCheckRefErrInvalid(t *testing.T) {

func TestFunctionsTypeInference(t *testing.T) {
functions := []string{
`foo([a, b]) = y { split(a, b, y) }`,
`bar(x) = y { count(x, y) }`,
`baz([x, y]) = z { sprintf("%s%s", [x, y], z) }`,
`qux({"bar": x, "foo": y}) = {a: b} { upper(y, a); json.unmarshal(x, b) }`,
`corge(x) = y { qux({"bar": x, "foo": x}, a); baz([a["{5: true}"], "BUZ"], y) }`,
`foo([a, b]) = y if { split(a, b, y) }`,
`bar(x) = y if { count(x, y) }`,
`baz([x, y]) = z if { sprintf("%s%s", [x, y], z) }`,
`qux({"bar": x, "foo": y}) = {a: b} if { upper(y, a); json.unmarshal(x, b) }`,
`corge(x) = y if { qux({"bar": x, "foo": x}, a); baz([a["{5: true}"], "BUZ"], y) }`,
}
body := strings.Join(functions, "\n")
base := fmt.Sprintf("package base\n%s", body)

popts := ParserOptions{AllFutureKeywords: true}

c := NewCompiler()
if c.Compile(map[string]*Module{"base": MustParseModule(base)}); c.Failed() {
if c.Compile(map[string]*Module{"base": MustParseModuleWithOpts(base, popts)}); c.Failed() {
t.Fatalf("Failed to compile base module: %v", c.Errors)
}

Expand All @@ -1244,68 +1246,68 @@ func TestFunctionsTypeInference(t *testing.T) {
wantErr bool
}{
{
`fn(_) = y { data.base.foo(["hello", 5], y) }`,
`fn(_) = y if { data.base.foo(["hello", 5], y) }`,
true,
},
{
`fn(_) = y { data.base.foo(["hello", "ll"], y) }`,
`fn(_) = y if { data.base.foo(["hello", "ll"], y) }`,
false,
},
{
`fn(_) = y { data.base.baz(["hello", "ll"], y) }`,
`fn(_) = y if { data.base.baz(["hello", "ll"], y) }`,
false,
},
{
`fn(_) = y { data.base.baz([5, ["foo", "bar", true]], y) }`,
`fn(_) = y if { data.base.baz([5, ["foo", "bar", true]], y) }`,
false,
},
{
`fn(_) = y { data.base.baz(["hello", {"a": "b", "c": 3}], y) }`,
`fn(_) = y if { data.base.baz(["hello", {"a": "b", "c": 3}], y) }`,
false,
},
{
`fn(_) = y { data.base.corge("this is not json", y) }`,
`fn(_) = y if { data.base.corge("this is not json", y) }`,
false,
},
{
`fn(x) = y { data.non_existent(x, a); y = a[0] }`,
`fn(x) = y if { data.non_existent(x, a); y = a[0] }`,
true,
},
{
`fn(x) = y { y = [x] }`,
`fn(x) = y if { y = [x] }`,
false,
},
{
`f(x) = y { [x] = y }`,
`f(x) = y if { [x] = y }`,
false,
},
{
`fn(x) = y { y = {"k": x} }`,
`fn(x) = y if { y = {"k": x} }`,
false,
},
{
`f(x) = y { {"k": x} = y }`,
`f(x) = y if { {"k": x} = y }`,
false,
},
{
`p { [data.base.foo] }`,
`p if { [data.base.foo] }`,
true,
},
{
`p { x = data.base.foo }`,
`p if { x = data.base.foo }`,
true,
},
{
`p { data.base.foo(data.base.bar) }`,
`p if { data.base.foo(data.base.bar) }`,
true,
},
}

for n, test := range tests {
t.Run(fmt.Sprintf("Test Case %d", n), func(t *testing.T) {
mod := MustParseModule(fmt.Sprintf("package test\n%s", test.body))
mod := MustParseModuleWithOpts(fmt.Sprintf("package test\n%s", test.body), popts)
c := NewCompiler()
c.Compile(map[string]*Module{"base": MustParseModule(base), "mod": mod})
c.Compile(map[string]*Module{"base": MustParseModuleWithOpts(base, popts), "mod": mod})
if test.wantErr && !c.Failed() {
t.Errorf("Expected error but got success")
} else if !test.wantErr && c.Failed() {
Expand All @@ -1321,8 +1323,9 @@ func TestFunctionTypeInferenceUnappliedWithObjectVarKey(t *testing.T) {
// from args in the head.
module := MustParseModule(`
package test
import rego.v1
f(x) = y { y = {x: 1} }
f(x) := y if { y = {x: 1} }
`)

elems := []util.T{
Expand All @@ -1348,46 +1351,49 @@ func TestCheckValidErrors(t *testing.T) {

module := MustParseModule(`
package test
import rego.v1
p {
p if {
concat("", 1) # type error
}
q {
q if {
r(1)
}
r(x) = x`)

module2 := MustParseModule(`
package test
import rego.v1
b {
b if {
a(1) # call erroneous function
}
a(x) {
a(x) if {
max("foo") # max requires an array
}
m {
m if {
1 / "foo" # type error
}
n {
n if {
m # call erroneous rule
}`)

module3 := MustParseModule(`
package test
import rego.v1
x := {"a" : 1}
y {
y if {
z
}
z {
z if {
x[1] == 1 # undefined reference error
}`)

Expand Down Expand Up @@ -1506,11 +1512,12 @@ func TestCheckErrorOrdering(t *testing.T) {

mod := MustParseModule(`
package test
import rego.v1
q = true
p { data.test.q = 1 } # type error: bool = number
p { data.test.q = 2 } # type error: bool = number
p if { data.test.q = 1 } # type error: bool = number
p if { data.test.q = 2 } # type error: bool = number
`)

input := make([]util.T, len(mod.Rules))
Expand Down Expand Up @@ -2310,6 +2317,7 @@ p { input = "foo" }`}},
for i, module := range tc.modules {
mod, err := ParseModuleWithOpts(fmt.Sprintf("test%d.rego", i+1), module, ParserOptions{
ProcessAnnotation: true,
RegoVersion: RegoV0,
})
if err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -2360,12 +2368,13 @@ func TestCheckAnnotationInference(t *testing.T) {
modules: map[string]string{
"test.rego": `
package test
import rego.v1
# METADATA
# scope: rule
# schemas:
# - input: schema.foo
p = x { input = x }
p = x if { input = x }
q = p`,
},
Expand Down Expand Up @@ -2438,11 +2447,12 @@ func TestRemoteSchema(t *testing.T) {

policy := fmt.Sprintf(`
package test
import rego.v1
# METADATA
# schemas:
# - input: {$ref: "%s"}
p {
p if {
input == 42
}`, server.URL)

Expand Down Expand Up @@ -2486,11 +2496,12 @@ func TestRemoteSchemaHostNotAllowed(t *testing.T) {

policy := fmt.Sprintf(`
package test
import rego.v1
# METADATA
# schemas:
# - input: {$ref: "%s"}
p {
p if {
input == 42
}`, server.URL)

Expand Down
Loading

0 comments on commit 546eeac

Please sign in to comment.