@@ -3740,6 +3740,68 @@ public void testTemplateExpansionComputedSubstitutionWithUniquify() throws Excep
3740
3740
assertThat (substitutionsUnchecked ).isEqualTo (ImmutableMap .of ("exts" , "txt%%log%%exe%%sh" ));
3741
3741
}
3742
3742
3743
+ @ Test
3744
+ public void testTemplateExpansionComputedSubstitutionWithUniquifyAndListMapEach ()
3745
+ throws Exception {
3746
+ setBuildLanguageOptions ("--experimental_lazy_template_expansion" );
3747
+ scratch .file (
3748
+ "test/rules.bzl" ,
3749
+ "def _artifact_to_extension(file):" ,
3750
+ " if file.extension == 'sh':" ,
3751
+ " return [file.extension]" ,
3752
+ " return [file.extension, '.' + file.extension]" ,
3753
+ "" ,
3754
+ "def _undertest_impl(ctx):" ,
3755
+ " template_dict = ctx.actions.template_dict()" ,
3756
+ " template_dict.add_joined('exts', depset(ctx.files.srcs)," ,
3757
+ " map_each = _artifact_to_extension," ,
3758
+ " uniquify = True," ,
3759
+ " join_with = '%%'," ,
3760
+ " )" ,
3761
+ " ctx.actions.expand_template(output=ctx.outputs.out," ,
3762
+ " template=ctx.file.template," ,
3763
+ " computed_substitutions=template_dict," ,
3764
+ " )" ,
3765
+ "undertest_rule = rule(" ,
3766
+ " implementation = _undertest_impl," ,
3767
+ " outputs = {'out': '%{name}.txt'}," ,
3768
+ " attrs = {'template': attr.label(allow_single_file=True)," ,
3769
+ " 'srcs':attr.label_list(allow_files=True)" ,
3770
+ " }," ,
3771
+ " _skylark_testable = True," ,
3772
+ ")" ,
3773
+ testingRuleDefinition );
3774
+ scratch .file ("test/template.txt" , "exts" , "exts" );
3775
+ scratch .file (
3776
+ "test/BUILD" ,
3777
+ "load(':rules.bzl', 'undertest_rule', 'testing_rule')" ,
3778
+ "undertest_rule(" ,
3779
+ " name = 'undertest'," ,
3780
+ " template = ':template.txt'," ,
3781
+ " srcs = ['foo.txt', 'bar.log', 'baz.txt', 'bak.exe', 'far.sh', 'boo.sh']," ,
3782
+ ")" ,
3783
+ "testing_rule(" ,
3784
+ " name = 'testing'," ,
3785
+ " dep = ':undertest'," ,
3786
+ ")" );
3787
+ StarlarkRuleContext ruleContext = createRuleContext ("//test:testing" );
3788
+ setRuleContext (ruleContext );
3789
+ ev .update ("file" , ev .eval ("ruleContext.attr.dep.files.to_list()[0]" ));
3790
+ ev .update ("action" , ev .eval ("ruleContext.attr.dep[Actions].by_file[file]" ));
3791
+
3792
+ assertThat (ev .eval ("type(action)" )).isEqualTo ("Action" );
3793
+
3794
+ Object contentUnchecked = ev .eval ("action.content" );
3795
+ assertThat (contentUnchecked ).isInstanceOf (String .class );
3796
+ assertThat (contentUnchecked )
3797
+ .isEqualTo ("txt%%.txt%%log%%.log%%exe%%.exe%%sh\n txt%%.txt%%log%%.log%%exe%%.exe%%sh\n " );
3798
+
3799
+ Object substitutionsUnchecked = ev .eval ("action.substitutions" );
3800
+ assertThat (substitutionsUnchecked ).isInstanceOf (Dict .class );
3801
+ assertThat (substitutionsUnchecked )
3802
+ .isEqualTo (ImmutableMap .of ("exts" , "txt%%.txt%%log%%.log%%exe%%.exe%%sh" ));
3803
+ }
3804
+
3743
3805
@ Test
3744
3806
public void testTemplateExpansionComputedSubstitutionDuplicateKeys () throws Exception {
3745
3807
setBuildLanguageOptions ("--experimental_lazy_template_expansion" );
@@ -3912,8 +3974,60 @@ public void testTemplateExpansionComputedSubstitutionMapEachBadReturnType() thro
3912
3974
assertThat (evalException )
3913
3975
.hasMessageThat ()
3914
3976
.isEqualTo (
3915
- "Function provided to map_each must return a String or None, but returned "
3916
- + "type Label for key '%files%' and value: <source file test/template.txt>" );
3977
+ "Function provided to map_each must return string, None, or list of strings, "
3978
+ + "but returned type Label for key '%files%' and value: "
3979
+ + "File:[/workspace[source]]test/template.txt" );
3980
+ }
3981
+
3982
+ @ Test
3983
+ public void testTemplateExpansionComputedSubstitutionMapEachBadListReturnType () throws Exception {
3984
+ setBuildLanguageOptions ("--experimental_lazy_template_expansion" );
3985
+ scratch .file (
3986
+ "test/rules.bzl" ,
3987
+ "def file_to_owner_label(file):" ,
3988
+ " return [file.owner]" ,
3989
+ "" ,
3990
+ "def _undertest_impl(ctx):" ,
3991
+ " template_dict = ctx.actions.template_dict()" ,
3992
+ " template_dict.add_joined('%files%', depset(ctx.files.template)," ,
3993
+ " map_each = file_to_owner_label," ,
3994
+ " join_with = '')" ,
3995
+ " ctx.actions.expand_template(output=ctx.outputs.out," ,
3996
+ " template=ctx.file.template," ,
3997
+ " computed_substitutions=template_dict," ,
3998
+ " )" ,
3999
+ "undertest_rule = rule(" ,
4000
+ " implementation = _undertest_impl," ,
4001
+ " outputs = {'out': '%{name}.txt'}," ,
4002
+ " attrs = {'template': attr.label(allow_single_file=True),}," ,
4003
+ " _skylark_testable = True," ,
4004
+ ")" ,
4005
+ testingRuleDefinition );
4006
+ scratch .file ("test/template.txt" );
4007
+ scratch .file (
4008
+ "test/BUILD" ,
4009
+ "load(':rules.bzl', 'undertest_rule', 'testing_rule')" ,
4010
+ "undertest_rule(" ,
4011
+ " name = 'undertest'," ,
4012
+ " template = ':template.txt'," ,
4013
+ ")" ,
4014
+ "testing_rule(" ,
4015
+ " name = 'testing'," ,
4016
+ " dep = ':undertest'," ,
4017
+ ")" );
4018
+ StarlarkRuleContext ruleContext = createRuleContext ("//test:testing" );
4019
+ setRuleContext (ruleContext );
4020
+ ev .update ("file" , ev .eval ("ruleContext.attr.dep.files.to_list()[0]" ));
4021
+ ev .update ("action" , ev .eval ("ruleContext.attr.dep[Actions].by_file[file]" ));
4022
+
4023
+ EvalException evalException =
4024
+ assertThrows (EvalException .class , () -> ev .eval ("action.content" ));
4025
+ assertThat (evalException )
4026
+ .hasMessageThat ()
4027
+ .isEqualTo (
4028
+ "Function provided to map_each must return string, None, or list of strings, "
4029
+ + "but returned list containing element '//test:template.txt' of type Label for "
4030
+ + "key '%files%' and value: File:[/workspace[source]]test/template.txt" );
3917
4031
}
3918
4032
3919
4033
@ Test
0 commit comments