@@ -16,6 +16,7 @@ import (
1616 "github.com/zclconf/go-cty/cty"
1717
1818 "github.com/coder/preview"
19+ "github.com/coder/preview/hclext"
1920 "github.com/coder/preview/types"
2021 "github.com/coder/terraform-provider-coder/v2/provider"
2122)
@@ -43,6 +44,7 @@ func Test_Extract(t *testing.T) {
4344 expTags map [string ]string
4445 unknownTags []string
4546 params map [string ]assertParam
47+ variables map [string ]assertVariable
4648 presets func (t * testing.T , presets []types.Preset )
4749 warnings []* regexp.Regexp
4850 }{
@@ -77,6 +79,18 @@ func Test_Extract(t *testing.T) {
7779 formType (provider .ParameterFormTypeRadio ),
7880 "numerical" : ap ().value ("5" ),
7981 },
82+ variables : map [string ]assertVariable {
83+ "string" : av ().def (cty .StringVal ("Hello, world!" )).typeEq (cty .String ).
84+ description ("test" ).nullable (true ).sensitive (true ),
85+ "number" : av ().def (cty .NumberIntVal (7 )).typeEq (cty .Number ),
86+ "boolean" : av ().def (cty .BoolVal (true )).typeEq (cty .Bool ),
87+ "coerce_string" : av ().def (cty .StringVal ("5" )).typeEq (cty .String ),
88+ "complex" : av ().typeEq (cty .Object (map [string ]cty.Type {
89+ "list" : cty .List (cty .String ),
90+ "name" : cty .String ,
91+ "age" : cty .Number ,
92+ })),
93+ },
8094 },
8195 {
8296 name : "conditional-no-inputs" ,
@@ -149,6 +163,11 @@ func Test_Extract(t *testing.T) {
149163 "indexed_0" : ap (),
150164 "indexed_1" : ap (),
151165 },
166+ variables : map [string ]assertVariable {
167+ "regions" : av ().def (cty .SetVal ([]cty.Value {
168+ cty .StringVal ("us" ), cty .StringVal ("eu" ), cty .StringVal ("au" ),
169+ })).typeEq (cty .Set (cty .String )),
170+ },
152171 },
153172 {
154173 name : "external docker resource without plan data" ,
@@ -222,6 +241,9 @@ func Test_Extract(t *testing.T) {
222241 def ("m7gd.8xlarge" ).
223242 value ("m7gd.8xlarge" ),
224243 },
244+ variables : map [string ]assertVariable {
245+ "regions" : av ().typeEq (cty .List (cty .String )),
246+ },
225247 },
226248 {
227249 name : "empty file" ,
@@ -434,6 +456,9 @@ func Test_Extract(t *testing.T) {
434456 "team" : ap ().optVals ("frontend" , "backend" , "fullstack" ),
435457 "jetbrains_ide" : ap (),
436458 },
459+ variables : map [string ]assertVariable {
460+ "security" : av ().def (cty .StringVal ("high" )).typeEq (cty .String ),
461+ },
437462 },
438463 {
439464 name : "count" ,
@@ -528,6 +553,17 @@ func Test_Extract(t *testing.T) {
528553 optVals ("GO" , "IU" , "PY" ).
529554 optNames ("GoLand 2024.3" , "IntelliJ IDEA Ultimate 2024.3" , "PyCharm Professional 2024.3" ),
530555 },
556+ variables : map [string ]assertVariable {
557+ "jetbrains_ides" : av ().typeEq (cty .List (cty .String )).description ("The list of IDE product codes." ),
558+ "releases_base_link" : av (),
559+ "channel" : av (),
560+ "download_base_link" : av (),
561+ "arch" : av (),
562+ "jetbrains_ide_versions" : av ().typeEq (cty .Map (cty .Object (map [string ]cty.Type {
563+ "build_number" : cty .String ,
564+ "version" : cty .String ,
565+ }))),
566+ },
531567 },
532568 {
533569 name : "tfvars_from_file" ,
@@ -541,6 +577,12 @@ func Test_Extract(t *testing.T) {
541577 "variable_values" : ap ().
542578 def ("alex" ).optVals ("alex" , "bob" , "claire" , "jason" ),
543579 },
580+ variables : map [string ]assertVariable {
581+ "one" : av (),
582+ "two" : av (),
583+ "three" : av (),
584+ "four" : av (),
585+ },
544586 },
545587 {
546588 name : "tfvars_from_input" ,
@@ -559,6 +601,12 @@ func Test_Extract(t *testing.T) {
559601 "variable_values" : ap ().
560602 def ("andrew" ).optVals ("andrew" , "bill" , "carter" , "jason" ),
561603 },
604+ variables : map [string ]assertVariable {
605+ "one" : av (),
606+ "two" : av (),
607+ "three" : av (),
608+ "four" : av (),
609+ },
562610 },
563611 {
564612 name : "unknownoption" ,
@@ -570,6 +618,9 @@ func Test_Extract(t *testing.T) {
570618 "unknown" : apWithDiags ().
571619 errorDiagnostics ("The set of options cannot be resolved" ),
572620 },
621+ variables : map [string ]assertVariable {
622+ "unknown" : av ().def (cty .NilVal ),
623+ },
573624 },
574625 } {
575626 t .Run (tc .name , func (t * testing.T ) {
@@ -637,10 +688,80 @@ func Test_Extract(t *testing.T) {
637688 if tc .presets != nil {
638689 tc .presets (t , output .Presets )
639690 }
691+
692+ // Assert variables
693+ require .Len (t , output .Variables , len (tc .variables ), "wrong number of variables expected" )
694+ for _ , variable := range output .Variables {
695+ check , ok := tc .variables [variable .Name ]
696+ require .True (t , ok , "unknown variable %s" , variable .Name )
697+ check (t , variable )
698+ }
640699 })
641700 }
642701}
643702
703+ type assertVariable func (t * testing.T , variable types.Variable )
704+
705+ func av () assertVariable {
706+ return func (t * testing.T , v types.Variable ) {
707+ t .Helper ()
708+ assert .Empty (t , v .Diagnostics , "variable should have no diagnostics" )
709+ }
710+ }
711+
712+ func avWithDiags () assertVariable {
713+ return func (t * testing.T , parameter types.Variable ) {}
714+ }
715+
716+ func (a assertVariable ) errorDiagnostics (patterns ... string ) assertVariable {
717+ return a .diagnostics (hcl .DiagError , patterns ... )
718+ }
719+
720+ func (a assertVariable ) warnDiagnostics (patterns ... string ) assertVariable {
721+ return a .diagnostics (hcl .DiagWarning , patterns ... )
722+ }
723+
724+ func (a assertVariable ) diagnostics (sev hcl.DiagnosticSeverity , patterns ... string ) assertVariable {
725+ shadow := patterns
726+ return a .extend (func (t * testing.T , v types.Variable ) {
727+ assertDiags (t , sev , v .Diagnostics , shadow ... )
728+ })
729+ }
730+
731+ func (a assertVariable ) nullable (n bool ) assertVariable {
732+ return a .extend (func (t * testing.T , v types.Variable ) {
733+ assert .Equal (t , v .Nullable , n , "variable nullable check" )
734+ })
735+ }
736+
737+ func (a assertVariable ) typeEq (ty cty.Type ) assertVariable {
738+ return a .extend (func (t * testing.T , v types.Variable ) {
739+ assert .Truef (t , ty .Equals (v .Type ), "%q variable type equality check" , v .Name )
740+ })
741+ }
742+
743+ func (a assertVariable ) def (def cty.Value ) assertVariable {
744+ return a .extend (func (t * testing.T , v types.Variable ) {
745+ if ! assert .Truef (t , def .Equals (v .Default ).True (), "%q variable default equality check" , v .Name ) {
746+ exp , _ := hclext .AsString (def )
747+ got , _ := hclext .AsString (v .Default )
748+ t .Logf ("Expected: %s, Value: %s" , exp , got )
749+ }
750+ })
751+ }
752+
753+ func (a assertVariable ) sensitive (s bool ) assertVariable {
754+ return a .extend (func (t * testing.T , v types.Variable ) {
755+ assert .Equal (t , v .Sensitive , s , "variable sensitive check" )
756+ })
757+ }
758+
759+ func (a assertVariable ) description (d string ) assertVariable {
760+ return a .extend (func (t * testing.T , v types.Variable ) {
761+ assert .Equal (t , v .Description , d , "variable description check" )
762+ })
763+ }
764+
644765type assertParam func (t * testing.T , parameter types.Parameter )
645766
646767func ap () assertParam {
@@ -665,23 +786,7 @@ func (a assertParam) warnDiagnostics(patterns ...string) assertParam {
665786func (a assertParam ) diagnostics (sev hcl.DiagnosticSeverity , patterns ... string ) assertParam {
666787 shadow := patterns
667788 return a .extend (func (t * testing.T , parameter types.Parameter ) {
668- checks := make ([]string , len (shadow ))
669- copy (checks , shadow )
670-
671- DiagLoop:
672- for _ , diag := range parameter .Diagnostics {
673- if diag .Severity != sev {
674- continue
675- }
676- for i , pat := range checks {
677- if strings .Contains (diag .Summary , pat ) || strings .Contains (diag .Detail , pat ) {
678- checks = append (checks [:i ], checks [i + 1 :]... )
679- break DiagLoop
680- }
681- }
682- }
683-
684- assert .Equal (t , []string {}, checks , "missing expected diagnostic errors" )
789+ assertDiags (t , sev , parameter .Diagnostics , shadow ... )
685790 })
686791}
687792
@@ -771,3 +876,37 @@ func (a assertParam) extend(f assertParam) assertParam {
771876 f (t , parameter )
772877 }
773878}
879+
880+ //nolint:revive
881+ func (a assertVariable ) extend (f assertVariable ) assertVariable {
882+ if a == nil {
883+ a = func (t * testing.T , v types.Variable ) {}
884+ }
885+
886+ return func (t * testing.T , v types.Variable ) {
887+ t .Helper ()
888+ (a )(t , v )
889+ f (t , v )
890+ }
891+ }
892+
893+ func assertDiags (t * testing.T , sev hcl.DiagnosticSeverity , diags types.Diagnostics , patterns ... string ) {
894+ t .Helper ()
895+ checks := make ([]string , len (patterns ))
896+ copy (checks , patterns )
897+
898+ DiagLoop:
899+ for _ , diag := range diags {
900+ if diag .Severity != sev {
901+ continue
902+ }
903+ for i , pat := range checks {
904+ if strings .Contains (diag .Summary , pat ) || strings .Contains (diag .Detail , pat ) {
905+ checks = append (checks [:i ], checks [i + 1 :]... )
906+ break DiagLoop
907+ }
908+ }
909+ }
910+
911+ assert .Equal (t , []string {}, checks , "missing expected diagnostic errors" )
912+ }
0 commit comments