testharness: allow describe blocks to be skiped with require(...)

When a require(...) call is present in a describe(...) body, it must
produce a successful result in order for the testers within that body
to be evaluated.
proto-test-harness
Martin Atkins 9 years ago
parent 2c261eca08
commit e41fb89966

@ -1,6 +1,7 @@
package testharness
import (
"github.com/hashicorp/hcl2/hcl"
"github.com/hashicorp/terraform/tfdiags"
lua "github.com/yuin/gopher-lua"
)
@ -83,6 +84,7 @@ func (t *describe) test(subject *Subject, cs CheckStream) {
return
}
Contexts:
for _, childContext := range childContexts {
L := childContext.lstate
var diags tfdiags.Diagnostics
@ -126,15 +128,38 @@ func (t *describe) test(subject *Subject, cs CheckStream) {
continue
}
if testersB.Skip {
// testersB.Skip is set if there's a call to require() in
// the body and the given condition didn't hold.
cs.Write(CheckItem{
Result: Skipped,
Caption: childContext.Name(),
Diags: diags,
})
continue
for _, requirement := range testersB.Requirements {
switch requirement.Result() {
case Skipped:
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Requirement created without assertion",
Detail: "An assertion method must be called on the result of each \"require\" call.",
Subject: requirement.defRange.ToHCL().Ptr(),
})
cs.Write(CheckItem{
Result: Error,
Caption: childContext.Name(),
Diags: diags,
})
continue Contexts
case Error:
diags = diags.Append(requirement.diags)
cs.Write(CheckItem{
Result: Error,
Caption: childContext.Name(),
Diags: diags,
})
continue Contexts
case Failure:
// TODO: Do something with the detail message from the requirement, if any.
cs.Write(CheckItem{
Result: Skipped,
Caption: childContext.Name(),
Diags: diags,
})
continue Contexts
}
}
for _, tester := range testersB.Testers {

@ -16,13 +16,15 @@ type testersBuilder struct {
Context *Context
Testers Testers
Diags *Diagnostics
Skip bool
Requirements []*expect
}
func (b *testersBuilder) luaTesterDecls(L *lua.LState) map[lua.LString]lua.LValue {
return map[lua.LString]lua.LValue{
"describe": L.NewFunction(b.luaDescribeFunc),
"it": L.NewFunction(b.luaItFunc),
"require": L.NewFunction(b.luaRequireFunc),
}
}
@ -124,6 +126,38 @@ func (b *testersBuilder) luaItFunc(L *lua.LState) int {
return 0
}
func (b *testersBuilder) luaRequireFunc(L *lua.LState) int {
defRangeHCL := callingRange(L, 1)
var defRange tfdiags.SourceRange
if defRangeHCL != nil {
defRange = tfdiags.SourceRangeFromHCL(*defRangeHCL)
}
if L.GetTop() != 1 {
b.Diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid \"require\" call",
Detail: "A \"require\" call must have one argument: the given value to make an assertion about.",
Subject: defRangeHCL,
})
// We'll still return a requirement object just so the subsequent
// method call doesn't _also_ fail here. It'll never actually
// be evaluated (since it's not in the requirements list) so doesn't
// really matter what value we set it to.
stubRequirement := newExpect(b.Context.lstate, lua.LNil, defRange)
L.Push(stubRequirement.LuaObject())
return 1
}
given := L.CheckAny(1)
requirement := newExpect(b.Context.lstate, given, defRange)
b.Requirements = append(b.Requirements, requirement)
L.Push(requirement.LuaObject())
return 1
}
func (b *testersBuilder) luaContextSetters(L *lua.LState) map[lua.LString]lua.LValue {
return map[lua.LString]lua.LValue{
"resource": b.luaResourceObj(L),

Loading…
Cancel
Save