| // Copyright 2017 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.objc; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| import static org.junit.Assert.assertThrows; |
| |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ObjectArrays; |
| import com.google.devtools.build.lib.actions.Artifact; |
| import com.google.devtools.build.lib.actions.util.ActionsTestUtil; |
| import com.google.devtools.build.lib.analysis.ConfiguredTarget; |
| import com.google.devtools.build.lib.cmdline.Label; |
| import com.google.devtools.build.lib.collect.nestedset.Depset; |
| import com.google.devtools.build.lib.packages.Provider; |
| import com.google.devtools.build.lib.packages.StarlarkProvider; |
| import com.google.devtools.build.lib.packages.StructImpl; |
| import com.google.devtools.build.lib.rules.apple.DottedVersion; |
| import com.google.devtools.build.lib.rules.cpp.CcInfo; |
| import com.google.devtools.build.lib.rules.cpp.CcLinkingContext; |
| import com.google.devtools.build.lib.vfs.PathFragment; |
| import java.util.List; |
| import java.util.Map; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.JUnit4; |
| |
| /** Tests for Starlark interaction with the objc_* rules. */ |
| @RunWith(JUnit4.class) |
| public class ObjcStarlarkTest extends ObjcRuleTestCase { |
| private static final Provider.Key APPLE_EXECUTABLE_BINARY_PROVIDER_KEY = |
| new StarlarkProvider.Key( |
| Label.parseCanonicalUnchecked("@_builtins//:common/objc/linking_support.bzl"), |
| "AppleExecutableBinaryInfo"); |
| |
| @Before |
| public void setupMyInfo() throws Exception { |
| scratch.file("myinfo/myinfo.bzl", "MyInfo = provider()"); |
| |
| scratch.file("myinfo/BUILD"); |
| } |
| |
| private StructImpl getMyInfoFromTarget(ConfiguredTarget configuredTarget) throws Exception { |
| Provider.Key key = |
| new StarlarkProvider.Key(Label.parseCanonical("//myinfo:myinfo.bzl"), "MyInfo"); |
| return (StructImpl) configuredTarget.get(key); |
| } |
| |
| @Test |
| @SuppressWarnings("unchecked") |
| public void testStarlarkRuleCanDependOnNativeAppleRule() throws Exception { |
| scratch.file("examples/rule/BUILD"); |
| scratch.file( |
| "examples/rule/apple_rules.bzl", |
| """ |
| load('//myinfo:myinfo.bzl', 'MyInfo') |
| def my_rule_impl(ctx): |
| dep = ctx.attr.deps[0] |
| library_to_link = dep[CcInfo].linking_context.linker_inputs.to_list()[0].libraries[0] |
| return MyInfo( |
| found_hdrs = dep[CcInfo].compilation_context.headers.to_list(), |
| found_libs = [library_to_link.static_library], |
| ) |
| my_rule = rule(implementation = my_rule_impl, |
| attrs = { |
| 'deps': attr.label_list(allow_files = False, mandatory = False, |
| providers = [[CcInfo]]), |
| }) |
| """); |
| scratch.file("examples/apple_starlark/a.m"); |
| scratch.file( |
| "examples/apple_starlark/BUILD", |
| """ |
| package(default_visibility = ['//visibility:public']) |
| load('//examples/rule:apple_rules.bzl', 'my_rule') |
| my_rule( |
| name = 'my_target', |
| deps = [':lib'], |
| ) |
| objc_library( |
| name = 'lib', |
| srcs = ['a.m'], |
| hdrs = ['b.h'] |
| ) |
| """); |
| |
| ConfiguredTarget starlarkTarget = getConfiguredTarget("//examples/apple_starlark:my_target"); |
| StructImpl myInfo = getMyInfoFromTarget(starlarkTarget); |
| List<Artifact> starlarkHdrs = (List<Artifact>) myInfo.getValue("found_hdrs"); |
| List<Artifact> starlarkLibraries = (List<Artifact>) myInfo.getValue("found_libs"); |
| |
| assertThat(ActionsTestUtil.baseArtifactNames(starlarkHdrs)).contains("b.h"); |
| assertThat(ActionsTestUtil.baseArtifactNames(starlarkLibraries)).contains("liblib.a"); |
| } |
| |
| @Test |
| public void testStarlarkProviderRetrievalNoneIfNoProvider() throws Exception { |
| scratch.file("examples/rule/BUILD"); |
| scratch.file( |
| "examples/rule/apple_rules.bzl", |
| """ |
| def my_rule_impl(ctx): |
| dep = ctx.attr.deps[0] |
| objc_provider = dep[apple_common.Objc] # this is line 3 |
| return [] |
| my_rule = rule(implementation = my_rule_impl, |
| attrs = { |
| 'deps': attr.label_list(allow_files = False, mandatory = False), |
| }) |
| """); |
| scratch.file("examples/apple_starlark/a.cc"); |
| scratch.file( |
| "examples/apple_starlark/BUILD", |
| """ |
| package(default_visibility = ['//visibility:public']) |
| load('//examples/rule:apple_rules.bzl', 'my_rule') |
| my_rule( |
| name = 'my_target', |
| deps = [':lib'], |
| ) |
| cc_library( |
| name = 'lib', |
| srcs = ['a.cc'], |
| hdrs = ['b.h'] |
| ) |
| """); |
| AssertionError e = |
| assertThrows( |
| AssertionError.class, () -> getConfiguredTarget("//examples/apple_starlark:my_target")); |
| assertThat(e) |
| .hasMessageThat() |
| .contains("apple_starlark/BUILD:3:8: in my_rule rule //examples/apple_starlark:my_target:"); |
| assertThat(e) |
| .hasMessageThat() |
| .contains( |
| "File \"/workspace/examples/rule/apple_rules.bzl\", line 3, column 23, in" |
| + " my_rule_impl"); |
| assertThat(e) |
| .hasMessageThat() |
| .contains( |
| "<target //examples/apple_starlark:lib> (rule 'cc_library') " |
| + "doesn't contain declared provider 'objc'"); |
| } |
| |
| @Test |
| public void testStarlarkProviderCanCheckForExistenceOfObjcProvider() throws Exception { |
| scratch.file("examples/rule/BUILD"); |
| scratch.file( |
| "examples/rule/apple_rules.bzl", |
| """ |
| load('//myinfo:myinfo.bzl', 'MyInfo') |
| def my_rule_impl(ctx): |
| cc_has_provider = apple_common.Objc in ctx.attr.deps[0] |
| objc_has_provider = apple_common.Objc in ctx.attr.deps[1] |
| return MyInfo(cc_has_provider=cc_has_provider, objc_has_provider=objc_has_provider) |
| my_rule = rule(implementation = my_rule_impl, |
| attrs = { |
| 'deps': attr.label_list(allow_files = False, mandatory = False), |
| }) |
| """); |
| scratch.file("examples/apple_starlark/a.cc"); |
| scratch.file("examples/apple_starlark/a.m"); |
| scratch.file( |
| "examples/apple_starlark/BUILD", |
| """ |
| package(default_visibility = ['//visibility:public']) |
| load('//examples/rule:apple_rules.bzl', 'my_rule') |
| my_rule( |
| name = 'my_target', |
| deps = [':cc_lib', ':objc_lib'], |
| ) |
| objc_library( |
| name = 'objc_lib', |
| srcs = ['a.m'], |
| ) |
| cc_library( |
| name = 'cc_lib', |
| srcs = ['a.cc'], |
| ) |
| """); |
| ConfiguredTarget starlarkTarget = getConfiguredTarget("//examples/apple_starlark:my_target"); |
| StructImpl myInfo = getMyInfoFromTarget(starlarkTarget); |
| boolean ccResult = (boolean) myInfo.getValue("cc_has_provider"); |
| boolean objcResult = (boolean) myInfo.getValue("objc_has_provider"); |
| assertThat(ccResult).isFalse(); |
| assertThat(objcResult).isTrue(); |
| } |
| |
| @Test |
| public void testStarlarkExportsObjcProviderToNativeRule() throws Exception { |
| scratch.file("examples/rule/BUILD"); |
| scratch.file( |
| "examples/rule/apple_rules.bzl", |
| """ |
| def my_rule_impl(ctx): |
| dep = ctx.attr.deps[0] |
| return [dep[apple_common.Objc], dep[CcInfo]] |
| swift_library = rule( |
| implementation = my_rule_impl, |
| attrs = { |
| 'deps': attr.label_list( |
| allow_files = False, |
| mandatory = False, |
| providers = [[apple_common.Objc, CcInfo]], |
| ) |
| } |
| ) |
| """); |
| |
| scratch.file("examples/apple_starlark/a.m"); |
| addAppleBinaryStarlarkRule(scratch); |
| scratch.file( |
| "examples/apple_starlark/BUILD", |
| """ |
| load('//test_starlark:apple_binary_starlark.bzl', 'apple_binary_starlark') |
| load('//examples/rule:apple_rules.bzl', 'swift_library') |
| package(default_visibility = ['//visibility:public']) |
| objc_library( |
| name = 'lib', |
| srcs = ['a.m'], |
| ) |
| swift_library( |
| name='my_target', |
| deps=[':lib'], |
| ) |
| apple_binary_starlark( |
| name = 'bin', |
| platform_type = 'ios', |
| deps = [':my_target'] |
| ) |
| """); |
| |
| ConfiguredTarget binaryTarget = getConfiguredTarget("//examples/apple_starlark:bin"); |
| StructImpl executableProvider = |
| (StructImpl) binaryTarget.get(APPLE_EXECUTABLE_BINARY_PROVIDER_KEY); |
| CcLinkingContext ccLinkingContext = |
| executableProvider.getValue("cc_info", CcInfo.class).getCcLinkingContext(); |
| |
| assertThat( |
| Artifact.toRootRelativePaths( |
| ccLinkingContext.getStaticModeParamsForDynamicLibraryLibraries())) |
| .contains("examples/apple_starlark/liblib.a"); |
| } |
| |
| @Test |
| public void testObjcRuleCanDependOnArbitraryStarlarkRuleThatProvidesCcInfo() throws Exception { |
| scratch.file("examples/rule/BUILD"); |
| scratch.file( |
| "examples/rule/apple_rules.bzl", |
| """ |
| def my_rule_impl(ctx): |
| return [CcInfo()] |
| my_rule = rule(implementation = my_rule_impl, |
| attrs = {}) |
| """); |
| |
| scratch.file("examples/apple_starlark/a.m"); |
| addAppleBinaryStarlarkRule(scratch); |
| scratch.file( |
| "examples/apple_starlark/BUILD", |
| """ |
| load('//test_starlark:apple_binary_starlark.bzl', 'apple_binary_starlark') |
| load('//examples/rule:apple_rules.bzl', 'my_rule') |
| package(default_visibility = ['//visibility:public']) |
| my_rule( |
| name='my_target' |
| ) |
| objc_library( |
| name = 'lib', |
| srcs = ['a.m'], |
| deps = [':my_target'] |
| ) |
| apple_binary_starlark( |
| name = 'bin', |
| platform_type = 'ios', |
| deps = [':lib'] |
| ) |
| """); |
| |
| ConfiguredTarget libTarget = getConfiguredTarget("//examples/apple_starlark:lib"); |
| assertThat(libTarget.get(CcInfo.PROVIDER)).isNotNull(); |
| } |
| |
| @Test |
| public void testStarlarkCanAccessAppleConfiguration() throws Exception { |
| scratch.file("examples/rule/BUILD"); |
| scratch.file( |
| "examples/rule/apple_rules.bzl", |
| """ |
| load('//myinfo:myinfo.bzl', 'MyInfo') |
| def swift_binary_impl(ctx): |
| xcode_config = ctx.attr._xcode_config[apple_common.XcodeVersionConfig] |
| cpu = ctx.fragments.apple.single_arch_cpu |
| platform = ctx.fragments.apple.single_arch_platform |
| xcode_config = ctx.attr._xcode_config[apple_common.XcodeVersionConfig] |
| dead_code_report = ctx.attr._dead_code_report |
| env = apple_common.target_apple_env(xcode_config, platform) |
| xcode_version = xcode_config.xcode_version() |
| sdk_version = xcode_config.sdk_version_for_platform(platform) |
| single_arch_platform = ctx.fragments.apple.single_arch_platform |
| single_arch_cpu = ctx.fragments.apple.single_arch_cpu |
| platform_type = single_arch_platform.platform_type |
| return MyInfo( |
| cpu=cpu, |
| env=env, |
| xcode_version=str(xcode_version), |
| sdk_version=str(sdk_version), |
| single_arch_platform=str(single_arch_platform), |
| single_arch_cpu=str(single_arch_cpu), |
| platform_type=str(platform_type), |
| dead_code_report=str(dead_code_report), |
| ) |
| swift_binary = rule( |
| implementation = swift_binary_impl, |
| fragments = ['apple'], |
| attrs = { |
| '_xcode_config': attr.label( |
| default = configuration_field( |
| fragment = 'apple', name = 'xcode_config_label')), |
| '_dead_code_report': attr.label( |
| default = configuration_field( |
| fragment = 'j2objc', name = 'dead_code_report')), |
| }, |
| ) |
| """); |
| |
| scratch.file("examples/apple_starlark/a.m"); |
| scratch.file( |
| "examples/apple_starlark/BUILD", |
| """ |
| package(default_visibility = ['//visibility:public']) |
| load('//examples/rule:apple_rules.bzl', 'swift_binary') |
| swift_binary( |
| name='my_target', |
| ) |
| """); |
| |
| useConfiguration("--apple_platform_type=ios", "--cpu=ios_i386", "--xcode_version=7.3"); |
| ConfiguredTarget starlarkTarget = getConfiguredTarget("//examples/apple_starlark:my_target"); |
| StructImpl myInfo = getMyInfoFromTarget(starlarkTarget); |
| |
| Object iosCpu = myInfo.getValue("cpu"); |
| @SuppressWarnings("unchecked") |
| Map<String, String> env = (Map<String, String>) myInfo.getValue("env"); |
| Object sdkVersion = myInfo.getValue("sdk_version"); |
| |
| assertThat(iosCpu).isEqualTo("i386"); |
| assertThat(env).containsEntry("APPLE_SDK_PLATFORM", "iPhoneSimulator"); |
| assertThat(env).containsEntry("APPLE_SDK_VERSION_OVERRIDE", "8.4"); |
| assertThat(sdkVersion).isEqualTo("8.4"); |
| assertThat(myInfo.getValue("xcode_version")).isEqualTo("7.3"); |
| assertThat(myInfo.getValue("single_arch_platform")).isEqualTo("IOS_SIMULATOR"); |
| assertThat(myInfo.getValue("single_arch_cpu")).isEqualTo("i386"); |
| assertThat(myInfo.getValue("platform_type")).isEqualTo("ios"); |
| assertThat(myInfo.getValue("dead_code_report")).isEqualTo("None"); |
| } |
| |
| @Test |
| public void testDefaultJ2objcDeadCodeReport() throws Exception { |
| scratch.file("examples/rule/BUILD"); |
| scratch.file( |
| "examples/rule/apple_rules.bzl", |
| """ |
| load('//myinfo:myinfo.bzl', 'MyInfo') |
| def swift_binary_impl(ctx): |
| dead_code_report = ctx.attr._dead_code_report |
| return MyInfo( |
| dead_code_report=str(dead_code_report), |
| ) |
| swift_binary = rule( |
| implementation = swift_binary_impl, |
| fragments = ['j2objc'], |
| attrs = { |
| '_dead_code_report': attr.label( |
| default = configuration_field( |
| fragment = 'j2objc', name = 'dead_code_report')), |
| }, |
| ) |
| """); |
| |
| scratch.file("examples/apple_starlark/a.m"); |
| scratch.file( |
| "examples/apple_starlark/BUILD", |
| """ |
| package(default_visibility = ['//visibility:public']) |
| load('//examples/rule:apple_rules.bzl', 'swift_binary') |
| swift_binary( |
| name='my_target', |
| ) |
| """); |
| |
| useConfiguration(); |
| ConfiguredTarget starlarkTarget = getConfiguredTarget("//examples/apple_starlark:my_target"); |
| |
| assertThat(getMyInfoFromTarget(starlarkTarget).getValue("dead_code_report")).isEqualTo("None"); |
| } |
| |
| @Test |
| public void testCustomJ2objcDeadCodeReport() throws Exception { |
| scratch.file("examples/rule/BUILD"); |
| scratch.file( |
| "examples/rule/apple_rules.bzl", |
| """ |
| load('//myinfo:myinfo.bzl', 'MyInfo') |
| def dead_code_report_impl(ctx): |
| return MyInfo(foo='bar') |
| def swift_binary_impl(ctx): |
| dead_code_report = ctx.attr._dead_code_report[MyInfo].foo |
| return MyInfo( |
| dead_code_report=dead_code_report, |
| ) |
| dead_code_report = rule( |
| implementation = dead_code_report_impl, |
| ) |
| swift_binary = rule( |
| implementation = swift_binary_impl, |
| fragments = ['j2objc'], |
| attrs = { |
| '_dead_code_report': attr.label( |
| default = configuration_field( |
| fragment = 'j2objc', name = 'dead_code_report')), |
| }, |
| ) |
| """); |
| |
| scratch.file("examples/apple_starlark/a.m"); |
| scratch.file( |
| "examples/apple_starlark/BUILD", |
| """ |
| package(default_visibility = ['//visibility:public']) |
| load('//examples/rule:apple_rules.bzl', 'dead_code_report', 'swift_binary') |
| swift_binary( |
| name='my_target', |
| ) |
| dead_code_report(name='dead_code_report') |
| """); |
| |
| useConfiguration("--j2objc_dead_code_report=//examples/apple_starlark:dead_code_report"); |
| ConfiguredTarget starlarkTarget = getConfiguredTarget("//examples/apple_starlark:my_target"); |
| |
| assertThat(getMyInfoFromTarget(starlarkTarget).getValue("dead_code_report")).isEqualTo("bar"); |
| } |
| |
| @Test |
| public void testStarlarkCanAccessJ2objcTranslationFlags() throws Exception { |
| scratch.file("examples/rule/BUILD"); |
| scratch.file( |
| "examples/rule/apple_rules.bzl", |
| """ |
| load('//myinfo:myinfo.bzl', 'MyInfo') |
| def swift_binary_impl(ctx): |
| j2objc_flags = ctx.fragments.j2objc.translation_flags |
| return MyInfo( |
| j2objc_flags=j2objc_flags, |
| ) |
| swift_binary = rule( |
| implementation = swift_binary_impl, |
| fragments = ['j2objc'], |
| ) |
| """); |
| |
| scratch.file("examples/apple_starlark/a.m"); |
| scratch.file( |
| "examples/apple_starlark/BUILD", |
| """ |
| package(default_visibility = ['//visibility:public']) |
| load('//examples/rule:apple_rules.bzl', 'swift_binary') |
| swift_binary( |
| name='my_target', |
| ) |
| """); |
| |
| useConfiguration("--j2objc_translation_flags=-DTestJ2ObjcFlag"); |
| ConfiguredTarget starlarkTarget = getConfiguredTarget("//examples/apple_starlark:my_target"); |
| |
| @SuppressWarnings("unchecked") |
| List<String> flags = (List<String>) getMyInfoFromTarget(starlarkTarget) |
| .getValue("j2objc_flags"); |
| assertThat(flags).contains("-DTestJ2ObjcFlag"); |
| assertThat(flags).doesNotContain("-unspecifiedFlag"); |
| } |
| |
| @Test |
| public void testStarlarkCanAccessApplePlatformNames() throws Exception { |
| scratch.file("examples/rule/BUILD"); |
| scratch.file( |
| "examples/rule/apple_rules.bzl", |
| """ |
| load('//myinfo:myinfo.bzl', 'MyInfo') |
| def _test_rule_impl(ctx): |
| platform = ctx.fragments.apple.single_arch_platform |
| return MyInfo( |
| name=platform.name_in_plist, |
| ) |
| test_rule = rule( |
| implementation = _test_rule_impl, |
| fragments = ['apple'] |
| ) |
| """); |
| |
| scratch.file( |
| "examples/apple_starlark/BUILD", |
| """ |
| package(default_visibility = ['//visibility:public']) |
| load('//examples/rule:apple_rules.bzl', 'test_rule') |
| test_rule( |
| name='my_target', |
| ) |
| """); |
| |
| useConfiguration("--cpu=ios_i386", "--apple_platform_type=ios"); |
| ConfiguredTarget starlarkTarget = getConfiguredTarget("//examples/apple_starlark:my_target"); |
| |
| Object name = getMyInfoFromTarget(starlarkTarget).getValue("name"); |
| assertThat(name).isEqualTo("iPhoneSimulator"); |
| } |
| |
| @Test |
| public void testStarlarkCanAccessAppleToolchain() throws Exception { |
| scratch.file("examples/rule/BUILD"); |
| scratch.file( |
| "examples/rule/apple_rules.bzl", |
| """ |
| load('//myinfo:myinfo.bzl', 'MyInfo') |
| def swift_binary_impl(ctx): |
| apple_toolchain = apple_common.apple_toolchain() |
| sdk_dir = apple_toolchain.sdk_dir() |
| platform_developer_framework_dir = \\ |
| apple_toolchain.platform_developer_framework_dir(ctx.fragments.apple) |
| return MyInfo( |
| platform_developer_framework_dir=platform_developer_framework_dir, |
| sdk_dir=sdk_dir, |
| ) |
| swift_binary = rule( |
| implementation = swift_binary_impl, |
| fragments = ['apple'] |
| ) |
| """); |
| |
| scratch.file("examples/apple_starlark/a.m"); |
| scratch.file( |
| "examples/apple_starlark/BUILD", |
| """ |
| package(default_visibility = ['//visibility:public']) |
| load('//examples/rule:apple_rules.bzl', 'swift_binary') |
| swift_binary( |
| name='my_target', |
| ) |
| """); |
| |
| useConfiguration("--apple_platform_type=ios", "--cpu=ios_i386"); |
| ConfiguredTarget starlarkTarget = getConfiguredTarget("//examples/apple_starlark:my_target"); |
| StructImpl myInfo = getMyInfoFromTarget(starlarkTarget); |
| |
| String platformDevFrameworksDir = (String) myInfo.getValue("platform_developer_framework_dir"); |
| String sdkDir = (String) myInfo.getValue("sdk_dir"); |
| |
| assertThat(platformDevFrameworksDir) |
| .isEqualTo( |
| "__BAZEL_XCODE_DEVELOPER_DIR__" |
| + "/Platforms/iPhoneSimulator.platform/Developer/Library/Frameworks"); |
| assertThat(sdkDir).isEqualTo("__BAZEL_XCODE_SDKROOT__"); |
| } |
| |
| @Test |
| public void testStarlarkCanAccessSdkAndMinimumOs() throws Exception { |
| scratch.file("examples/rule/BUILD"); |
| scratch.file( |
| "examples/rule/apple_rules.bzl", |
| """ |
| load('//myinfo:myinfo.bzl', 'MyInfo') |
| def swift_binary_impl(ctx): |
| xcode_config = ctx.attr._xcode_config[apple_common.XcodeVersionConfig] |
| ios_sdk_version = xcode_config.sdk_version_for_platform\\ |
| (apple_common.platform.ios_device) |
| watchos_sdk_version = xcode_config.sdk_version_for_platform\\ |
| (apple_common.platform.watchos_device) |
| tvos_sdk_version = xcode_config.sdk_version_for_platform\\ |
| (apple_common.platform.tvos_device) |
| macos_sdk_version = xcode_config.sdk_version_for_platform\\ |
| (apple_common.platform.macos) |
| ios_minimum_os = xcode_config.minimum_os_for_platform_type\\ |
| (apple_common.platform_type.ios) |
| watchos_minimum_os = xcode_config.minimum_os_for_platform_type\\ |
| (apple_common.platform_type.watchos) |
| tvos_minimum_os = xcode_config.minimum_os_for_platform_type\\ |
| (apple_common.platform_type.tvos) |
| visionos_minimum_os = xcode_config.minimum_os_for_platform_type\\ |
| (apple_common.platform_type.visionos) |
| return MyInfo( |
| ios_sdk_version=str(ios_sdk_version), |
| watchos_sdk_version=str(watchos_sdk_version), |
| tvos_sdk_version=str(tvos_sdk_version), |
| macos_sdk_version=str(macos_sdk_version), |
| ios_minimum_os=str(ios_minimum_os), |
| watchos_minimum_os=str(watchos_minimum_os), |
| tvos_minimum_os=str(tvos_minimum_os), |
| visionos_minimum_os=str(visionos_minimum_os) |
| ) |
| swift_binary = rule( |
| implementation = swift_binary_impl, |
| fragments = ['apple'], |
| attrs = { '_xcode_config': |
| attr.label(default=configuration_field( |
| fragment='apple', name='xcode_config_label')) }, |
| ) |
| """); |
| |
| scratch.file("examples/apple_starlark/a.m"); |
| scratch.file( |
| "examples/apple_starlark/BUILD", |
| """ |
| package(default_visibility = ['//visibility:public']) |
| load('//examples/rule:apple_rules.bzl', 'swift_binary') |
| swift_binary( |
| name='my_target', |
| ) |
| """); |
| |
| useConfiguration( |
| "--ios_sdk_version=1.1", |
| "--ios_minimum_os=1.0", |
| "--watchos_sdk_version=2.1", |
| "--watchos_minimum_os=2.0", |
| "--tvos_sdk_version=3.1", |
| "--tvos_minimum_os=3.0", |
| "--macos_sdk_version=4.1", |
| "--minimum_os_version=5.1"); |
| ConfiguredTarget starlarkTarget = getConfiguredTarget("//examples/apple_starlark:my_target"); |
| StructImpl myInfo = getMyInfoFromTarget(starlarkTarget); |
| |
| assertThat(myInfo.getValue("ios_sdk_version")).isEqualTo("1.1"); |
| assertThat(myInfo.getValue("ios_minimum_os")).isEqualTo("1.0"); |
| assertThat(myInfo.getValue("watchos_sdk_version")).isEqualTo("2.1"); |
| assertThat(myInfo.getValue("watchos_minimum_os")).isEqualTo("2.0"); |
| assertThat(myInfo.getValue("tvos_sdk_version")).isEqualTo("3.1"); |
| assertThat(myInfo.getValue("tvos_minimum_os")).isEqualTo("3.0"); |
| assertThat(myInfo.getValue("macos_sdk_version")).isEqualTo("4.1"); |
| assertThat(myInfo.getValue("visionos_minimum_os")).isEqualTo("5.1"); |
| |
| useConfiguration("--ios_sdk_version=1.1", |
| "--watchos_sdk_version=2.1", |
| "--tvos_sdk_version=3.1", |
| "--macos_sdk_version=4.1"); |
| starlarkTarget = getConfiguredTarget("//examples/apple_starlark:my_target"); |
| myInfo = getMyInfoFromTarget(starlarkTarget); |
| |
| assertThat(myInfo.getValue("ios_sdk_version")).isEqualTo("1.1"); |
| assertThat(myInfo.getValue("ios_minimum_os")).isEqualTo("1.1"); |
| assertThat(myInfo.getValue("watchos_sdk_version")).isEqualTo("2.1"); |
| assertThat(myInfo.getValue("watchos_minimum_os")).isEqualTo("2.1"); |
| assertThat(myInfo.getValue("tvos_sdk_version")).isEqualTo("3.1"); |
| assertThat(myInfo.getValue("tvos_minimum_os")).isEqualTo("3.1"); |
| assertThat(myInfo.getValue("macos_sdk_version")).isEqualTo("4.1"); |
| } |
| |
| @Test |
| public void testStarlarkCanAccessObjcConfiguration() throws Exception { |
| scratch.file("examples/rule/BUILD"); |
| scratch.file( |
| "examples/rule/objc_rules.bzl", |
| """ |
| load('//myinfo:myinfo.bzl', 'MyInfo') |
| def swift_binary_impl(ctx): |
| compilation_mode_copts = ctx.fragments.objc.copts_for_current_compilation_mode |
| ios_simulator_device = ctx.fragments.objc.ios_simulator_device |
| ios_simulator_version = ctx.fragments.objc.ios_simulator_version |
| signing_certificate_name = ctx.fragments.objc.signing_certificate_name |
| return MyInfo( |
| compilation_mode_copts=compilation_mode_copts, |
| ios_simulator_device=ios_simulator_device, |
| ios_simulator_version=str(ios_simulator_version), |
| signing_certificate_name=signing_certificate_name, |
| ) |
| swift_binary = rule( |
| implementation = swift_binary_impl, |
| fragments = ['objc'] |
| ) |
| """); |
| |
| scratch.file("examples/objc_starlark/a.m"); |
| scratch.file( |
| "examples/objc_starlark/BUILD", |
| """ |
| package(default_visibility = ['//visibility:public']) |
| load('//examples/rule:objc_rules.bzl', 'swift_binary') |
| swift_binary( |
| name='my_target', |
| ) |
| """); |
| |
| useConfiguration( |
| "--compilation_mode=opt", |
| "--ios_simulator_device='iPhone 6'", |
| "--ios_simulator_version=8.4", |
| "--ios_signing_cert_name='Apple Developer'"); |
| ConfiguredTarget starlarkTarget = getConfiguredTarget("//examples/objc_starlark:my_target"); |
| StructImpl myInfo = getMyInfoFromTarget(starlarkTarget); |
| |
| @SuppressWarnings("unchecked") |
| List<String> compilationModeCopts = (List<String>) myInfo.getValue("compilation_mode_copts"); |
| Object iosSimulatorDevice = myInfo.getValue("ios_simulator_device"); |
| Object iosSimulatorVersion = myInfo.getValue("ios_simulator_version"); |
| Object signingCertificateName = myInfo.getValue("signing_certificate_name"); |
| |
| assertThat(compilationModeCopts).containsExactlyElementsIn(ObjcConfiguration.OPT_COPTS); |
| assertThat(iosSimulatorDevice).isEqualTo("'iPhone 6'"); |
| assertThat(iosSimulatorVersion).isEqualTo("8.4"); |
| assertThat(signingCertificateName).isEqualTo("'Apple Developer'"); |
| } |
| |
| @Test |
| public void testSigningCertificateNameCanReturnNone() throws Exception { |
| scratch.file("examples/rule/BUILD"); |
| scratch.file( |
| "examples/rule/objc_rules.bzl", |
| """ |
| load('//myinfo:myinfo.bzl', 'MyInfo') |
| def my_rule_impl(ctx): |
| signing_certificate_name = ctx.fragments.objc.signing_certificate_name |
| return MyInfo( |
| signing_certificate_name=str(signing_certificate_name), |
| ) |
| my_rule = rule( |
| implementation = my_rule_impl, |
| fragments = ['objc'] |
| ) |
| """); |
| |
| scratch.file("examples/objc_starlark/a.m"); |
| scratch.file( |
| "examples/objc_starlark/BUILD", |
| """ |
| package(default_visibility = ['//visibility:public']) |
| load('//examples/rule:objc_rules.bzl', 'my_rule') |
| my_rule( |
| name='my_target', |
| ) |
| """); |
| |
| ConfiguredTarget starlarkTarget = getConfiguredTarget("//examples/objc_starlark:my_target"); |
| |
| Object signingCertificateName = |
| getMyInfoFromTarget(starlarkTarget).getValue("signing_certificate_name"); |
| assertThat(signingCertificateName).isEqualTo("None"); |
| } |
| |
| @Test |
| public void testUsesDebugEntitlementsIsTrueIfCompilationModeIsNotOpt() throws Exception { |
| scratch.file("examples/rule/BUILD"); |
| scratch.file( |
| "examples/rule/objc_rules.bzl", |
| """ |
| load('//myinfo:myinfo.bzl', 'MyInfo') |
| def test_rule_impl(ctx): |
| uses_device_debug_entitlements = ctx.fragments.objc.uses_device_debug_entitlements |
| return MyInfo( |
| uses_device_debug_entitlements=uses_device_debug_entitlements, |
| ) |
| test_rule = rule( |
| implementation = test_rule_impl, |
| fragments = ['objc'] |
| ) |
| """); |
| |
| scratch.file("examples/objc_starlark/a.m"); |
| scratch.file( |
| "examples/objc_starlark/BUILD", |
| """ |
| package(default_visibility = ['//visibility:public']) |
| load('//examples/rule:objc_rules.bzl', 'test_rule') |
| test_rule( |
| name='my_target', |
| ) |
| """); |
| |
| useConfiguration("--compilation_mode=dbg"); |
| ConfiguredTarget starlarkTarget = getConfiguredTarget("//examples/objc_starlark:my_target"); |
| |
| boolean usesDeviceDebugEntitlements = |
| (boolean) getMyInfoFromTarget(starlarkTarget).getValue("uses_device_debug_entitlements"); |
| assertThat(usesDeviceDebugEntitlements).isTrue(); |
| } |
| |
| @Test |
| public void testUsesDebugEntitlementsIsFalseIfFlagIsExplicitlyFalse() throws Exception { |
| scratch.file("examples/rule/BUILD"); |
| scratch.file( |
| "examples/rule/objc_rules.bzl", |
| """ |
| load('//myinfo:myinfo.bzl', 'MyInfo') |
| def test_rule_impl(ctx): |
| uses_device_debug_entitlements = ctx.fragments.objc.uses_device_debug_entitlements |
| return MyInfo( |
| uses_device_debug_entitlements=uses_device_debug_entitlements, |
| ) |
| test_rule = rule( |
| implementation = test_rule_impl, |
| fragments = ['objc'] |
| ) |
| """); |
| |
| scratch.file("examples/objc_starlark/a.m"); |
| scratch.file( |
| "examples/objc_starlark/BUILD", |
| """ |
| package(default_visibility = ['//visibility:public']) |
| load('//examples/rule:objc_rules.bzl', 'test_rule') |
| test_rule( |
| name='my_target', |
| ) |
| """); |
| |
| useConfiguration( |
| "--compilation_mode=dbg", |
| "--nodevice_debug_entitlements"); |
| ConfiguredTarget starlarkTarget = getConfiguredTarget("//examples/objc_starlark:my_target"); |
| |
| boolean usesDeviceDebugEntitlements = |
| (boolean) getMyInfoFromTarget(starlarkTarget).getValue("uses_device_debug_entitlements"); |
| assertThat(usesDeviceDebugEntitlements).isFalse(); |
| } |
| |
| @Test |
| public void testUsesDebugEntitlementsIsFalseIfCompilationModeIsOpt() throws Exception { |
| scratch.file("examples/rule/BUILD"); |
| scratch.file( |
| "examples/rule/objc_rules.bzl", |
| """ |
| load('//myinfo:myinfo.bzl', 'MyInfo') |
| def test_rule_impl(ctx): |
| uses_device_debug_entitlements = ctx.fragments.objc.uses_device_debug_entitlements |
| return MyInfo( |
| uses_device_debug_entitlements=uses_device_debug_entitlements, |
| ) |
| test_rule = rule( |
| implementation = test_rule_impl, |
| fragments = ['objc'] |
| ) |
| """); |
| |
| scratch.file("examples/objc_starlark/a.m"); |
| scratch.file( |
| "examples/objc_starlark/BUILD", |
| """ |
| package(default_visibility = ['//visibility:public']) |
| load('//examples/rule:objc_rules.bzl', 'test_rule') |
| test_rule( |
| name='my_target', |
| ) |
| """); |
| |
| useConfiguration("--compilation_mode=opt"); |
| ConfiguredTarget starlarkTarget = getConfiguredTarget("//examples/objc_starlark:my_target"); |
| |
| boolean usesDeviceDebugEntitlements = |
| (boolean) getMyInfoFromTarget(starlarkTarget).getValue("uses_device_debug_entitlements"); |
| assertThat(usesDeviceDebugEntitlements).isFalse(); |
| } |
| |
| private ConfiguredTarget createObjcProviderStarlarkTarget(String... implLines) throws Exception { |
| String[] impl = |
| ObjectArrays.concat( |
| ObjectArrays.concat("def swift_binary_impl(ctx):", implLines), |
| new String[] { |
| "swift_binary = rule(", |
| "implementation = swift_binary_impl,", |
| "attrs = {", |
| " 'deps': attr.label_list(", |
| "allow_files = False, mandatory = False, providers = [[apple_common.Objc]])", |
| "})" |
| }, |
| String.class); |
| |
| scratch.file("examples/rule/BUILD"); |
| scratch.file("examples/rule/objc_rules.bzl", impl); |
| scratch.file( |
| "examples/objc_starlark/BUILD", |
| """ |
| package(default_visibility = ['//visibility:public']) |
| load('//examples/rule:objc_rules.bzl', 'swift_binary') |
| swift_binary( |
| name='my_target', |
| deps=[':lib'], |
| ) |
| objc_library( |
| name = 'lib', |
| srcs = ['a.m'], |
| ) |
| """); |
| |
| return getConfiguredTarget("//examples/objc_starlark:my_target"); |
| } |
| |
| @Test |
| public void testStarlarkCanCreateObjcProviderFromScratch() throws Exception { |
| ConfiguredTarget starlarkTarget = |
| createObjcProviderStarlarkTarget( |
| " file = ctx.actions.declare_file('foo.m')", |
| " ctx.actions.run_shell(outputs=[file], command='echo')", |
| " created_provider = apple_common.new_objc_provider(source=depset([file]))", |
| " return [created_provider]"); |
| |
| ImmutableList<Artifact> sources = |
| starlarkTarget.get(ObjcProvider.STARLARK_CONSTRUCTOR).get(ObjcProvider.SOURCE).toList(); |
| |
| assertThat(ActionsTestUtil.baseArtifactNames(sources)).containsExactly("foo.m"); |
| } |
| |
| @Test |
| public void testStarlarkCanCreateObjcProviderWithStrictDeps() throws Exception { |
| ConfiguredTarget starlarkTarget = |
| createObjcProviderStarlarkTarget( |
| " strict_includes = depset(['path'])", |
| " created_provider = apple_common.new_objc_provider(strict_include=strict_includes)", |
| " return [created_provider, CcInfo()]"); |
| |
| ObjcProvider starlarkProvider = starlarkTarget.get(ObjcProvider.STARLARK_CONSTRUCTOR); |
| assertThat(starlarkProvider.getStrictDependencyIncludes()) |
| .containsExactly(PathFragment.create("path")); |
| |
| scratch.file( |
| "examples/objc_starlark2/BUILD", |
| """ |
| objc_library( |
| name = 'direct_dep', |
| deps = ['//examples/objc_starlark:my_target'] |
| ) |
| """); |
| |
| ObjcProvider starlarkProviderDirectDepender = |
| getConfiguredTarget("//examples/objc_starlark2:direct_dep") |
| .get(ObjcProvider.STARLARK_CONSTRUCTOR); |
| assertThat(starlarkProviderDirectDepender.getStrictDependencyIncludes()).isEmpty(); |
| } |
| |
| @Test |
| public void testStarlarkCanCreateObjcProviderFromObjcProvider() throws Exception { |
| scratch.file("examples/rule/BUILD"); |
| scratch.file( |
| "examples/rule/objc_rules.bzl", |
| """ |
| def library_impl(ctx): |
| lib = ctx.label.name + '.a' |
| file = ctx.actions.declare_file(lib) |
| ctx.actions.run_shell(outputs=[file], command='echo') |
| return [apple_common.new_objc_provider(j2objc_library=depset([file]))] |
| library = rule(implementation = library_impl) |
| def binary_impl(ctx): |
| dep = ctx.attr.deps[0] |
| lib = ctx.label.name + '.a' |
| file = ctx.actions.declare_file(lib) |
| ctx.actions.run_shell(outputs=[file], command='echo') |
| created_provider = apple_common.new_objc_provider( |
| providers=[dep[apple_common.Objc]], |
| j2objc_library=depset([file]), |
| ) |
| return [created_provider] |
| binary = rule( |
| implementation = binary_impl, |
| attrs = { |
| 'deps': attr.label_list( |
| allow_files = False, |
| mandatory = False, |
| providers = [[apple_common.Objc]], |
| ) |
| }) |
| """); |
| |
| scratch.file( |
| "examples/objc_starlark/BUILD", |
| """ |
| package(default_visibility = ['//visibility:public']) |
| load('//examples/rule:objc_rules.bzl', 'library', 'binary') |
| binary( |
| name='bin', |
| deps=[':lib'], |
| ) |
| library( |
| name = 'lib', |
| ) |
| """); |
| |
| ConfiguredTarget starlarkTarget = getConfiguredTarget("//examples/objc_starlark:bin"); |
| |
| ImmutableList<Artifact> libraries = |
| starlarkTarget |
| .get(ObjcProvider.STARLARK_CONSTRUCTOR) |
| .get(ObjcProvider.J2OBJC_LIBRARY) |
| .toList(); |
| |
| assertThat(ActionsTestUtil.baseArtifactNames(libraries)).containsExactly("lib.a", "bin.a"); |
| } |
| |
| @Test |
| public void testStarlarkErrorOnBadObjcProviderInputKey() throws Exception { |
| AssertionError e = |
| assertThrows( |
| AssertionError.class, |
| () -> |
| createObjcProviderStarlarkTarget( |
| " created_provider = apple_common.new_objc_provider(foo=depset(['bar']))", |
| " return created_provider")); |
| assertThat(e) |
| .hasMessageThat() |
| .contains(String.format(AppleStarlarkCommon.BAD_KEY_ERROR, "foo")); |
| } |
| |
| @Test |
| public void testStarlarkErrorOnNonSetObjcProviderInputValue() throws Exception { |
| AssertionError e = |
| assertThrows( |
| AssertionError.class, |
| () -> |
| createObjcProviderStarlarkTarget( |
| " created_provider = apple_common.new_objc_provider(source='bar')", |
| " return created_provider")); |
| assertThat(e).hasMessageThat().contains("for source, got string, want a depset of File"); |
| } |
| |
| @Test |
| public void testStarlarkErrorOnObjcProviderInputValueWrongSetType() throws Exception { |
| AssertionError e = |
| assertThrows( |
| AssertionError.class, |
| () -> |
| createObjcProviderStarlarkTarget( |
| " created_provider = apple_common.new_objc_provider(source=depset(['bar']))", |
| " return created_provider")); |
| assertThat(e) |
| .hasMessageThat() |
| .contains("for 'source', got a depset of 'string', expected a depset of 'File'"); |
| } |
| |
| @Test |
| public void testStarlarkErrorOnNonIterableObjcProviderProviderValue() throws Exception { |
| AssertionError e = |
| assertThrows( |
| AssertionError.class, |
| () -> |
| createObjcProviderStarlarkTarget( |
| " created_provider = apple_common.new_objc_provider(providers='bar')", |
| " return created_provider")); |
| assertThat(e) |
| .hasMessageThat() |
| .contains(String.format(AppleStarlarkCommon.BAD_PROVIDERS_ITER_ERROR, "string")); |
| } |
| |
| @Test |
| public void testStarlarkErrorOnBadIterableObjcProviderProviderValue() throws Exception { |
| AssertionError e = |
| assertThrows( |
| AssertionError.class, |
| () -> |
| createObjcProviderStarlarkTarget( |
| " created_provider = apple_common.new_objc_provider(providers=['bar'])", |
| " return created_provider")); |
| assertThat(e) |
| .hasMessageThat() |
| .contains(String.format(AppleStarlarkCommon.BAD_PROVIDERS_ELEM_ERROR, "string")); |
| } |
| |
| @Test |
| public void testEmptyObjcProviderKeysArePresent() throws Exception { |
| scratch.file("examples/rule/BUILD"); |
| scratch.file( |
| "examples/rule/apple_rules.bzl", |
| """ |
| load('//myinfo:myinfo.bzl', 'MyInfo') |
| def swift_binary_impl(ctx): |
| objc_provider = ctx.attr.deps[0][apple_common.Objc] |
| return MyInfo( |
| empty_value=objc_provider.j2objc_library, |
| ) |
| swift_binary = rule( |
| implementation = swift_binary_impl, |
| fragments = ['apple'], |
| attrs = { |
| 'deps': attr.label_list( |
| allow_files = False, |
| mandatory = False, |
| providers = [[apple_common.Objc]], |
| ) |
| }, |
| ) |
| """); |
| |
| scratch.file("examples/apple_starlark/a.m"); |
| scratch.file( |
| "examples/apple_starlark/BUILD", |
| """ |
| package(default_visibility = ['//visibility:public']) |
| load('//examples/rule:apple_rules.bzl', 'swift_binary') |
| swift_binary( |
| name='my_target', |
| deps=[':lib'], |
| ) |
| objc_library( |
| name = 'lib', |
| srcs = ['a.m'], |
| ) |
| """); |
| ConfiguredTarget starlarkTarget = getConfiguredTarget("//examples/apple_starlark:my_target"); |
| Depset emptyValue = (Depset) getMyInfoFromTarget(starlarkTarget).getValue("empty_value"); |
| assertThat(emptyValue.toList()).isEmpty(); |
| } |
| |
| @Test |
| public void testStarlarkCanAccessAndUseApplePlatformTypes() throws Exception { |
| scratch.file("examples/rule/BUILD"); |
| scratch.file( |
| "examples/rule/apple_rules.bzl", |
| """ |
| load('//myinfo:myinfo.bzl', 'MyInfo') |
| def _test_rule_impl(ctx): |
| apple = ctx.fragments.apple |
| ios_platform = apple.multi_arch_platform(apple_common.platform_type.ios) |
| watchos_platform = apple.multi_arch_platform(apple_common.platform_type.watchos) |
| tvos_platform = apple.multi_arch_platform(apple_common.platform_type.tvos) |
| return MyInfo( |
| ios_platform=str(ios_platform), |
| watchos_platform=str(watchos_platform), |
| tvos_platform=str(tvos_platform), |
| ) |
| test_rule = rule(implementation = _test_rule_impl, |
| fragments = ['apple']) |
| """); |
| |
| scratch.file( |
| "examples/apple_starlark/BUILD", |
| """ |
| package(default_visibility = ['//visibility:public']) |
| load('//examples/rule:apple_rules.bzl', 'test_rule') |
| test_rule( |
| name = 'my_target', |
| ) |
| """); |
| |
| useConfiguration( |
| "--ios_multi_cpus=arm64,armv7", |
| "--watchos_cpus=armv7k", |
| "--tvos_cpus=arm64"); |
| ConfiguredTarget starlarkTarget = getConfiguredTarget("//examples/apple_starlark:my_target"); |
| StructImpl myInfo = getMyInfoFromTarget(starlarkTarget); |
| |
| Object iosPlatform = myInfo.getValue("ios_platform"); |
| Object watchosPlatform = myInfo.getValue("watchos_platform"); |
| Object tvosPlatform = myInfo.getValue("tvos_platform"); |
| |
| assertThat(iosPlatform).isEqualTo("IOS_DEVICE"); |
| assertThat(watchosPlatform).isEqualTo("WATCHOS_DEVICE"); |
| assertThat(tvosPlatform).isEqualTo("TVOS_DEVICE"); |
| } |
| |
| @Test |
| public void testPlatformIsDeviceReturnsTrueForDevicePlatforms() throws Exception { |
| scratch.file("examples/rule/BUILD"); |
| scratch.file( |
| "examples/rule/apple_rules.bzl", |
| """ |
| load('//myinfo:myinfo.bzl', 'MyInfo') |
| def _test_rule_impl(ctx): |
| apple = ctx.fragments.apple |
| platform = apple.multi_arch_platform(apple_common.platform_type.ios) |
| return MyInfo( |
| is_device=platform.is_device, |
| ) |
| test_rule = rule(implementation = _test_rule_impl, |
| fragments = ['apple']) |
| """); |
| |
| scratch.file( |
| "examples/apple_starlark/BUILD", |
| """ |
| package(default_visibility = ['//visibility:public']) |
| load('//examples/rule:apple_rules.bzl', 'test_rule') |
| test_rule( |
| name = 'my_target', |
| ) |
| """); |
| |
| useConfiguration( |
| "--ios_multi_cpus=arm64,armv7"); |
| ConfiguredTarget starlarkTarget = getConfiguredTarget("//examples/apple_starlark:my_target"); |
| |
| Boolean isDevice = (Boolean) getMyInfoFromTarget(starlarkTarget).getValue("is_device"); |
| assertThat(isDevice).isTrue(); |
| } |
| |
| @Test |
| public void testPlatformIsDeviceReturnsFalseForSimulatorPlatforms() throws Exception { |
| scratch.file("examples/rule/BUILD"); |
| scratch.file( |
| "examples/rule/apple_rules.bzl", |
| """ |
| load('//myinfo:myinfo.bzl', 'MyInfo') |
| def _test_rule_impl(ctx): |
| apple = ctx.fragments.apple |
| platform = apple.multi_arch_platform(apple_common.platform_type.ios) |
| return MyInfo( |
| is_device=platform.is_device, |
| ) |
| test_rule = rule(implementation = _test_rule_impl, |
| fragments = ['apple']) |
| """); |
| |
| scratch.file( |
| "examples/apple_starlark/BUILD", |
| """ |
| package(default_visibility = ['//visibility:public']) |
| load('//examples/rule:apple_rules.bzl', 'test_rule') |
| test_rule( |
| name = 'my_target', |
| ) |
| """); |
| |
| ConfiguredTarget starlarkTarget = getConfiguredTarget("//examples/apple_starlark:my_target"); |
| |
| Boolean isDevice = (Boolean) getMyInfoFromTarget(starlarkTarget).getValue("is_device"); |
| assertThat(isDevice).isFalse(); |
| } |
| |
| @Test |
| public void testStarlarkWithRunMemleaksEnabled() throws Exception { |
| useConfiguration("--ios_memleaks"); |
| checkStarlarkRunMemleaksWithExpectedValue(true); |
| } |
| |
| @Test |
| public void testStarlarkWithRunMemleaksDisabled() throws Exception { |
| checkStarlarkRunMemleaksWithExpectedValue(false); |
| } |
| |
| @Test |
| public void testDottedVersion() throws Exception { |
| scratch.file("examples/rule/BUILD", |
| "exports_files(['test_artifact'])"); |
| scratch.file( |
| "examples/rule/apple_rules.bzl", |
| """ |
| load('//myinfo:myinfo.bzl', 'MyInfo') |
| def _test_rule_impl(ctx): |
| version = apple_common.dotted_version('5.4') |
| return MyInfo( |
| version=version |
| ) |
| test_rule = rule(implementation = _test_rule_impl) |
| """); |
| |
| scratch.file( |
| "examples/apple_starlark/BUILD", |
| """ |
| package(default_visibility = ['//visibility:public']) |
| load('//examples/rule:apple_rules.bzl', 'test_rule') |
| test_rule( |
| name = 'my_target', |
| ) |
| """); |
| |
| ConfiguredTarget starlarkTarget = getConfiguredTarget("//examples/apple_starlark:my_target"); |
| |
| DottedVersion version = (DottedVersion) getMyInfoFromTarget(starlarkTarget).getValue("version"); |
| assertThat(version).isEqualTo(DottedVersion.fromString("5.4")); |
| } |
| |
| @Test |
| public void testDottedVersion_invalid() throws Exception { |
| scratch.file("examples/rule/BUILD", |
| "exports_files(['test_artifact'])"); |
| scratch.file( |
| "examples/rule/apple_rules.bzl", |
| """ |
| load('//myinfo:myinfo.bzl', 'MyInfo') |
| def _test_rule_impl(ctx): |
| version = apple_common.dotted_version('hello') |
| return MyInfo( |
| version=version |
| ) |
| test_rule = rule(implementation = _test_rule_impl) |
| """); |
| |
| scratch.file( |
| "examples/apple_starlark/BUILD", |
| """ |
| package(default_visibility = ['//visibility:public']) |
| load('//examples/rule:apple_rules.bzl', 'test_rule') |
| test_rule( |
| name = 'my_target', |
| ) |
| """); |
| |
| AssertionError e = |
| assertThrows( |
| AssertionError.class, () -> getConfiguredTarget("//examples/apple_starlark:my_target")); |
| assertThat(e) |
| .hasMessageThat() |
| .contains("Dotted version components must all start with the form"); |
| } |
| |
| /** |
| * This test verifies that its possible to use the Starlark constructor of ObjcProvider as a |
| * provider key to obtain the provider. This test only needs to exist as long as there are two |
| * methods of retrieving ObjcProvider (which is true for legacy reasons). This is the 'new' method |
| * of retrieving ObjcProvider. |
| */ |
| @Test |
| public void testObjcProviderStarlarkConstructor() throws Exception { |
| scratch.file("examples/rule/BUILD"); |
| scratch.file( |
| "examples/rule/apple_rules.bzl", |
| """ |
| def my_rule_impl(ctx): |
| dep = ctx.attr.deps[0] |
| objc_provider = dep[apple_common.Objc] |
| return objc_provider |
| my_rule = rule(implementation = my_rule_impl, |
| attrs = { |
| 'deps': attr.label_list(allow_files = False, mandatory = False), |
| }) |
| """); |
| scratch.file("examples/apple_starlark/a.cc"); |
| scratch.file( |
| "examples/apple_starlark/BUILD", |
| """ |
| package(default_visibility = ['//visibility:public']) |
| load('//examples/rule:apple_rules.bzl', 'my_rule') |
| my_rule( |
| name = 'my_target', |
| deps = [':lib'], |
| ) |
| objc_library( |
| name = 'lib', |
| srcs = ['a.m'], |
| hdrs = ['a.h'] |
| ) |
| """); |
| |
| ConfiguredTarget starlarkTarget = getConfiguredTarget("//examples/apple_starlark:my_target"); |
| assertThat(starlarkTarget.get(ObjcProvider.STARLARK_CONSTRUCTOR)).isNotNull(); |
| } |
| |
| private void checkStarlarkRunMemleaksWithExpectedValue(boolean expectedValue) throws Exception { |
| scratch.file("examples/rule/BUILD"); |
| scratch.file( |
| "examples/rule/apple_rules.bzl", |
| """ |
| load('//myinfo:myinfo.bzl', 'MyInfo') |
| def _test_rule_impl(ctx): |
| return MyInfo(run_memleaks = ctx.fragments.objc.run_memleaks) |
| test_rule = rule(implementation = _test_rule_impl, |
| fragments = ['objc'], |
| attrs = {}, |
| ) |
| """); |
| |
| scratch.file( |
| "examples/apple_starlark/BUILD", |
| """ |
| package(default_visibility = ['//visibility:public']) |
| load('//examples/rule:apple_rules.bzl', 'test_rule') |
| test_rule( |
| name = 'my_target', |
| ) |
| """); |
| |
| ConfiguredTarget starlarkTarget = getConfiguredTarget("//examples/apple_starlark:my_target"); |
| |
| boolean runMemleaks = (boolean) getMyInfoFromTarget(starlarkTarget).getValue("run_memleaks"); |
| assertThat(runMemleaks).isEqualTo(expectedValue); |
| } |
| |
| @Test |
| public void testDisallowSDKFrameworkAttribute() throws Exception { |
| useConfiguration("--incompatible_disallow_sdk_frameworks_attributes"); |
| |
| scratch.file( |
| "examples/apple_starlark/BUILD", |
| """ |
| objc_library( |
| name = 'lib', |
| srcs = ['a.m'], |
| sdk_frameworks = ['Accelerate', 'GLKit'], |
| ) |
| """); |
| AssertionError e = |
| assertThrows( |
| AssertionError.class, () -> getConfiguredTarget("//examples/apple_starlark:lib")); |
| assertThat(e) |
| .hasMessageThat() |
| .contains( |
| "ERROR /workspace/examples/apple_starlark/BUILD:1:13: in sdk_frameworks attribute of" |
| + " objc_library rule //examples/apple_starlark:lib: sdk_frameworks attribute is" |
| + " disallowed. Use explicit dependencies instead."); |
| } |
| |
| @Test |
| public void testDisallowWeakSDKFrameworksAttribute() throws Exception { |
| useConfiguration("--incompatible_disallow_sdk_frameworks_attributes"); |
| |
| scratch.file( |
| "examples/apple_starlark/BUILD", |
| """ |
| objc_library( |
| name = 'lib', |
| srcs = ['a.m'], |
| weak_sdk_frameworks = ['XCTest'], |
| ) |
| """); |
| AssertionError e = |
| assertThrows( |
| AssertionError.class, () -> getConfiguredTarget("//examples/apple_starlark:lib")); |
| assertThat(e) |
| .hasMessageThat() |
| .contains( |
| "ERROR /workspace/examples/apple_starlark/BUILD:1:13: in weak_sdk_frameworks attribute" |
| + " of objc_library rule //examples/apple_starlark:lib: weak_sdk_frameworks" |
| + " attribute is disallowed. Use explicit dependencies instead."); |
| } |
| |
| @Test |
| public void testGetExperimentalShorterHeaderPathForStarlarkIsPrivateApi() throws Exception { |
| scratch.file( |
| "foo/rule.bzl", |
| """ |
| def _impl(ctx): |
| ctx.fragments.j2objc.experimental_shorter_header_path() |
| return [] |
| myrule = rule( |
| implementation=_impl, |
| fragments = ['j2objc'] |
| ) |
| """); |
| scratch.file( |
| "foo/BUILD", |
| """ |
| load(':rule.bzl', 'myrule') |
| myrule(name='myrule') |
| """); |
| reporter.removeHandler(failFastHandler); |
| |
| getConfiguredTarget("//foo:myrule"); |
| |
| assertContainsEvent("file '//foo:rule.bzl' cannot use private @_builtins API"); |
| } |
| |
| @Test |
| public void testGetExperimentalJ2ObjcHeaderMapForStarlarkIsPrivateApi() throws Exception { |
| scratch.file( |
| "foo/rule.bzl", |
| """ |
| def _impl(ctx): |
| ctx.fragments.j2objc.experimental_j2objc_header_map() |
| return [] |
| myrule = rule( |
| implementation=_impl, |
| fragments = ['j2objc'] |
| ) |
| """); |
| scratch.file( |
| "foo/BUILD", |
| """ |
| load(':rule.bzl', 'myrule') |
| myrule(name='myrule') |
| """); |
| reporter.removeHandler(failFastHandler); |
| |
| getConfiguredTarget("//foo:myrule"); |
| |
| assertContainsEvent("file '//foo:rule.bzl' cannot use private @_builtins API"); |
| } |
| |
| @Test |
| public void testGetRemoveDeadCodeFromJ2ObjcConfigurationForStarlarkIsPrivateApi() |
| throws Exception { |
| scratch.file( |
| "foo/rule.bzl", |
| """ |
| def _impl(ctx): |
| ctx.fragments.j2objc.remove_dead_code() |
| return [] |
| myrule = rule( |
| implementation=_impl, |
| fragments = ['j2objc'] |
| ) |
| """); |
| scratch.file( |
| "foo/BUILD", |
| """ |
| load(':rule.bzl', 'myrule') |
| myrule(name='myrule') |
| """); |
| reporter.removeHandler(failFastHandler); |
| |
| getConfiguredTarget("//foo:myrule"); |
| |
| assertContainsEvent("file '//foo:rule.bzl' cannot use private @_builtins API"); |
| } |
| |
| @Test |
| public void testJ2objcLibraryMigrationForStarlarkIsPrivateApi() throws Exception { |
| scratch.file( |
| "foo/rule.bzl", |
| """ |
| def _impl(ctx): |
| ctx.fragments.j2objc.j2objc_library_migration() |
| return [] |
| myrule = rule( |
| implementation=_impl, |
| fragments = ['j2objc'] |
| ) |
| """); |
| scratch.file( |
| "foo/BUILD", |
| """ |
| load(':rule.bzl', 'myrule') |
| myrule(name='myrule') |
| """); |
| reporter.removeHandler(failFastHandler); |
| |
| getConfiguredTarget("//foo:myrule"); |
| |
| assertContainsEvent("file \'//foo:rule.bzl\' cannot use private API"); |
| } |
| } |