blob: aa6a6a873e782d579c08a11baf4507ca1c95d2ce [file] [log] [blame]
// Copyright 2022 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.devtools.build.lib.rules.proto;
import static com.google.common.truth.Truth.assertThat;
import static com.google.devtools.build.lib.actions.util.ActionsTestUtil.prettyArtifactNames;
import static com.google.devtools.build.lib.skyframe.BzlLoadValue.keyForBuild;
import com.google.common.truth.Correspondence;
import com.google.devtools.build.lib.actions.ResourceSet;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.FileProvider;
import com.google.devtools.build.lib.analysis.actions.SpawnAction;
import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.packages.StarlarkInfo;
import com.google.devtools.build.lib.packages.StarlarkProvider;
import com.google.devtools.build.lib.packages.StarlarkProviderIdentifier;
import com.google.devtools.build.lib.packages.util.MockProtoSupport;
import com.google.devtools.build.lib.testutil.TestConstants;
import com.google.devtools.build.lib.util.OS;
import com.google.testing.junit.testparameterinjector.TestParameterInjector;
import com.google.testing.junit.testparameterinjector.TestParameters;
import java.util.List;
import java.util.regex.Pattern;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
/** Unit test for proto_common module. */
@RunWith(TestParameterInjector.class)
public class BazelProtoCommonTest extends BuildViewTestCase {
private static final Correspondence<String, String> MATCHES_REGEX =
Correspondence.from((a, b) -> Pattern.matches(b, a), "matches");
private static final StarlarkProviderIdentifier boolProviderId =
StarlarkProviderIdentifier.forKey(
new StarlarkProvider.Key(
keyForBuild(Label.parseCanonicalUnchecked("//foo:should_generate.bzl")),
"BoolProvider"));
@Before
public final void setup() throws Exception {
MockProtoSupport.setup(mockToolsConfig);
invalidatePackages();
scratch.file(
"third_party/x/BUILD",
"""
licenses(['unencumbered'])
cc_binary(name = 'plugin', srcs = ['plugin.cc'])
cc_library(name = 'runtime', srcs = ['runtime.cc'])
filegroup(name = 'descriptors', srcs = ['metadata.proto', 'descriptor.proto'])
filegroup(name = 'any', srcs = ['any.proto'])
filegroup(name = 'something', srcs = ['something.proto'])
proto_library(name = 'mixed', srcs = [':descriptors', ':something'])
proto_library(name = 'denied', srcs = [':descriptors', ':any'])
""");
scratch.file(
"foo/BUILD",
TestConstants.LOAD_PROTO_LANG_TOOLCHAIN,
"proto_lang_toolchain(",
" name = 'toolchain',",
" command_line = '--java_out=param1,param2:$(OUT)',",
" plugin_format_flag = '--plugin=%s',",
" plugin = '//third_party/x:plugin',",
" runtime = '//third_party/x:runtime',",
" blacklisted_protos = ['//third_party/x:denied'],",
" progress_message = 'Progress Message %{label}',",
" mnemonic = 'MyMnemonic',",
" allowlist_different_package ="
+ " '//tools/allowlists/proto_library_allowlists:lang_proto_library_allowed_in_different_package'",
")",
"proto_lang_toolchain(",
" name = 'toolchain_noplugin',",
" command_line = '--java_out=param1,param2:$(OUT)',",
" runtime = '//third_party/x:runtime',",
" blacklisted_protos = ['//third_party/x:denied'],",
" progress_message = 'Progress Message %{label}',",
" mnemonic = 'MyMnemonic',",
")");
mockToolsConfig.overwrite(
"tools/allowlists/proto_library_allowlists/BUILD",
"""
package_group(
name='lang_proto_library_allowed_in_different_package',
packages=['//...', '-//test/...'],
)
""");
scratch.file(
"foo/generate.bzl",
"""
def _resource_set_callback(os, inputs_size):
return {'memory': 25 + 0.15 * inputs_size, 'cpu': 1}
def _impl(ctx):
outfile = ctx.actions.declare_file('out')
kwargs = {}
if ctx.attr.plugin_output == 'single':
kwargs['plugin_output'] = outfile.path
elif ctx.attr.plugin_output == 'multiple':
kwargs['plugin_output'] = ctx.genfiles_dir.path
elif ctx.attr.plugin_output == 'wrong':
kwargs['plugin_output'] = ctx.genfiles_dir.path + '///'
if ctx.attr.additional_args:
additional_args = ctx.actions.args()
additional_args.add_all(ctx.attr.additional_args)
kwargs['additional_args'] = additional_args
if ctx.files.additional_tools:
kwargs['additional_tools'] = ctx.files.additional_tools
if ctx.files.additional_inputs:
kwargs['additional_inputs'] = depset(ctx.files.additional_inputs)
if ctx.attr.use_resource_set:
kwargs['resource_set'] = _resource_set_callback
if ctx.attr.progress_message:
kwargs['experimental_progress_message'] = ctx.attr.progress_message
proto_common_do_not_use.compile(
ctx.actions,
ctx.attr.proto_dep[ProtoInfo],
ctx.attr.toolchain[proto_common_do_not_use.ProtoLangToolchainInfo],
[outfile],
**kwargs)
return [DefaultInfo(files = depset([outfile]))]
generate_rule = rule(_impl,
attrs = {
'proto_dep': attr.label(),
'plugin_output': attr.string(),
'toolchain': attr.label(default = '//foo:toolchain'),
'additional_args': attr.string_list(),
'additional_tools': attr.label_list(cfg = 'exec'),
'additional_inputs': attr.label_list(allow_files = True),
'use_resource_set': attr.bool(),
'progress_message': attr.string(),
})
""");
scratch.file(
"foo/should_generate.bzl",
"""
BoolProvider = provider()
def _impl(ctx):
result = proto_common_do_not_use.experimental_should_generate_code(
ctx.attr.proto_dep[ProtoInfo],
ctx.attr.toolchain[proto_common_do_not_use.ProtoLangToolchainInfo],
'MyRule',
ctx.attr.proto_dep.label)
return [BoolProvider(value = result)]
should_generate_rule = rule(_impl,
attrs = {
'proto_dep': attr.label(),
'toolchain': attr.label(default = '//foo:toolchain'),
})
""");
scratch.file(
"foo/declare_generated_files.bzl",
"""
def _impl(ctx):
files = proto_common_do_not_use.declare_generated_files(
ctx.actions,
ctx.attr.proto_dep[ProtoInfo],
ctx.attr.extension,
(lambda s: s.replace('-','_').replace('.','/')) if ctx.attr.python_names else None)
for f in files:
ctx.actions.write(f, '')
return [DefaultInfo(files = depset(files))]
declare_generated_files = rule(_impl,
attrs = {
'proto_dep': attr.label(),
'extension': attr.string(),
'python_names': attr.bool(default = False),
})
""");
scratch.file(
"foo/check_collocated.bzl",
"""
def _impl(ctx):
proto_common_do_not_use.check_collocated(
ctx.label,
ctx.attr.proto_dep[ProtoInfo],
ctx.attr.toolchain[proto_common_do_not_use.ProtoLangToolchainInfo])
return None
check_collocated = rule(_impl,
attrs = {
'proto_dep': attr.label(),
'toolchain': attr.label(default = '//foo:toolchain'),
})
""");
}
/** Verifies basic usage of <code>proto_common.generate_code</code>. */
@Test
public void generateCode_basic() throws Exception {
scratch.file(
"bar/BUILD",
TestConstants.LOAD_PROTO_LIBRARY,
"load('//foo:generate.bzl', 'generate_rule')",
"proto_library(name = 'proto', srcs = ['A.proto'])",
"generate_rule(name = 'simple', proto_dep = ':proto')");
ConfiguredTarget target = getConfiguredTarget("//bar:simple");
SpawnAction spawnAction = getGeneratingSpawnAction(getBinArtifact("out", target));
List<String> cmdLine = spawnAction.getRemainingArguments();
assertThat(cmdLine)
.comparingElementsUsing(MATCHES_REGEX)
.containsExactly(
"--plugin=bl?azel?-out/[^/]*-exec-[^/]*/bin/third_party/x/plugin", "-I.", "bar/A.proto")
.inOrder();
assertThat(spawnAction.getMnemonic()).isEqualTo("MyMnemonic");
assertThat(spawnAction.getProgressMessage()).isEqualTo("Progress Message //bar:simple");
}
/** Verifies usage of proto_common.generate_code with no plugin specified by toolchain. */
@Test
public void generateCode_noPlugin() throws Exception {
scratch.file(
"bar/BUILD",
TestConstants.LOAD_PROTO_LIBRARY,
"load('//foo:generate.bzl', 'generate_rule')",
"proto_library(name = 'proto', srcs = ['A.proto'])",
"generate_rule(name = 'simple', proto_dep = ':proto',",
" toolchain = '//foo:toolchain_noplugin')");
ConfiguredTarget target = getConfiguredTarget("//bar:simple");
List<String> cmdLine =
getGeneratingSpawnAction(getBinArtifact("out", target)).getRemainingArguments();
assertThat(cmdLine)
.comparingElementsUsing(MATCHES_REGEX)
.containsExactly("-I.", "bar/A.proto")
.inOrder();
}
/**
* Verifies usage of <code>proto_common.generate_code</code> with <code>plugin_output</code>
* parameter set to file.
*/
@Test
public void generateCode_withPluginOutput() throws Exception {
scratch.file(
"bar/BUILD",
TestConstants.LOAD_PROTO_LIBRARY,
"load('//foo:generate.bzl', 'generate_rule')",
"proto_library(name = 'proto', srcs = ['A.proto'])",
"generate_rule(name = 'simple', proto_dep = ':proto', plugin_output = 'single')");
useConfiguration(
"--platforms=" + TestConstants.PLATFORM_LABEL,
"--experimental_platform_in_output_dir",
String.format(
"--experimental_override_name_platform_in_output_dir=%s=k8",
TestConstants.PLATFORM_LABEL));
ConfiguredTarget target = getConfiguredTarget("//bar:simple");
List<String> cmdLine =
getGeneratingSpawnAction(getBinArtifact("out", target)).getRemainingArguments();
assertThat(cmdLine)
.comparingElementsUsing(MATCHES_REGEX)
.containsExactly(
"--java_out=param1,param2:bl?azel?-out/k8-fastbuild/bin/bar/out",
"--plugin=bl?azel?-out/[^/]*-exec/bin/third_party/x/plugin",
"-I.",
"bar/A.proto")
.inOrder();
}
/**
* Verifies usage of <code>proto_common.generate_code</code> with <code>plugin_output</code>
* parameter set to directory.
*/
@Test
public void generateCode_withDirectoryPluginOutput() throws Exception {
scratch.file(
"bar/BUILD",
TestConstants.LOAD_PROTO_LIBRARY,
"load('//foo:generate.bzl', 'generate_rule')",
"proto_library(name = 'proto', srcs = ['A.proto'])",
"generate_rule(name = 'simple', proto_dep = ':proto', plugin_output = 'multiple')");
useConfiguration(
"--platforms=" + TestConstants.PLATFORM_LABEL,
"--experimental_platform_in_output_dir",
String.format(
"--experimental_override_name_platform_in_output_dir=%s=k8",
TestConstants.PLATFORM_LABEL));
ConfiguredTarget target = getConfiguredTarget("//bar:simple");
List<String> cmdLine =
getGeneratingSpawnAction(getBinArtifact("out", target)).getRemainingArguments();
assertThat(cmdLine)
.comparingElementsUsing(MATCHES_REGEX)
.containsExactly(
"--java_out=param1,param2:bl?azel?-out/k8-fastbuild/bin",
"--plugin=bl?azel?-out/[^/]*-exec/bin/third_party/x/plugin",
"-I.",
"bar/A.proto")
.inOrder();
}
/**
* Verifies usage of <code>proto_common.generate_code</code> with <code>additional_args</code>
* parameter.
*/
@Test
public void generateCode_additionalArgs() throws Exception {
scratch.file(
"bar/BUILD",
TestConstants.LOAD_PROTO_LIBRARY,
"load('//foo:generate.bzl', 'generate_rule')",
"proto_library(name = 'proto', srcs = ['A.proto'])",
"generate_rule(name = 'simple', proto_dep = ':proto', additional_args = ['--a', '--b'])");
ConfiguredTarget target = getConfiguredTarget("//bar:simple");
List<String> cmdLine =
getGeneratingSpawnAction(getBinArtifact("out", target)).getRemainingArguments();
assertThat(cmdLine)
.comparingElementsUsing(MATCHES_REGEX)
.containsExactly(
"--a",
"--b",
"--plugin=bl?azel?-out/[^/]*-exec-[^/]*/bin/third_party/x/plugin",
"-I.",
"bar/A.proto")
.inOrder();
}
/**
* Verifies usage of <code>proto_common.generate_code</code> with <code>additional_tools</code>
* parameter.
*/
@Test
public void generateCode_additionalTools() throws Exception {
scratch.file(
"bar/BUILD",
TestConstants.LOAD_PROTO_LIBRARY,
"load('//foo:generate.bzl', 'generate_rule')",
"proto_library(name = 'proto', srcs = ['A.proto'])",
"cc_binary(name = 'tool1', srcs = ['tool1.cc'])",
"cc_binary(name = 'tool2', srcs = ['tool2.cc'])",
"generate_rule(name = 'simple', proto_dep = ':proto',",
" additional_tools = [':tool1', ':tool2'])");
ConfiguredTarget target = getConfiguredTarget("//bar:simple");
SpawnAction spawnAction = getGeneratingSpawnAction(getBinArtifact("out", target));
assertThat(prettyArtifactNames(spawnAction.getTools()))
.containsAtLeast("bar/tool1", "bar/tool2", "third_party/x/plugin");
}
/**
* Verifies usage of <code>proto_common.generate_code</code> with <code>additional_tools</code>
* parameter and no plugin on the toolchain.
*/
@Test
public void generateCode_additionalToolsNoPlugin() throws Exception {
scratch.file(
"bar/BUILD",
TestConstants.LOAD_PROTO_LIBRARY,
"load('//foo:generate.bzl', 'generate_rule')",
"proto_library(name = 'proto', srcs = ['A.proto'])",
"cc_binary(name = 'tool1', srcs = ['tool1.cc'])",
"cc_binary(name = 'tool2', srcs = ['tool2.cc'])",
"generate_rule(name = 'simple',",
" proto_dep = ':proto',",
" additional_tools = [':tool1', ':tool2'],",
" toolchain = '//foo:toolchain_noplugin',",
")");
ConfiguredTarget target = getConfiguredTarget("//bar:simple");
SpawnAction spawnAction = getGeneratingSpawnAction(getBinArtifact("out", target));
assertThat(prettyArtifactNames(spawnAction.getTools()))
.containsAtLeast("bar/tool1", "bar/tool2");
}
/**
* Verifies usage of <code>proto_common.generate_code</code> with <code>additional_inputs</code>
* parameter.
*/
@Test
public void generateCode_additionalInputs() throws Exception {
scratch.file(
"bar/BUILD",
TestConstants.LOAD_PROTO_LIBRARY,
"load('//foo:generate.bzl', 'generate_rule')",
"proto_library(name = 'proto', srcs = ['A.proto'])",
"generate_rule(name = 'simple', proto_dep = ':proto',",
" additional_inputs = [':input1.txt', ':input2.txt'])");
ConfiguredTarget target = getConfiguredTarget("//bar:simple");
SpawnAction spawnAction = getGeneratingSpawnAction(getBinArtifact("out", target));
assertThat(prettyArtifactNames(spawnAction.getInputs()))
.containsAtLeast("bar/input1.txt", "bar/input2.txt");
}
/**
* Verifies usage of <code>proto_common.generate_code</code> with <code>resource_set</code>
* parameter.
*/
@Test
public void generateCode_resourceSet() throws Exception {
scratch.file(
"bar/BUILD",
TestConstants.LOAD_PROTO_LIBRARY,
"load('//foo:generate.bzl', 'generate_rule')",
"proto_library(name = 'proto', srcs = ['A.proto'])",
"generate_rule(name = 'simple', proto_dep = ':proto', use_resource_set = True)");
ConfiguredTarget target = getConfiguredTarget("//bar:simple");
SpawnAction spawnAction = getGeneratingSpawnAction(getBinArtifact("out", target));
assertThat(spawnAction.getResourceSetOrBuilder().buildResourceSet(OS.DARWIN, 0))
.isEqualTo(ResourceSet.createWithRamCpu(25, 1));
assertThat(spawnAction.getResourceSetOrBuilder().buildResourceSet(OS.LINUX, 2))
.isEqualTo(ResourceSet.createWithRamCpu(25.3, 1));
}
/** Verifies <code>--protocopts</code> are passed to command line. */
@Test
public void generateCode_protocOpts() throws Exception {
useConfiguration("--protocopt=--foo", "--protocopt=--bar");
scratch.file(
"bar/BUILD",
TestConstants.LOAD_PROTO_LIBRARY,
"load('//foo:generate.bzl', 'generate_rule')",
"proto_library(name = 'proto', srcs = ['A.proto'])",
"generate_rule(name = 'simple', proto_dep = ':proto')");
ConfiguredTarget target = getConfiguredTarget("//bar:simple");
SpawnAction spawnAction = getGeneratingSpawnAction(getBinArtifact("out", target));
List<String> cmdLine = spawnAction.getRemainingArguments();
assertThat(cmdLine)
.comparingElementsUsing(MATCHES_REGEX)
.containsExactly(
"--plugin=bl?azel?-out/[^/]*-exec-[^/]*/bin/third_party/x/plugin",
"-I.",
"--foo",
"--bar",
"bar/A.proto")
.inOrder();
}
/**
* Verifies <code>proto_common.generate_code</code> correctly handles direct generated <code>
* .proto</code> files.
*/
@Test
public void generateCode_directGeneratedProtos() throws Exception {
scratch.file(
"bar/BUILD",
TestConstants.LOAD_PROTO_LIBRARY,
"load('//foo:generate.bzl', 'generate_rule')",
"genrule(name = 'generate', srcs = ['A.txt'], cmd = '', outs = ['G.proto'])",
"proto_library(name = 'proto', srcs = ['A.proto', 'G.proto'])",
"generate_rule(name = 'simple', proto_dep = ':proto')");
useConfiguration(
"--platforms=" + TestConstants.PLATFORM_LABEL,
"--experimental_platform_in_output_dir",
String.format(
"--experimental_override_name_platform_in_output_dir=%s=k8",
TestConstants.PLATFORM_LABEL));
ConfiguredTarget target = getConfiguredTarget("//bar:simple");
SpawnAction spawnAction = getGeneratingSpawnAction(getBinArtifact("out", target));
List<String> cmdLine = spawnAction.getRemainingArguments();
assertThat(cmdLine)
.comparingElementsUsing(MATCHES_REGEX)
.containsExactly(
"--plugin=bl?azel?-out/[^/]*-exec/bin/third_party/x/plugin",
"-Ibl?azel?-out/k8-fastbuild/bin",
"-I.",
"bar/A.proto",
"bl?azel?-out/k8-fastbuild/bin/bar/G.proto")
.inOrder();
}
/**
* Verifies <code>proto_common.generate_code</code> correctly handles in-direct generated <code>
* .proto</code> files.
*/
@Test
public void generateCode_inDirectGeneratedProtos() throws Exception {
scratch.file(
"bar/BUILD",
TestConstants.LOAD_PROTO_LIBRARY,
"load('//foo:generate.bzl', 'generate_rule')",
"genrule(name = 'generate', srcs = ['A.txt'], cmd = '', outs = ['G.proto'])",
"proto_library(name = 'generated', srcs = ['G.proto'])",
"proto_library(name = 'proto', srcs = ['A.proto'], deps = [':generated'])",
"generate_rule(name = 'simple', proto_dep = ':proto')");
useConfiguration(
"--platforms=" + TestConstants.PLATFORM_LABEL,
"--experimental_platform_in_output_dir",
String.format(
"--experimental_override_name_platform_in_output_dir=%s=k8",
TestConstants.PLATFORM_LABEL));
ConfiguredTarget target = getConfiguredTarget("//bar:simple");
SpawnAction spawnAction = getGeneratingSpawnAction(getBinArtifact("out", target));
List<String> cmdLine = spawnAction.getRemainingArguments();
assertThat(cmdLine)
.comparingElementsUsing(MATCHES_REGEX)
.containsExactly(
"--plugin=bl?azel?-out/[^/]*-exec/bin/third_party/x/plugin",
"-Ibl?azel?-out/k8-fastbuild/bin",
"-I.",
"bar/A.proto")
.inOrder();
}
/**
* Verifies <code>proto_common.generate_code</code> correctly handles external <code>proto_library
* </code>-es.
*/
@Test
@TestParameters({
"{sibling: false, generated: false, expectedFlags:" + " ['-Iexternal/foo']}",
"{sibling: false, generated: true, expectedFlags:"
+ " ['-Ibl?azel?-out/k8-fastbuild/bin/external/foo']}",
"{sibling: true, generated: false,expectedFlags:" + " ['-I../foo']}",
"{sibling: true, generated: true, expectedFlags:" + " ['-Ibl?azel?-out/foo/k8-fastbuild/bin']}",
})
public void generateCode_externalProtoLibrary(
boolean sibling, boolean generated, List<String> expectedFlags) throws Exception {
if (sibling) {
setBuildLanguageOptions("--experimental_sibling_repository_layout");
}
scratch.appendFile("WORKSPACE", "local_repository(name = 'foo', path = '/foo')");
invalidatePackages();
scratch.file("/foo/WORKSPACE");
scratch.file(
"/foo/e/BUILD",
TestConstants.LOAD_PROTO_LIBRARY,
"proto_library(name='e', srcs=['E.proto'])",
generated
? "genrule(name = 'generate', srcs = ['A.txt'], cmd = '', outs = ['E.proto'])"
: "");
scratch.file(
"bar/BUILD",
TestConstants.LOAD_PROTO_LIBRARY,
"load('//foo:generate.bzl', 'generate_rule')",
"proto_library(name = 'proto', srcs = ['A.proto'], deps = ['@foo//e:e'])",
"generate_rule(name = 'simple', proto_dep = ':proto')");
useConfiguration(
"--platforms=" + TestConstants.PLATFORM_LABEL,
"--experimental_platform_in_output_dir",
String.format(
"--experimental_override_name_platform_in_output_dir=%s=k8",
TestConstants.PLATFORM_LABEL));
ConfiguredTarget target = getConfiguredTarget("//bar:simple");
SpawnAction spawnAction = getGeneratingSpawnAction(getBinArtifact("out", target));
List<String> cmdLine = spawnAction.getRemainingArguments();
assertThat(cmdLine)
.comparingElementsUsing(MATCHES_REGEX)
.containsExactly(
"--plugin=bl?azel?-out/[^/]*-exec/bin/third_party/x/plugin",
expectedFlags.get(0),
"-I.",
"bar/A.proto")
.inOrder();
}
/** Verifies <code>experimental_progress_message</code> parameters. */
@Test
public void generateCode_overrideProgressMessage() throws Exception {
scratch.file(
"bar/BUILD",
TestConstants.LOAD_PROTO_LIBRARY,
"load('//foo:generate.bzl', 'generate_rule')",
"proto_library(name = 'proto', srcs = ['A.proto'])",
"generate_rule(name = 'simple', proto_dep = ':proto', progress_message = 'My %{label}')");
ConfiguredTarget target = getConfiguredTarget("//bar:simple");
SpawnAction spawnAction = getGeneratingSpawnAction(getBinArtifact("out", target));
List<String> cmdLine = spawnAction.getRemainingArguments();
assertThat(cmdLine)
.comparingElementsUsing(MATCHES_REGEX)
.containsExactly(
"--plugin=bl?azel?-out/[^/]*-exec-[^/]*/bin/third_party/x/plugin", "-I.", "bar/A.proto")
.inOrder();
assertThat(spawnAction.getMnemonic()).isEqualTo("MyMnemonic");
assertThat(spawnAction.getProgressMessage()).isEqualTo("My //bar:simple");
}
/** Verifies <code>proto_common.should_generate_code</code> call. */
@Test
public void shouldGenerateCode_basic() throws Exception {
scratch.file(
"bar/BUILD",
TestConstants.LOAD_PROTO_LIBRARY,
"load('//foo:should_generate.bzl', 'should_generate_rule')",
"proto_library(name = 'proto', srcs = ['A.proto'])",
"should_generate_rule(name = 'simple', proto_dep = ':proto')");
ConfiguredTarget target = getConfiguredTarget("//bar:simple");
StarlarkInfo boolProvider = (StarlarkInfo) target.get(boolProviderId);
assertThat(boolProvider.getValue("value", Boolean.class)).isTrue();
}
/** Verifies <code>proto_common.should_generate_code</code> call. */
@Test
public void shouldGenerateCode_dontGenerate() throws Exception {
scratch.file(
"bar/BUILD",
TestConstants.LOAD_PROTO_LIBRARY,
"load('//foo:should_generate.bzl', 'should_generate_rule')",
"should_generate_rule(name = 'simple', proto_dep = '//third_party/x:denied')");
ConfiguredTarget target = getConfiguredTarget("//bar:simple");
StarlarkInfo boolProvider = (StarlarkInfo) target.get(boolProviderId);
assertThat(boolProvider.getValue("value", Boolean.class)).isFalse();
}
/** Verifies <code>proto_common.should_generate_code</code> call. */
@Test
public void shouldGenerateCode_mixed() throws Exception {
scratch.file(
"bar/BUILD",
TestConstants.LOAD_PROTO_LIBRARY,
"load('//foo:should_generate.bzl', 'should_generate_rule')",
"should_generate_rule(name = 'simple', proto_dep = '//third_party/x:mixed')");
reporter.removeHandler(failFastHandler);
getConfiguredTarget("//bar:simple");
assertContainsEvent(
"The 'srcs' attribute of '@@//third_party/x:mixed' contains protos for which 'MyRule'"
+ " shouldn't generate code (third_party/x/metadata.proto,"
+ " third_party/x/descriptor.proto), in addition to protos for which it should"
+ " (third_party/x/something.proto).\n"
+ "Separate '@@//third_party/x:mixed' into 2 proto_library rules.");
}
/** Verifies <code>proto_common.declare_generated_files</code> call. */
@Test
public void declareGenerateFiles_basic() throws Exception {
scratch.file(
"bar/BUILD",
TestConstants.LOAD_PROTO_LIBRARY,
"load('//foo:declare_generated_files.bzl', 'declare_generated_files')",
"proto_library(name = 'proto', srcs = ['A.proto', 'b/B.proto'])",
"declare_generated_files(name = 'simple', proto_dep = ':proto', extension = '.cc')");
ConfiguredTarget target = getConfiguredTarget("//bar:simple");
assertThat(prettyArtifactNames(target.getProvider(FileProvider.class).getFilesToBuild()))
.containsExactly("bar/A.cc", "bar/b/B.cc");
}
/** Verifies <code>proto_common.declare_generated_files</code> call for Python. */
@Test
public void declareGenerateFiles_pythonc() throws Exception {
scratch.file(
"bar/BUILD",
TestConstants.LOAD_PROTO_LIBRARY,
"load('//foo:declare_generated_files.bzl', 'declare_generated_files')",
"proto_library(name = 'proto', srcs = ['my-proto.gen.proto'])",
"declare_generated_files(name = 'simple', proto_dep = ':proto', extension = '_pb2.py',",
" python_names = True)");
ConfiguredTarget target = getConfiguredTarget("//bar:simple");
assertThat(prettyArtifactNames(target.getProvider(FileProvider.class).getFilesToBuild()))
.containsExactly("bar/my_proto/gen_pb2.py");
}
@Test
public void langProtoLibrary_inDifferentPackage_allowed() throws Exception {
scratch.file(
"proto/BUILD",
TestConstants.LOAD_PROTO_LIBRARY,
"proto_library(name = 'proto', srcs = ['A.proto'])");
scratch.file(
"bar/BUILD",
"""
load('//foo:check_collocated.bzl', 'check_collocated')
check_collocated(name = 'simple', proto_dep = '//proto:proto')
""");
getConfiguredTarget("//bar:simple");
assertNoEvents();
}
@Test
public void langProtoLibrary_inDifferentPackage_fails() throws Exception {
scratch.file(
"proto/BUILD",
TestConstants.LOAD_PROTO_LIBRARY,
"proto_library(name = 'proto', srcs = ['A.proto'])");
scratch.file(
"test/BUILD",
"""
load('//foo:check_collocated.bzl', 'check_collocated')
check_collocated(name = 'simple', proto_dep = '//proto:proto')
""");
reporter.removeHandler(failFastHandler);
getConfiguredTarget("//test:simple");
assertContainsEvent(
"lang_proto_library '@@//test:simple' may only be created in the same package as"
+ " proto_library '@@//proto:proto'");
}
@Test
public void langProtoLibrary_exportNotAllowed() throws Exception {
scratch.file(
"x/BUILD",
"""
proto_library(name='foo', srcs=['foo.proto'], allow_exports = ':test')
package_group(
name='test',
packages=['//allowed'],
)
""");
scratch.file(
"notallowed/BUILD",
"""
load('//foo:check_collocated.bzl', 'check_collocated')
check_collocated(name = 'simple', proto_dep = '//x:foo')
""");
reporter.removeHandler(failFastHandler);
getConfiguredTarget("//notallowed:simple");
assertContainsEvent(
"lang_proto_library '@@//notallowed:simple' may only be created in the same package as"
+ " proto_library '@@//x:foo'");
}
@Test
public void langProtoLibrary_exportAllowed() throws Exception {
scratch.file(
"x/BUILD",
"""
proto_library(name='foo', srcs=['foo.proto'], allow_exports = ':test')
package_group(
name='test',
packages=['//allowed'],
)
""");
scratch.file(
"allowed/BUILD",
"""
load('//foo:check_collocated.bzl', 'check_collocated')
check_collocated(name = 'simple', proto_dep = '//x:foo')
""");
getConfiguredTarget("//allowed:simple");
assertNoEvents();
}
}