github.com/stackb/rules_proto@v0.0.0-20240221195024-5428336c51f1/pkg/protoc/starlark_rule_test.go (about) 1 package protoc 2 3 import ( 4 "fmt" 5 "strings" 6 "testing" 7 8 "github.com/bazelbuild/bazel-gazelle/config" 9 "github.com/bazelbuild/bazel-gazelle/rule" 10 "github.com/google/go-cmp/cmp" 11 ) 12 13 func TestLoadStarlarkRule(t *testing.T) { 14 for name, tc := range map[string]struct { 15 code string 16 rc *LanguageRuleConfig 17 pc *ProtocConfiguration 18 wantErr error 19 wantPrinted string 20 want *rule.Rule 21 }{ 22 "degenerate": { 23 wantErr: fmt.Errorf(`test.star: rule "test" was never declared`), 24 }, 25 "wrong rule name": { 26 code: ` 27 protoc.Rule( 28 name = "not-test", 29 load_info = lambda: None, 30 kind_info = lambda: None, 31 provide_rule = lambda rctx, pctx: None, 32 ) 33 `, 34 wantErr: fmt.Errorf(`test.star: rule "test" was never declared`), 35 }, 36 "missing provide_rule attribute": { 37 code: ` 38 protoc.Rule( 39 load_info = lambda: None, 40 kind_info = lambda: None, 41 name = "test", 42 ) 43 `, 44 wantErr: fmt.Errorf(`test.star: eval: Rule: missing argument for provide_rule`), 45 }, 46 "provide_rule attribute not callable": { 47 code: ` 48 protoc.Rule( 49 name = "test", 50 load_info = lambda: None, 51 kind_info = lambda: None, 52 provide_rule = "not-callable", 53 ) 54 `, 55 wantErr: fmt.Errorf(`test.star: eval: Rule: for parameter "provide_rule": got string, want callable`), 56 }, 57 "simple": { 58 code: ` 59 def make_py_library_rule(self): 60 rule = gazelle.Rule( 61 name = "py_library", 62 kind = "py_library", 63 ) 64 return rule 65 66 def provide_rule(rctx, pctx): 67 print(rctx) 68 print("---") 69 print(pctx) 70 return struct( 71 name = rctx.name, 72 kind = "py_library", 73 rule = make_py_library_rule, 74 ) 75 76 protoc.Rule( 77 name = "test", 78 load_info = lambda: None, 79 kind_info = lambda: None, 80 provide_rule = provide_rule, 81 ) 82 `, 83 rc: &LanguageRuleConfig{ 84 Config: &config.Config{}, 85 Name: "test", 86 Options: map[string]bool{"grpc": true}, 87 }, 88 pc: &ProtocConfiguration{}, 89 wantPrinted: `LanguageRuleConfig(attrs = {}, config = Config(repo_name = "", repo_root = "", work_dir = ""), deps = [], enabled = False, implementation = "", name = "test", options = ["grpc"], visibility = [])` + 90 "\n---\n" + 91 `ProtocConfiguration(imports = [], language_config = LanguageConfig(enabled = False, name = "", plugins = {}, protoc = "", rules = {}), mappings = {}, outputs = [], package_config = PackageConfig(config = Config(repo_name = "", repo_root = "", work_dir = "")), plugins = [], prefix = "", proto_library = ProtoLibrary(base_name = "", deps = [], files = [], imports = [], name = "", srcs = [], strip_import_prefix = ""), rel = "")` + 92 "\n", 93 }, 94 "may-return-none": { 95 code: ` 96 def make_py_library_rule(self): 97 return None 98 99 def provide_rule(rctx, pctx): 100 print(rctx) 101 print("---") 102 print(pctx) 103 return struct( 104 name = rctx.name, 105 kind = "py_library", 106 rule = make_py_library_rule, 107 ) 108 109 protoc.Rule( 110 name = "test", 111 load_info = lambda: None, 112 kind_info = lambda: None, 113 provide_rule = provide_rule, 114 ) 115 `, 116 rc: &LanguageRuleConfig{ 117 Config: &config.Config{}, 118 Name: "test", 119 Options: map[string]bool{"grpc": true}, 120 }, 121 pc: &ProtocConfiguration{}, 122 wantErr: nil, 123 wantPrinted: `LanguageRuleConfig(attrs = {}, config = Config(repo_name = "", repo_root = "", work_dir = ""), deps = [], enabled = False, implementation = "", name = "test", options = ["grpc"], visibility = [])` + 124 "\n---\n" + 125 `ProtocConfiguration(imports = [], language_config = LanguageConfig(enabled = False, name = "", plugins = {}, protoc = "", rules = {}), mappings = {}, outputs = [], package_config = PackageConfig(config = Config(repo_name = "", repo_root = "", work_dir = "")), plugins = [], prefix = "", proto_library = ProtoLibrary(base_name = "", deps = [], files = [], imports = [], name = "", srcs = [], strip_import_prefix = ""), rel = "")` + 126 "\n", 127 }, 128 } { 129 t.Run(name, func(t *testing.T) { 130 var err error 131 var gotPrinted strings.Builder 132 var rule LanguageRule 133 rule, err = loadStarlarkLanguageRule("test", "test.star", strings.NewReader(tc.code), func(msg string) { 134 gotPrinted.WriteString(msg) 135 gotPrinted.Write([]byte{'\n'}) 136 }, func(loadErr error) { 137 err = loadErr 138 }) 139 if err != nil { 140 if tc.wantErr != nil { 141 if diff := cmp.Diff(tc.wantErr.Error(), err.Error()); diff != "" { 142 t.Fatalf("StarlarkRule.load error (-want +got):\n%s", diff) 143 } 144 return 145 } else { 146 t.Fatalf("StarlarkRule.load error: %v", err) 147 } 148 } 149 150 provider := rule.ProvideRule(tc.rc, tc.pc) 151 if err != nil { 152 if tc.wantErr != nil { 153 if diff := cmp.Diff(tc.wantErr.Error(), err.Error()); diff != "" { 154 t.Fatalf("StarlarkRule.ProvideRule error (-want +got):\n%s", diff) 155 } 156 return 157 } else { 158 t.Fatalf("StarlarkRule.ProvideRule error: %v", err) 159 } 160 } 161 if provider == nil { 162 t.Fatalf("StarlarkRule.ProvideRule returned nil") 163 } 164 165 t.Log(gotPrinted.String()) 166 if diff := cmp.Diff(tc.wantPrinted, gotPrinted.String()); diff != "" { 167 t.Errorf("StarlarkRule print (-want +got):\n%s", diff) 168 } 169 170 got := provider.Rule() 171 if diff := cmp.Diff(tc.want, got); diff != "" { 172 t.Errorf("StarlarkRule.ProvideRule (-want +got):\n%s", diff) 173 } 174 }) 175 } 176 }