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  }