Skip to content

Commit 4e9c4e0

Browse files
terraform: lang.Data fake for use in unit tests
Our real implementation of the lang.Data interface depends on just about everything else in the modules runtime to implement its behavior, and so it's not really appropriate to use in unit tests. This new implementation is considerably simpler, just returning values predefined in a set of fixed tables. This is appropriate for unit tests of features that perform expression evaluation as a side-effect of their work but that don't contribute their own values to the real evaluation data implementation.
1 parent 79479f5 commit 4e9c4e0

File tree

1 file changed

+100
-0
lines changed

1 file changed

+100
-0
lines changed

internal/terraform/evaluate_test.go

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package terraform
55

66
import (
7+
"fmt"
78
"testing"
89

910
"github.com/davecgh/go-spew/spew"
@@ -621,3 +622,102 @@ func evaluatorForModule(stateSync *states.SyncState, changesSync *plans.ChangesS
621622
NamedValues: namedvals.NewState(),
622623
}
623624
}
625+
626+
// fakeEvaluationData is an implementation of [lang.Data] that answers most
627+
// questions just by returning data directly from the maps stored inside it.
628+
type fakeEvaluationData struct {
629+
checkBlocks map[addrs.Check]cty.Value
630+
countAttrs map[addrs.CountAttr]cty.Value
631+
forEachAttrs map[addrs.ForEachAttr]cty.Value
632+
inputVariables map[addrs.InputVariable]cty.Value
633+
localValues map[addrs.LocalValue]cty.Value
634+
modules map[addrs.ModuleCall]cty.Value
635+
outputValues map[addrs.OutputValue]cty.Value
636+
pathAttrs map[addrs.PathAttr]cty.Value
637+
resources map[addrs.Resource]cty.Value
638+
runBlocks map[addrs.Run]cty.Value
639+
terraformAttrs map[addrs.TerraformAttr]cty.Value
640+
641+
// staticValidateRefs optionally implements [lang.Data.StaticValidateReferences],
642+
// but can be left as nil to just skip static validation altogether.
643+
staticValidateRefs func(refs []*addrs.Reference, self addrs.Referenceable, source addrs.Referenceable) tfdiags.Diagnostics
644+
}
645+
646+
var _ lang.Data = (*fakeEvaluationData)(nil)
647+
648+
func fakeEvaluationDataLookup[Addr interface {
649+
comparable
650+
addrs.Referenceable
651+
}](addr Addr, _ tfdiags.SourceRange, table map[Addr]cty.Value) (cty.Value, tfdiags.Diagnostics) {
652+
ret, ok := table[addr]
653+
if !ok {
654+
var diags tfdiags.Diagnostics
655+
diags = diags.Append(fmt.Errorf("fakeEvaluationData does not know about %s", addr))
656+
return cty.DynamicVal, diags
657+
}
658+
return ret, nil
659+
}
660+
661+
// GetCheckBlock implements lang.Data.
662+
func (d *fakeEvaluationData) GetCheckBlock(addr addrs.Check, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
663+
return fakeEvaluationDataLookup(addr, rng, d.checkBlocks)
664+
}
665+
666+
// GetCountAttr implements lang.Data.
667+
func (d *fakeEvaluationData) GetCountAttr(addr addrs.CountAttr, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
668+
return fakeEvaluationDataLookup(addr, rng, d.countAttrs)
669+
}
670+
671+
// GetForEachAttr implements lang.Data.
672+
func (d *fakeEvaluationData) GetForEachAttr(addr addrs.ForEachAttr, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
673+
return fakeEvaluationDataLookup(addr, rng, d.forEachAttrs)
674+
}
675+
676+
// GetInputVariable implements lang.Data.
677+
func (d *fakeEvaluationData) GetInputVariable(addr addrs.InputVariable, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
678+
return fakeEvaluationDataLookup(addr, rng, d.inputVariables)
679+
}
680+
681+
// GetLocalValue implements lang.Data.
682+
func (d *fakeEvaluationData) GetLocalValue(addr addrs.LocalValue, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
683+
return fakeEvaluationDataLookup(addr, rng, d.localValues)
684+
}
685+
686+
// GetModule implements lang.Data.
687+
func (d *fakeEvaluationData) GetModule(addr addrs.ModuleCall, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
688+
return fakeEvaluationDataLookup(addr, rng, d.modules)
689+
}
690+
691+
// GetOutput implements lang.Data.
692+
func (d *fakeEvaluationData) GetOutput(addr addrs.OutputValue, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
693+
return fakeEvaluationDataLookup(addr, rng, d.outputValues)
694+
}
695+
696+
// GetPathAttr implements lang.Data.
697+
func (d *fakeEvaluationData) GetPathAttr(addr addrs.PathAttr, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
698+
return fakeEvaluationDataLookup(addr, rng, d.pathAttrs)
699+
}
700+
701+
// GetResource implements lang.Data.
702+
func (d *fakeEvaluationData) GetResource(addr addrs.Resource, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
703+
return fakeEvaluationDataLookup(addr, rng, d.resources)
704+
}
705+
706+
// GetRunBlock implements lang.Data.
707+
func (d *fakeEvaluationData) GetRunBlock(addr addrs.Run, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
708+
return fakeEvaluationDataLookup(addr, rng, d.runBlocks)
709+
}
710+
711+
// GetTerraformAttr implements lang.Data.
712+
func (d *fakeEvaluationData) GetTerraformAttr(addr addrs.TerraformAttr, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
713+
return fakeEvaluationDataLookup(addr, rng, d.terraformAttrs)
714+
}
715+
716+
// StaticValidateReferences implements lang.Data.
717+
func (d *fakeEvaluationData) StaticValidateReferences(refs []*addrs.Reference, self addrs.Referenceable, source addrs.Referenceable) tfdiags.Diagnostics {
718+
if d.staticValidateRefs == nil {
719+
// By default we just skip static validation
720+
return nil
721+
}
722+
return d.staticValidateRefs(refs, self, source)
723+
}

0 commit comments

Comments
 (0)