xref: /aosp_15_r20/external/bazelbuild-rules_cc/tools/migration/legacy_fields_migration_lib_test.py (revision eed53cd41c5909d05eedc7ad9720bb158fd93452)
1import unittest
2from google.protobuf import text_format
3from third_party.com.github.bazelbuild.bazel.src.main.protobuf import crosstool_config_pb2
4from tools.migration.legacy_fields_migration_lib import ALL_CC_COMPILE_ACTIONS
5from tools.migration.legacy_fields_migration_lib import ALL_OBJC_COMPILE_ACTIONS
6from tools.migration.legacy_fields_migration_lib import ALL_CXX_COMPILE_ACTIONS
7from tools.migration.legacy_fields_migration_lib import ALL_CC_LINK_ACTIONS
8from tools.migration.legacy_fields_migration_lib import ALL_OBJC_LINK_ACTIONS
9from tools.migration.legacy_fields_migration_lib import DYNAMIC_LIBRARY_LINK_ACTIONS
10from tools.migration.legacy_fields_migration_lib import NODEPS_DYNAMIC_LIBRARY_LINK_ACTIONS
11from tools.migration.legacy_fields_migration_lib import TRANSITIVE_LINK_ACTIONS
12from tools.migration.legacy_fields_migration_lib import TRANSITIVE_DYNAMIC_LIBRARY_LINK_ACTIONS
13from tools.migration.legacy_fields_migration_lib import CC_LINK_EXECUTABLE
14from tools.migration.legacy_fields_migration_lib import migrate_legacy_fields
15
16
17def assert_has_feature(self, toolchain, name):
18  self.assertTrue(any(feature.name == name for feature in toolchain.feature))
19
20
21def make_crosstool(string):
22  crosstool = crosstool_config_pb2.CrosstoolRelease()
23  text_format.Merge("major_version: '123' minor_version: '456'", crosstool)
24  toolchain = crosstool.toolchain.add()
25  text_format.Merge(string, toolchain)
26  return crosstool
27
28
29def migrate_to_string(crosstool):
30  migrate_legacy_fields(crosstool)
31  return to_string(crosstool)
32
33
34def to_string(crosstool):
35  return text_format.MessageToString(crosstool)
36
37
38class LegacyFieldsMigrationLibTest(unittest.TestCase):
39
40  def test_deletes_fields(self):
41    crosstool = make_crosstool("""
42          debian_extra_requires: 'debian-1'
43          gcc_plugin_compiler_flag: 'gcc_plugin_compiler_flag-1'
44          ar_flag: 'ar_flag-1'
45          ar_thin_archives_flag: 'ar_thin_archives_flag-1'
46          gcc_plugin_header_directory: 'gcc_plugin_header_directory-1'
47          mao_plugin_header_directory: 'mao_plugin_header_directory-1'
48          default_python_top: 'default_python_top-1'
49          default_python_version: 'default_python_version-1'
50          python_preload_swigdeps: false
51          supports_normalizing_ar: false
52          supports_thin_archives: false
53          supports_incremental_linker: false
54          supports_dsym: false
55          supports_gold_linker: false
56          needsPic: false
57          supports_start_end_lib: false
58          supports_interface_shared_objects: false
59          supports_fission: false
60          supports_embedded_runtimes: false
61          static_runtimes_filegroup: 'yolo'
62          dynamic_runtimes_filegroup: 'yolo'
63      """)
64    output = migrate_to_string(crosstool)
65    self.assertNotIn("debian_extra_requires", output)
66    self.assertNotIn("gcc_plugin_compiler_flag", output)
67    self.assertNotIn("ar_flag", output)
68    self.assertNotIn("ar_thin_archives_flag", output)
69    self.assertNotIn("gcc_plugin_header_directory", output)
70    self.assertNotIn("mao_plugin_header_directory", output)
71    self.assertNotIn("supports_normalizing_ar", output)
72    self.assertNotIn("supports_thin_archives", output)
73    self.assertNotIn("supports_incremental_linker", output)
74    self.assertNotIn("supports_dsym", output)
75    self.assertNotIn("default_python_top", output)
76    self.assertNotIn("default_python_version", output)
77    self.assertNotIn("python_preload_swigdeps", output)
78    self.assertNotIn("supports_gold_linker", output)
79    self.assertNotIn("needsPic", output)
80    self.assertNotIn("supports_start_end_lib", output)
81    self.assertNotIn("supports_interface_shared_objects", output)
82    self.assertNotIn("supports_fission", output)
83    self.assertNotIn("supports_embedded_runtimes", output)
84    self.assertNotIn("static_runtimes_filegroup", output)
85    self.assertNotIn("dynamic_runtimes_filegroup", output)
86
87  def test_deletes_default_toolchains(self):
88    crosstool = make_crosstool("")
89    crosstool.default_toolchain.add()
90    self.assertEqual(len(crosstool.default_toolchain), 1)
91    migrate_legacy_fields(crosstool)
92    self.assertEqual(len(crosstool.default_toolchain), 0)
93
94  def test_replace_legacy_compile_flags(self):
95    crosstool = make_crosstool("""
96        feature { name: 'foo' }
97        feature { name: 'legacy_compile_flags' }
98        compiler_flag: 'clang-flag-1'
99    """)
100    migrate_legacy_fields(crosstool)
101    output = crosstool.toolchain[0]
102    self.assertEqual(len(output.compiler_flag), 0)
103    self.assertEqual(output.feature[0].name, "foo")
104    self.assertEqual(output.feature[1].name, "default_compile_flags")
105    self.assertEqual(output.feature[1].flag_set[0].action,
106                     ALL_CC_COMPILE_ACTIONS)
107    self.assertEqual(output.feature[1].flag_set[0].flag_group[0].flag,
108                     ["clang-flag-1"])
109
110  def test_replace_legacy_compile_flags_in_action_configs(self):
111    crosstool = make_crosstool("""
112        feature {
113          name: 'foo'
114          implies: 'legacy_compile_flags'
115          requires: { feature: 'legacy_compile_flags' }
116          flag_set {
117            with_feature { feature: 'legacy_compile_flags' }
118            with_feature { not_feature: 'legacy_compile_flags' }
119          }
120          env_set {
121            with_feature { feature: 'legacy_compile_flags' }
122            with_feature { not_feature: 'legacy_compile_flags' }
123          }
124        }
125        feature { name: 'legacy_compile_flags' }
126        action_config {
127          action_name: 'foo'
128          config_name: 'foo'
129          implies: 'legacy_compile_flags'
130          requires: { feature: 'legacy_compile_flags' }
131          flag_set {
132            with_feature { feature: 'legacy_compile_flags' }
133            with_feature { not_feature: 'legacy_compile_flags' }
134          }
135          env_set {
136            with_feature { feature: 'legacy_compile_flags' }
137            with_feature { not_feature: 'legacy_compile_flags' }
138          }
139        }
140        compiler_flag: 'clang-flag-1'
141    """)
142    migrate_legacy_fields(crosstool)
143    output = crosstool.toolchain[0]
144    self.assertEqual(output.action_config[0].action_name, "foo")
145    self.assertEqual(output.action_config[0].implies, [])
146    self.assertEqual(output.action_config[0].requires[0].feature,
147                     ["default_compile_flags"])
148    self.assertEqual(
149        output.action_config[0].flag_set[0].with_feature[0].feature,
150        ["default_compile_flags"])
151    self.assertEqual(
152        output.action_config[0].flag_set[0].with_feature[1].not_feature,
153        ["default_compile_flags"])
154    self.assertEqual(output.action_config[0].env_set[0].with_feature[0].feature,
155                     ["default_compile_flags"])
156    self.assertEqual(
157        output.action_config[0].env_set[0].with_feature[1].not_feature,
158        ["default_compile_flags"])
159    self.assertEqual(output.feature[0].name, "foo")
160    self.assertEqual(output.feature[0].implies, [])
161    self.assertEqual(output.feature[0].requires[0].feature,
162                     ["default_compile_flags"])
163    self.assertEqual(output.feature[0].flag_set[0].with_feature[0].feature,
164                     ["default_compile_flags"])
165    self.assertEqual(output.feature[0].flag_set[0].with_feature[1].not_feature,
166                     ["default_compile_flags"])
167    self.assertEqual(output.feature[0].env_set[0].with_feature[0].feature,
168                     ["default_compile_flags"])
169    self.assertEqual(output.feature[0].env_set[0].with_feature[1].not_feature,
170                     ["default_compile_flags"])
171
172  def test_replace_legacy_link_flags(self):
173    crosstool = make_crosstool("""
174        feature { name: 'foo' }
175        feature { name: 'legacy_link_flags' }
176        linker_flag: 'ld-flag-1'
177    """)
178    migrate_legacy_fields(crosstool)
179    output = crosstool.toolchain[0]
180    self.assertEqual(len(output.compiler_flag), 0)
181    self.assertEqual(output.feature[0].name, "foo")
182    self.assertEqual(output.feature[1].name, "default_link_flags")
183    self.assertEqual(output.feature[1].flag_set[0].action, ALL_CC_LINK_ACTIONS)
184    self.assertEqual(output.feature[1].flag_set[0].flag_group[0].flag,
185                     ["ld-flag-1"])
186
187  def test_replace_legacy_link_flags_in_action_configs(self):
188    crosstool = make_crosstool("""
189        feature {
190          name: 'foo'
191          implies: 'legacy_link_flags'
192          requires: { feature: 'legacy_link_flags' }
193          flag_set {
194            with_feature { feature: 'legacy_link_flags' }
195            with_feature { not_feature: 'legacy_link_flags' }
196          }
197          env_set {
198            with_feature { feature: 'legacy_link_flags' }
199            with_feature { not_feature: 'legacy_link_flags' }
200          }
201        }
202        feature { name: 'legacy_link_flags' }
203        action_config {
204          action_name: 'foo'
205          config_name: 'foo'
206          implies: 'legacy_link_flags'
207          requires: { feature: 'legacy_link_flags' }
208          flag_set {
209            with_feature { feature: 'legacy_link_flags' }
210            with_feature { not_feature: 'legacy_link_flags' }
211          }
212          env_set {
213            with_feature { feature: 'legacy_link_flags' }
214            with_feature { not_feature: 'legacy_link_flags' }
215          }
216        }
217        linker_flag: 'clang-flag-1'
218    """)
219    migrate_legacy_fields(crosstool)
220    output = crosstool.toolchain[0]
221    self.assertEqual(output.action_config[0].action_name, "foo")
222    self.assertEqual(output.action_config[0].implies, [])
223    self.assertEqual(output.action_config[0].requires[0].feature,
224                     ["default_link_flags"])
225    self.assertEqual(
226        output.action_config[0].flag_set[0].with_feature[0].feature,
227        ["default_link_flags"])
228    self.assertEqual(
229        output.action_config[0].flag_set[0].with_feature[1].not_feature,
230        ["default_link_flags"])
231    self.assertEqual(output.action_config[0].env_set[0].with_feature[0].feature,
232                     ["default_link_flags"])
233    self.assertEqual(
234        output.action_config[0].env_set[0].with_feature[1].not_feature,
235        ["default_link_flags"])
236    self.assertEqual(output.feature[0].name, "foo")
237    self.assertEqual(output.feature[0].implies, [])
238    self.assertEqual(output.feature[0].requires[0].feature,
239                     ["default_link_flags"])
240    self.assertEqual(output.feature[0].flag_set[0].with_feature[0].feature,
241                     ["default_link_flags"])
242    self.assertEqual(output.feature[0].flag_set[0].with_feature[1].not_feature,
243                     ["default_link_flags"])
244    self.assertEqual(output.feature[0].env_set[0].with_feature[0].feature,
245                     ["default_link_flags"])
246    self.assertEqual(output.feature[0].env_set[0].with_feature[1].not_feature,
247                     ["default_link_flags"])
248
249
250  def test_migrate_compiler_flags(self):
251    crosstool = make_crosstool("""
252        compiler_flag: 'clang-flag-1'
253    """)
254    migrate_legacy_fields(crosstool)
255    output = crosstool.toolchain[0]
256    self.assertEqual(len(output.compiler_flag), 0)
257    self.assertEqual(output.feature[0].name, "default_compile_flags")
258    self.assertEqual(output.feature[0].flag_set[0].action, ALL_CC_COMPILE_ACTIONS)
259    self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag,
260                     ["clang-flag-1"])
261
262  def test_migrate_compiler_flags_for_objc(self):
263    crosstool = make_crosstool("""
264        action_config { action_name: "objc-compile" }
265        compiler_flag: 'clang-flag-1'
266    """)
267    migrate_legacy_fields(crosstool)
268    output = crosstool.toolchain[0]
269    self.assertEqual(len(output.compiler_flag), 0)
270    self.assertEqual(output.feature[0].name, "default_compile_flags")
271    self.assertEqual(output.feature[0].flag_set[0].action, ALL_CC_COMPILE_ACTIONS + ALL_OBJC_COMPILE_ACTIONS)
272    self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag,
273                     ["clang-flag-1"])
274
275  def test_migrate_cxx_flags(self):
276    crosstool = make_crosstool("""
277        cxx_flag: 'clang-flag-1'
278    """)
279    migrate_legacy_fields(crosstool)
280    output = crosstool.toolchain[0]
281    self.assertEqual(len(output.cxx_flag), 0)
282    self.assertEqual(output.feature[0].name, "default_compile_flags")
283    self.assertEqual(output.feature[0].flag_set[0].action,
284                     ALL_CXX_COMPILE_ACTIONS)
285    self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag,
286                     ["clang-flag-1"])
287
288  def test_compiler_flag_come_before_cxx_flags(self):
289    crosstool = make_crosstool("""
290        compiler_flag: 'clang-flag-1'
291        cxx_flag: 'clang-flag-2'
292    """)
293    migrate_legacy_fields(crosstool)
294    output = crosstool.toolchain[0]
295    self.assertEqual(output.feature[0].name, "default_compile_flags")
296    self.assertEqual(output.feature[0].flag_set[0].action, ALL_CC_COMPILE_ACTIONS)
297    self.assertEqual(output.feature[0].flag_set[1].action,
298                     ALL_CXX_COMPILE_ACTIONS)
299    self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag,
300                     ["clang-flag-1"])
301    self.assertEqual(output.feature[0].flag_set[1].flag_group[0].flag,
302                     ["clang-flag-2"])
303
304  def test_migrate_linker_flags(self):
305    crosstool = make_crosstool("""
306        linker_flag: 'linker-flag-1'
307    """)
308    migrate_legacy_fields(crosstool)
309    output = crosstool.toolchain[0]
310    self.assertEqual(len(output.linker_flag), 0)
311    self.assertEqual(output.feature[0].name, "default_link_flags")
312    self.assertEqual(output.feature[0].flag_set[0].action, ALL_CC_LINK_ACTIONS)
313    self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag,
314                     ["linker-flag-1"])
315
316  def test_migrate_dynamic_library_linker_flags(self):
317    crosstool = make_crosstool("""
318        dynamic_library_linker_flag: 'linker-flag-1'
319    """)
320    migrate_legacy_fields(crosstool)
321    output = crosstool.toolchain[0]
322    self.assertEqual(len(output.dynamic_library_linker_flag), 0)
323    self.assertEqual(output.feature[0].name, "default_link_flags")
324    self.assertEqual(output.feature[0].flag_set[0].action,
325                     DYNAMIC_LIBRARY_LINK_ACTIONS)
326    self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag,
327                     ["linker-flag-1"])
328
329  def test_compilation_mode_flags(self):
330    crosstool = make_crosstool("""
331        compiler_flag: "compile-flag-1"
332        cxx_flag: "cxx-flag-1"
333        linker_flag: "linker-flag-1"
334        compilation_mode_flags {
335          mode: OPT
336          compiler_flag: "opt-flag-1"
337          cxx_flag: "opt-flag-2"
338          linker_flag: "opt-flag-3"
339        }
340    """)
341    migrate_legacy_fields(crosstool)
342    output = crosstool.toolchain[0]
343    self.assertEqual(len(output.compilation_mode_flags), 0)
344    assert_has_feature(self, output, "opt")
345
346    self.assertEqual(output.feature[0].name, "default_compile_flags")
347    self.assertEqual(output.feature[1].name, "default_link_flags")
348
349    # flag set for compiler_flag fields
350    self.assertEqual(len(output.feature[0].flag_set[0].with_feature), 0)
351    self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag,
352                     ["compile-flag-1"])
353
354    # flag set for compiler_flag from compilation_mode_flags
355    self.assertEqual(len(output.feature[0].flag_set[1].with_feature), 1)
356    self.assertEqual(output.feature[0].flag_set[1].with_feature[0].feature[0],
357                     "opt")
358    self.assertEqual(output.feature[0].flag_set[1].flag_group[0].flag,
359                     ["opt-flag-1"])
360
361    # flag set for cxx_flag fields
362    self.assertEqual(len(output.feature[0].flag_set[2].with_feature), 0)
363    self.assertEqual(output.feature[0].flag_set[2].flag_group[0].flag,
364                     ["cxx-flag-1"])
365
366    # flag set for cxx_flag from compilation_mode_flags
367    self.assertEqual(len(output.feature[0].flag_set[3].with_feature), 1)
368    self.assertEqual(output.feature[0].flag_set[3].with_feature[0].feature[0],
369                     "opt")
370    self.assertEqual(output.feature[0].flag_set[3].flag_group[0].flag,
371                     ["opt-flag-2"])
372
373    # default_link_flags, flag set for linker_flag
374    self.assertEqual(len(output.feature[1].flag_set[0].with_feature), 0)
375    self.assertEqual(output.feature[1].flag_set[0].flag_group[0].flag,
376                     ["linker-flag-1"])
377
378    # default_link_flags, flag set for linker_flag from
379    # compilation_mode_flags
380    self.assertEqual(len(output.feature[1].flag_set[1].with_feature), 1)
381    self.assertEqual(output.feature[1].flag_set[1].with_feature[0].feature[0],
382                     "opt")
383    self.assertEqual(output.feature[1].flag_set[1].flag_group[0].flag,
384                     ["opt-flag-3"])
385
386  def test_linking_mode_flags(self):
387    crosstool = make_crosstool("""
388        linker_flag: "linker-flag-1"
389        compilation_mode_flags {
390          mode: DBG
391          linker_flag: "dbg-flag-1"
392        }
393        linking_mode_flags {
394          mode: MOSTLY_STATIC
395          linker_flag: "mostly-static-flag-1"
396        }
397        """)
398    migrate_legacy_fields(crosstool)
399    output = crosstool.toolchain[0]
400    self.assertEqual(len(output.compilation_mode_flags), 0)
401    self.assertEqual(len(output.linking_mode_flags), 0)
402
403    # flag set for linker_flag
404    self.assertEqual(len(output.feature[0].flag_set[0].with_feature), 0)
405    self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag,
406                     ["linker-flag-1"])
407
408    # flag set for compilation_mode_flags
409    self.assertEqual(len(output.feature[0].flag_set[1].with_feature), 1)
410    self.assertEqual(output.feature[0].flag_set[1].with_feature[0].feature[0],
411                     "dbg")
412    self.assertEqual(output.feature[0].flag_set[1].flag_group[0].flag,
413                     ["dbg-flag-1"])
414
415    # flag set for linking_mode_flags
416    self.assertEqual(len(output.feature[0].flag_set[2].with_feature), 1)
417    self.assertEqual(output.feature[0].flag_set[2].action, CC_LINK_EXECUTABLE)
418    self.assertEqual(output.feature[0].flag_set[2].with_feature[0].feature[0],
419                     "static_linking_mode")
420    self.assertEqual(output.feature[0].flag_set[2].flag_group[0].flag,
421                     ["mostly-static-flag-1"])
422
423  def test_coverage_compilation_mode_ignored(self):
424    crosstool = make_crosstool("""
425    compilation_mode_flags {
426      mode: COVERAGE
427      compiler_flag: "coverage-flag-1"
428      cxx_flag: "coverage-flag-2"
429      linker_flag: "coverage-flag-3"
430    }
431    """)
432    output = migrate_to_string(crosstool)
433    self.assertNotIn("compilation_mode_flags", output)
434    self.assertNotIn("coverage-flag-1", output)
435    self.assertNotIn("coverage-flag-2", output)
436    self.assertNotIn("coverage-flag-3", output)
437    self.assertNotIn("COVERAGE", output)
438
439  def test_supports_dynamic_linker_when_dynamic_library_linker_flag_is_used(
440      self):
441    crosstool = make_crosstool("""
442        dynamic_library_linker_flag: "foo"
443    """)
444    migrate_legacy_fields(crosstool)
445    output = crosstool.toolchain[0]
446    self.assertEqual(output.feature[0].name, "default_link_flags")
447    self.assertEqual(output.feature[1].name, "supports_dynamic_linker")
448    self.assertEqual(output.feature[1].enabled, True)
449
450  def test_supports_dynamic_linker_is_added_when_DYNAMIC_present(self):
451    crosstool = make_crosstool("""
452    linking_mode_flags {
453      mode: DYNAMIC
454    }
455    """)
456    migrate_legacy_fields(crosstool)
457    output = crosstool.toolchain[0]
458    self.assertEqual(output.feature[0].name, "supports_dynamic_linker")
459    self.assertEqual(output.feature[0].enabled, True)
460
461  def test_supports_dynamic_linker_is_not_added_when_present(self):
462    crosstool = make_crosstool("""
463    feature { name: "supports_dynamic_linker" enabled: false }
464    """)
465    migrate_legacy_fields(crosstool)
466    output = crosstool.toolchain[0]
467    self.assertEqual(output.feature[0].name, "supports_dynamic_linker")
468    self.assertEqual(output.feature[0].enabled, False)
469
470  def test_all_linker_flag_ordering(self):
471    crosstool = make_crosstool("""
472    linker_flag: 'linker-flag-1'
473    compilation_mode_flags {
474        mode: OPT
475        linker_flag: 'cmf-flag-2'
476    }
477    linking_mode_flags {
478      mode: MOSTLY_STATIC
479      linker_flag: 'lmf-flag-3'
480    }
481    linking_mode_flags {
482      mode: DYNAMIC
483      linker_flag: 'lmf-dynamic-flag-4'
484    }
485    dynamic_library_linker_flag: 'dl-flag-5'
486    test_only_linker_flag: 'to-flag-6'
487    """)
488    migrate_legacy_fields(crosstool)
489    output = crosstool.toolchain[0]
490    self.assertEqual(output.feature[0].name, "default_link_flags")
491    self.assertEqual(output.feature[0].enabled, True)
492    self.assertEqual(output.feature[0].flag_set[0].action[:], ALL_CC_LINK_ACTIONS)
493    self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag[:],
494                     ["linker-flag-1"])
495
496    self.assertEqual(output.feature[0].flag_set[1].action[:], ALL_CC_LINK_ACTIONS)
497    self.assertEqual(output.feature[0].flag_set[1].with_feature[0].feature[0],
498                     "opt")
499    self.assertEqual(output.feature[0].flag_set[1].flag_group[0].flag,
500                     ["cmf-flag-2"])
501
502    self.assertEqual(output.feature[0].flag_set[2].action, CC_LINK_EXECUTABLE)
503    self.assertEqual(output.feature[0].flag_set[2].with_feature[0].feature[0],
504                     "static_linking_mode")
505    self.assertEqual(output.feature[0].flag_set[2].flag_group[0].flag,
506                     ["lmf-flag-3"])
507
508    self.assertEqual(len(output.feature[0].flag_set[3].with_feature), 0)
509    self.assertEqual(output.feature[0].flag_set[3].flag_group[0].flag,
510                     ["lmf-dynamic-flag-4"])
511    self.assertEqual(output.feature[0].flag_set[3].action,
512                     NODEPS_DYNAMIC_LIBRARY_LINK_ACTIONS)
513
514    self.assertEqual(
515        output.feature[0].flag_set[4].with_feature[0].not_feature[0],
516        "static_link_cpp_runtimes")
517    self.assertEqual(output.feature[0].flag_set[4].flag_group[0].flag,
518                     ["lmf-dynamic-flag-4"])
519    self.assertEqual(output.feature[0].flag_set[4].action,
520                     TRANSITIVE_DYNAMIC_LIBRARY_LINK_ACTIONS)
521
522    self.assertEqual(output.feature[0].flag_set[5].with_feature[0].feature[0],
523                     "dynamic_linking_mode")
524    self.assertEqual(output.feature[0].flag_set[5].flag_group[0].flag,
525                     ["lmf-dynamic-flag-4"])
526    self.assertEqual(output.feature[0].flag_set[5].action,
527                     CC_LINK_EXECUTABLE)
528
529    self.assertEqual(output.feature[0].flag_set[6].flag_group[0].flag,
530                     ["dl-flag-5"])
531    self.assertEqual(output.feature[0].flag_set[6].action,
532                     DYNAMIC_LIBRARY_LINK_ACTIONS)
533
534    self.assertEqual(output.feature[0].flag_set[7].flag_group[0].flag,
535                     ["to-flag-6"])
536    self.assertEqual(output.feature[0].flag_set[7].action, ALL_CC_LINK_ACTIONS)
537    self.assertEqual(
538        output.feature[0].flag_set[7].flag_group[0].expand_if_all_available,
539        ["is_cc_test"])
540
541  def test_all_linker_flag_objc_actions(self):
542    crosstool = make_crosstool("""
543    action_config { action_name: "objc-compile" }
544    linker_flag: 'linker-flag-1'
545    compilation_mode_flags {
546        mode: OPT
547        linker_flag: 'cmf-flag-2'
548    }
549    linking_mode_flags {
550      mode: MOSTLY_STATIC
551      linker_flag: 'lmf-flag-3'
552    }
553    dynamic_library_linker_flag: 'dl-flag-5'
554    test_only_linker_flag: 'to-flag-6'
555    """)
556    migrate_legacy_fields(crosstool)
557    output = crosstool.toolchain[0]
558    self.assertEqual(output.feature[0].name, "default_link_flags")
559    self.assertEqual(output.feature[0].flag_set[0].action[:],
560                     ALL_CC_LINK_ACTIONS + ALL_OBJC_LINK_ACTIONS)
561    self.assertEqual(output.feature[0].flag_set[1].action[:],
562                     ALL_CC_LINK_ACTIONS + ALL_OBJC_LINK_ACTIONS)
563    self.assertEqual(output.feature[0].flag_set[2].action[:],
564                     CC_LINK_EXECUTABLE)
565    self.assertEqual(output.feature[0].flag_set[3].action[:],
566                     DYNAMIC_LIBRARY_LINK_ACTIONS)
567    self.assertEqual(output.feature[0].flag_set[4].action[:],
568                     ALL_CC_LINK_ACTIONS + ALL_OBJC_LINK_ACTIONS)
569
570  def test_linking_mode_features_are_not_added_when_present(self):
571    crosstool = make_crosstool("""
572    linking_mode_flags {
573      mode: DYNAMIC
574      linker_flag: 'dynamic-flag'
575    }
576    linking_mode_flags {
577      mode: FULLY_STATIC
578      linker_flag: 'fully-static-flag'
579    }
580    linking_mode_flags {
581      mode: MOSTLY_STATIC
582      linker_flag: 'mostly-static-flag'
583    }
584    linking_mode_flags {
585      mode: MOSTLY_STATIC_LIBRARIES
586      linker_flag: 'mostly-static-libraries-flag'
587    }
588    feature { name: "static_linking_mode" }
589    feature { name: "dynamic_linking_mode" }
590    feature { name: "static_linking_mode_nodeps_library" }
591    feature { name: "fully_static_link" }
592    """)
593    output = migrate_to_string(crosstool)
594    self.assertNotIn("linking_mode_flags", output)
595    self.assertNotIn("DYNAMIC", output)
596    self.assertNotIn("MOSTLY_STATIC", output)
597    self.assertNotIn("MOSTLY_STATIC_LIBRARIES", output)
598    self.assertNotIn("MOSTLY_STATIC_LIBRARIES", output)
599    self.assertNotIn("dynamic-flag", output)
600    self.assertNotIn("fully-static-flag", output)
601    self.assertNotIn("mostly-static-flag", output)
602    self.assertNotIn("mostly-static-libraries-flag", output)
603
604  def test_unfiltered_require_user_compile_flags_and_sysroot(self):
605    crosstool = make_crosstool("""
606      feature { name: 'preexisting_feature' }
607      unfiltered_cxx_flag: 'unfiltered-flag-1'
608    """)
609    migrate_legacy_fields(crosstool)
610    output = crosstool.toolchain[0]
611    # all these features are added after features that are already present in
612    # the crosstool
613    self.assertEqual(output.feature[0].name, "preexisting_feature")
614    self.assertEqual(output.feature[1].name, "user_compile_flags")
615    self.assertEqual(output.feature[2].name, "sysroot")
616    self.assertEqual(output.feature[3].name, "unfiltered_compile_flags")
617
618  def test_user_compile_flags_not_migrated_when_present(self):
619    crosstool = make_crosstool("""
620      unfiltered_cxx_flag: 'unfiltered-flag-1'
621      feature { name: 'user_compile_flags' }
622      feature { name: 'preexisting_feature' }
623    """)
624    migrate_legacy_fields(crosstool)
625    output = crosstool.toolchain[0]
626    self.assertEqual(output.feature[0].name, "user_compile_flags")
627    self.assertEqual(output.feature[1].name, "preexisting_feature")
628    self.assertEqual(output.feature[2].name, "sysroot")
629    self.assertEqual(output.feature[3].name, "unfiltered_compile_flags")
630
631  def test_sysroot_not_migrated_when_present(self):
632    crosstool = make_crosstool("""
633      unfiltered_cxx_flag: 'unfiltered-flag-1'
634      feature { name: 'sysroot' }
635      feature { name: 'preexisting_feature' }
636    """)
637    migrate_legacy_fields(crosstool)
638    output = crosstool.toolchain[0]
639    self.assertEqual(output.feature[0].name, "sysroot")
640    self.assertEqual(output.feature[1].name, "preexisting_feature")
641    self.assertEqual(output.feature[2].name, "user_compile_flags")
642    self.assertEqual(output.feature[3].name, "unfiltered_compile_flags")
643
644  def test_user_compile_flags(self):
645    crosstool = make_crosstool("""
646      unfiltered_cxx_flag: 'unfiltered-flag-1'
647    """)
648    migrate_legacy_fields(crosstool)
649    output = crosstool.toolchain[0]
650    self.assertEqual(output.feature[0].name, "user_compile_flags")
651    self.assertEqual(output.feature[0].enabled, True)
652    self.assertEqual(output.feature[0].flag_set[0].action,
653                     ALL_CC_COMPILE_ACTIONS)
654    self.assertEqual(
655        output.feature[0].flag_set[0].flag_group[0].expand_if_all_available,
656        ["user_compile_flags"])
657    self.assertEqual(output.feature[0].flag_set[0].flag_group[0].iterate_over,
658                     "user_compile_flags")
659    self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag,
660                     ["%{user_compile_flags}"])
661
662  def test_sysroot(self):
663    sysroot_actions = ALL_CC_COMPILE_ACTIONS + ALL_CC_LINK_ACTIONS
664    sysroot_actions.remove("assemble")
665    self.assertTrue("assemble" not in sysroot_actions)
666    crosstool = make_crosstool("""
667      unfiltered_cxx_flag: 'unfiltered-flag-1'
668    """)
669    migrate_legacy_fields(crosstool)
670    output = crosstool.toolchain[0]
671    self.assertEqual(output.feature[1].name, "sysroot")
672    self.assertEqual(output.feature[1].enabled, True)
673    self.assertEqual(output.feature[1].flag_set[0].action, sysroot_actions)
674    self.assertEqual(
675        output.feature[1].flag_set[0].flag_group[0].expand_if_all_available,
676        ["sysroot"])
677    self.assertEqual(output.feature[1].flag_set[0].flag_group[0].flag,
678                     ["--sysroot=%{sysroot}"])
679
680  def test_unfiltered_compile_flags_is_not_added_when_already_present(self):
681    crosstool = make_crosstool("""
682            unfiltered_cxx_flag: 'unfiltered-flag-1'
683            feature { name: 'something_else' }
684            feature { name: 'unfiltered_compile_flags' }
685            feature { name: 'something_else_2' }
686        """)
687    migrate_legacy_fields(crosstool)
688    output = crosstool.toolchain[0]
689    self.assertEqual(output.feature[0].name, "something_else")
690    self.assertEqual(output.feature[1].name, "unfiltered_compile_flags")
691    self.assertEqual(len(output.feature[1].flag_set), 0)
692    self.assertEqual(output.feature[2].name, "something_else_2")
693
694  def test_unfiltered_compile_flags_is_not_edited_if_old_variant_present(self):
695    crosstool = make_crosstool("""
696            unfiltered_cxx_flag: 'unfiltered-flag-1'
697            feature {
698              name: 'unfiltered_compile_flags'
699              flag_set {
700                action: 'c-compile'
701                flag_group {
702                  flag: 'foo-flag-1'
703                }
704              }
705            }
706        """)
707    migrate_legacy_fields(crosstool)
708    output = crosstool.toolchain[0]
709    self.assertEqual(output.feature[0].name, "unfiltered_compile_flags")
710    self.assertEqual(len(output.feature[0].flag_set), 1)
711    self.assertEqual(output.feature[0].flag_set[0].action, ["c-compile"])
712    self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag,
713                     ["foo-flag-1"])
714
715  def test_use_of_unfiltered_compile_flags_var_is_removed_and_replaced(self):
716    crosstool = make_crosstool("""
717            unfiltered_cxx_flag: 'unfiltered-flag-1'
718            feature {
719              name: 'unfiltered_compile_flags'
720              flag_set {
721                action: 'c-compile'
722                flag_group {
723                  flag: 'foo-flag-1'
724                }
725              }
726              flag_set {
727                action: 'c++-compile'
728                flag_group {
729                  flag: 'bar-flag-1'
730                }
731                flag_group {
732                  expand_if_all_available: 'unfiltered_compile_flags'
733                  iterate_over: 'unfiltered_compile_flags'
734                  flag: '%{unfiltered_compile_flags}'
735                }
736                flag_group {
737                  flag: 'bar-flag-2'
738                }
739              }
740              flag_set {
741                action: 'c-compile'
742                flag_group {
743                  flag: 'foo-flag-2'
744                }
745              }
746            }
747        """)
748    migrate_legacy_fields(crosstool)
749    output = crosstool.toolchain[0]
750    self.assertEqual(output.feature[0].name, "unfiltered_compile_flags")
751    self.assertEqual(output.feature[0].flag_set[0].action, ["c-compile"])
752    self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag,
753                     ["foo-flag-1"])
754    self.assertEqual(output.feature[0].flag_set[1].action, ["c++-compile"])
755    self.assertEqual(output.feature[0].flag_set[1].flag_group[0].flag,
756                     ["bar-flag-1"])
757    self.assertEqual(output.feature[0].flag_set[1].flag_group[1].flag,
758                     ["unfiltered-flag-1"])
759    self.assertEqual(output.feature[0].flag_set[1].flag_group[2].flag,
760                     ["bar-flag-2"])
761    self.assertEqual(output.feature[0].flag_set[2].action, ["c-compile"])
762    self.assertEqual(output.feature[0].flag_set[2].flag_group[0].flag,
763                     ["foo-flag-2"])
764
765  def test_unfiltered_compile_flags_is_added_at_the_end(self):
766    crosstool = make_crosstool("""
767            feature { name: 'something_else' }
768            unfiltered_cxx_flag: 'unfiltered-flag-1'
769        """)
770    migrate_legacy_fields(crosstool)
771    output = crosstool.toolchain[0]
772    self.assertEqual(output.feature[0].name, "something_else")
773    self.assertEqual(output.feature[1].name, "user_compile_flags")
774    self.assertEqual(output.feature[2].name, "sysroot")
775    self.assertEqual(output.feature[3].name, "unfiltered_compile_flags")
776    self.assertEqual(output.feature[3].flag_set[0].action,
777                     ALL_CC_COMPILE_ACTIONS)
778    self.assertEqual(output.feature[3].flag_set[0].flag_group[0].flag,
779                     ["unfiltered-flag-1"])
780
781  def test_unfiltered_compile_flags_are_not_added_for_objc(self):
782    crosstool = make_crosstool("""
783        action_config { action_name: "obc-compile" }
784        feature { name: 'something_else' }
785        unfiltered_cxx_flag: 'unfiltered-flag-1'
786    """)
787    migrate_legacy_fields(crosstool)
788    output = crosstool.toolchain[0]
789    self.assertEqual(output.feature[3].name, "unfiltered_compile_flags")
790    self.assertEqual(output.feature[3].flag_set[0].action,
791                     ALL_CC_COMPILE_ACTIONS)
792    self.assertEqual(output.feature[3].flag_set[0].flag_group[0].flag,
793                     ["unfiltered-flag-1"])
794
795  def test_default_link_flags_is_added_first(self):
796    crosstool = make_crosstool("""
797          linker_flag: 'linker-flag-1'
798          feature { name: 'something_else' }
799        """)
800    migrate_legacy_fields(crosstool)
801    output = crosstool.toolchain[0]
802    self.assertEqual(output.feature[0].name, "default_link_flags")
803    self.assertEqual(output.feature[0].enabled, True)
804    self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag,
805                     ["linker-flag-1"])
806
807  def test_default_link_flags_is_not_added_when_already_present(self):
808    crosstool = make_crosstool("""
809            linker_flag: 'linker-flag-1'
810            feature { name: 'something_else' }
811            feature { name: 'default_link_flags' }
812        """)
813    migrate_legacy_fields(crosstool)
814    output = crosstool.toolchain[0]
815    self.assertEqual(output.feature[0].name, "something_else")
816    self.assertEqual(output.feature[1].name, "default_link_flags")
817
818  def test_default_compile_flags_is_not_added_when_no_reason_to(self):
819    crosstool = make_crosstool("""
820          feature { name: 'something_else' }
821        """)
822    migrate_legacy_fields(crosstool)
823    output = crosstool.toolchain[0]
824    self.assertEqual(output.feature[0].name, "something_else")
825    self.assertEqual(len(output.feature), 1)
826
827  def test_default_compile_flags_is_first(self):
828    crosstool = make_crosstool("""
829          compiler_flag: 'compiler-flag-1'
830          feature { name: 'something_else' }
831        """)
832    migrate_legacy_fields(crosstool)
833    output = crosstool.toolchain[0]
834    self.assertEqual(output.feature[0].name, "default_compile_flags")
835    self.assertEqual(output.feature[0].enabled, True)
836    self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag,
837                     ["compiler-flag-1"])
838
839  def test_default_compile_flags_not_added_when_present(self):
840    crosstool = make_crosstool("""
841          compiler_flag: 'compiler-flag-1'
842          feature { name: 'something_else' }
843          feature { name: 'default_compile_flags' }
844        """)
845    migrate_legacy_fields(crosstool)
846    output = crosstool.toolchain[0]
847    self.assertEqual(output.feature[0].name, "something_else")
848    self.assertEqual(output.feature[1].name, "default_compile_flags")
849    self.assertEqual(len(output.feature[1].flag_set), 0)
850
851  def test_supports_start_end_lib_migrated(self):
852    crosstool = make_crosstool("supports_start_end_lib: true")
853    migrate_legacy_fields(crosstool)
854    output = crosstool.toolchain[0]
855    self.assertEqual(output.feature[0].name, "supports_start_end_lib")
856    self.assertEqual(output.feature[0].enabled, True)
857
858  def test_supports_start_end_lib_not_migrated_on_false(self):
859    crosstool = make_crosstool("supports_start_end_lib: false")
860    migrate_legacy_fields(crosstool)
861    output = crosstool.toolchain[0]
862    self.assertEqual(len(output.feature), 0)
863
864  def test_supports_start_end_lib_not_migrated_when_already_present(self):
865    crosstool = make_crosstool("""
866            supports_start_end_lib: true
867            feature { name: "supports_start_end_lib" enabled: false }
868        """)
869    migrate_legacy_fields(crosstool)
870    output = crosstool.toolchain[0]
871    self.assertEqual(output.feature[0].name, "supports_start_end_lib")
872    self.assertEqual(output.feature[0].enabled, False)
873
874  def test_supports_interface_shared_libraries_migrated(self):
875    crosstool = make_crosstool("supports_interface_shared_objects: true")
876    migrate_legacy_fields(crosstool)
877    output = crosstool.toolchain[0]
878    self.assertEqual(output.feature[0].name,
879                     "supports_interface_shared_libraries")
880    self.assertEqual(output.feature[0].enabled, True)
881
882  def test_supports_interface_shared_libraries_not_migrated_on_false(self):
883    crosstool = make_crosstool("supports_interface_shared_objects: false")
884    migrate_legacy_fields(crosstool)
885    output = crosstool.toolchain[0]
886    self.assertEqual(len(output.feature), 0)
887
888  def test_supports_interface_shared_libraries_not_migrated_when_present(self):
889    crosstool = make_crosstool("""
890            supports_interface_shared_objects: true
891            feature {
892              name: "supports_interface_shared_libraries"
893              enabled: false }
894        """)
895    migrate_legacy_fields(crosstool)
896    output = crosstool.toolchain[0]
897    self.assertEqual(output.feature[0].name,
898                     "supports_interface_shared_libraries")
899    self.assertEqual(output.feature[0].enabled, False)
900
901  def test_supports_embedded_runtimes_migrated(self):
902    crosstool = make_crosstool("supports_embedded_runtimes: true")
903    migrate_legacy_fields(crosstool)
904    output = crosstool.toolchain[0]
905    self.assertEqual(output.feature[0].name, "static_link_cpp_runtimes")
906    self.assertEqual(output.feature[0].enabled, True)
907
908  def test_supports_embedded_runtimes_not_migrated_on_false(self):
909    crosstool = make_crosstool("supports_embedded_runtimes: false")
910    migrate_legacy_fields(crosstool)
911    output = crosstool.toolchain[0]
912    self.assertEqual(len(output.feature), 0)
913
914  def test_supports_embedded_runtimes_not_migrated_when_already_present(self):
915    crosstool = make_crosstool("""
916            supports_embedded_runtimes: true
917            feature { name: "static_link_cpp_runtimes" enabled: false }
918        """)
919    migrate_legacy_fields(crosstool)
920    output = crosstool.toolchain[0]
921    self.assertEqual(output.feature[0].name, "static_link_cpp_runtimes")
922    self.assertEqual(output.feature[0].enabled, False)
923
924  def test_needs_pic_migrated(self):
925    crosstool = make_crosstool("needsPic: true")
926    migrate_legacy_fields(crosstool)
927    output = crosstool.toolchain[0]
928    self.assertEqual(output.feature[0].name, "supports_pic")
929    self.assertEqual(output.feature[0].enabled, True)
930
931  def test_needs_pic_not_migrated_on_false(self):
932    crosstool = make_crosstool("needsPic: false")
933    migrate_legacy_fields(crosstool)
934    output = crosstool.toolchain[0]
935    self.assertEqual(len(output.feature), 0)
936
937  def test_needs_pic_not_migrated_when_already_present(self):
938    crosstool = make_crosstool("""
939            needsPic: true
940            feature { name: "supports_pic" enabled: false }
941        """)
942    migrate_legacy_fields(crosstool)
943    output = crosstool.toolchain[0]
944    self.assertEqual(output.feature[0].name, "supports_pic")
945    self.assertEqual(output.feature[0].enabled, False)
946
947  def test_supports_fission_migrated(self):
948    crosstool = make_crosstool("supports_fission: true")
949    migrate_legacy_fields(crosstool)
950    output = crosstool.toolchain[0]
951    self.assertEqual(output.feature[0].name, "per_object_debug_info")
952    self.assertEqual(output.feature[0].enabled, True)
953    self.assertEqual(
954        output.feature[0].flag_set[0].flag_group[0].expand_if_all_available,
955        ["is_using_fission"])
956
957  def test_supports_fission_not_migrated_on_false(self):
958    crosstool = make_crosstool("supports_fission: false")
959    migrate_legacy_fields(crosstool)
960    output = crosstool.toolchain[0]
961    self.assertEqual(len(output.feature), 0)
962
963  def test_supports_fission_not_migrated_when_already_present(self):
964    crosstool = make_crosstool("""
965            supports_fission: true
966            feature { name: "per_object_debug_info" enabled: false }
967        """)
968    migrate_legacy_fields(crosstool)
969    output = crosstool.toolchain[0]
970    self.assertEqual(output.feature[0].name, "per_object_debug_info")
971    self.assertEqual(output.feature[0].enabled, False)
972
973  def test_migrating_objcopy_embed_flag(self):
974    crosstool = make_crosstool("""
975            tool_path { name: "objcopy" path: "foo/objcopy" }
976            objcopy_embed_flag: "a"
977            objcopy_embed_flag: "b"
978        """)
979    migrate_legacy_fields(crosstool)
980    output = crosstool.toolchain[0]
981    self.assertEqual(output.feature[0].name, "objcopy_embed_flags")
982    self.assertEqual(output.feature[0].enabled, True)
983    self.assertEqual(output.feature[0].flag_set[0].action[:],
984                     ["objcopy_embed_data"])
985    self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag[:],
986                     ["a", "b"])
987    self.assertEqual(len(output.objcopy_embed_flag), 0)
988    self.assertEqual(output.action_config[0].action_name, "objcopy_embed_data")
989    self.assertEqual(output.action_config[0].tool[0].tool_path, "foo/objcopy")
990
991  def test_not_migrating_objcopy_embed_flag_when_feature_present(self):
992    crosstool = make_crosstool("""
993            objcopy_embed_flag: "a"
994            objcopy_embed_flag: "b"
995            feature { name: "objcopy_embed_flags" }
996        """)
997    migrate_legacy_fields(crosstool)
998    output = crosstool.toolchain[0]
999    self.assertEqual(output.feature[0].name, "objcopy_embed_flags")
1000    self.assertEqual(output.feature[0].enabled, False)
1001
1002  def test_migrating_ld_embed_flag(self):
1003    crosstool = make_crosstool("""
1004            tool_path { name: "ld" path: "foo/ld" }
1005            ld_embed_flag: "a"
1006            ld_embed_flag: "b"
1007        """)
1008    migrate_legacy_fields(crosstool)
1009    output = crosstool.toolchain[0]
1010    self.assertEqual(output.feature[0].name, "ld_embed_flags")
1011    self.assertEqual(output.feature[0].enabled, True)
1012    self.assertEqual(output.feature[0].flag_set[0].action[:], ["ld_embed_data"])
1013    self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag[:],
1014                     ["a", "b"])
1015    self.assertEqual(len(output.ld_embed_flag), 0)
1016    self.assertEqual(output.action_config[0].action_name, "ld_embed_data")
1017    self.assertEqual(output.action_config[0].tool[0].tool_path, "foo/ld")
1018
1019  def test_not_migrating_objcopy_embed_flag_when_feature_present(self):
1020    crosstool = make_crosstool("""
1021            objcopy_embed_flag: "a"
1022            objcopy_embed_flag: "b"
1023            feature { name: "objcopy_embed_flags" }
1024        """)
1025    migrate_legacy_fields(crosstool)
1026    output = crosstool.toolchain[0]
1027    self.assertEqual(output.feature[0].name, "objcopy_embed_flags")
1028    self.assertEqual(output.feature[0].enabled, False)
1029
1030  def test_migrate_expand_if_all_available_from_flag_sets(self):
1031    crosstool = make_crosstool("""
1032        action_config {
1033          action_name: 'something'
1034          config_name: 'something'
1035          flag_set {
1036            expand_if_all_available: 'foo'
1037            flag_group {
1038              flag: '%{foo}'
1039            }
1040            flag_group {
1041              flag: 'bar'
1042            }
1043          }
1044        }
1045        feature {
1046          name: 'something_else'
1047          flag_set {
1048            action: 'c-compile'
1049            expand_if_all_available: 'foo'
1050            flag_group {
1051              flag: '%{foo}'
1052            }
1053            flag_group {
1054              flag: 'bar'
1055            }
1056          }
1057        }
1058        """)
1059    migrate_legacy_fields(crosstool)
1060    output = crosstool.toolchain[0]
1061    self.assertEqual(output.action_config[0].action_name, "something")
1062    self.assertEqual(len(output.action_config[0].flag_set), 1)
1063    self.assertEqual(
1064        len(output.action_config[0].flag_set[0].expand_if_all_available), 0)
1065    self.assertEqual(len(output.action_config[0].flag_set[0].flag_group), 2)
1066    self.assertEqual(
1067        output.action_config[0].flag_set[0].flag_group[0]
1068        .expand_if_all_available, ["foo"])
1069    self.assertEqual(
1070        output.action_config[0].flag_set[0].flag_group[1]
1071        .expand_if_all_available, ["foo"])
1072
1073    self.assertEqual(output.feature[0].name, "something_else")
1074    self.assertEqual(len(output.feature[0].flag_set), 1)
1075    self.assertEqual(
1076        len(output.feature[0].flag_set[0].expand_if_all_available), 0)
1077    self.assertEqual(len(output.feature[0].flag_set[0].flag_group), 2)
1078    self.assertEqual(
1079        output.feature[0].flag_set[0].flag_group[0].expand_if_all_available,
1080        ["foo"])
1081    self.assertEqual(
1082        output.feature[0].flag_set[0].flag_group[1].expand_if_all_available,
1083        ["foo"])
1084
1085  def test_enable_previously_default_features(self):
1086    default_features = [
1087        "dependency_file", "random_seed", "module_maps", "module_map_home_cwd",
1088        "header_module_compile", "include_paths", "pic", "preprocessor_define"
1089    ]
1090    crosstool = make_crosstool("""
1091          feature { name: "dependency_file" }
1092          feature { name: "random_seed" }
1093          feature { name: "module_maps" }
1094          feature { name: "module_map_home_cwd" }
1095          feature { name: "header_module_compile" }
1096          feature { name: "include_paths" }
1097          feature { name: "pic" }
1098          feature { name: "preprocessor_define" }
1099          """)
1100    migrate_legacy_fields(crosstool)
1101    output = crosstool.toolchain[0]
1102    for i in range(0, 8):
1103      self.assertEqual(output.feature[i].name, default_features[i])
1104      self.assertTrue(output.feature[i].enabled)
1105
1106  def test_migrate_repeated_expand_if_all_available_from_flag_groups(self):
1107    crosstool = make_crosstool("""
1108          action_config {
1109            action_name: 'something'
1110            config_name: 'something'
1111            flag_set {
1112              flag_group {
1113                expand_if_all_available: 'foo'
1114                expand_if_all_available: 'bar'
1115                flag: '%{foo}'
1116              }
1117              flag_group {
1118                expand_if_none_available: 'foo'
1119                expand_if_none_available: 'bar'
1120                flag: 'bar'
1121              }
1122            }
1123          }
1124          feature {
1125            name: 'something_else'
1126            flag_set {
1127              action: 'c-compile'
1128              flag_group {
1129                expand_if_all_available: 'foo'
1130                expand_if_all_available: 'bar'
1131                flag: '%{foo}'
1132              }
1133              flag_group {
1134                expand_if_none_available: 'foo'
1135                expand_if_none_available: 'bar'
1136                flag: 'bar'
1137              }
1138            }
1139          }
1140          """)
1141    migrate_legacy_fields(crosstool)
1142    output = crosstool.toolchain[0]
1143    self.assertEqual(output.action_config[0].action_name, "something")
1144    self.assertEqual(len(output.action_config[0].flag_set), 1)
1145    self.assertEqual(
1146        len(output.action_config[0].flag_set[0].expand_if_all_available), 0)
1147    self.assertEqual(len(output.action_config[0].flag_set[0].flag_group), 2)
1148    self.assertEqual(
1149        output.action_config[0].flag_set[0].flag_group[0]
1150        .expand_if_all_available, ["foo"])
1151    self.assertEqual(
1152        output.action_config[0].flag_set[0].flag_group[0].flag_group[0]
1153        .expand_if_all_available, ["bar"])
1154    self.assertEqual(
1155        output.action_config[0].flag_set[0].flag_group[1]
1156        .expand_if_none_available, ["foo"])
1157    self.assertEqual(
1158        output.action_config[0].flag_set[0].flag_group[1].flag_group[0]
1159        .expand_if_none_available, ["bar"])
1160
1161    self.assertEqual(output.feature[0].name, "something_else")
1162    self.assertEqual(len(output.feature[0].flag_set), 1)
1163    self.assertEqual(
1164        len(output.feature[0].flag_set[0].expand_if_all_available), 0)
1165    self.assertEqual(len(output.feature[0].flag_set[0].flag_group), 2)
1166    self.assertEqual(
1167        output.feature[0].flag_set[0].flag_group[0].expand_if_all_available,
1168        ["foo"])
1169    self.assertEqual(
1170        output.feature[0].flag_set[0].flag_group[0].flag_group[0]
1171        .expand_if_all_available, ["bar"])
1172    self.assertEqual(
1173        output.feature[0].flag_set[0].flag_group[1].expand_if_none_available,
1174        ["foo"])
1175    self.assertEqual(
1176        output.feature[0].flag_set[0].flag_group[1].flag_group[0]
1177        .expand_if_none_available, ["bar"])
1178
1179  def test_migrate_repeated_expands_from_nested_flag_groups(self):
1180    crosstool = make_crosstool("""
1181          feature {
1182            name: 'something'
1183            flag_set {
1184              action: 'c-compile'
1185              flag_group {
1186                flag_group {
1187                  expand_if_all_available: 'foo'
1188                  expand_if_all_available: 'bar'
1189                  flag: '%{foo}'
1190                }
1191              }
1192              flag_group {
1193                flag_group {
1194                  expand_if_all_available: 'foo'
1195                  expand_if_all_available: 'bar'
1196                  expand_if_none_available: 'foo'
1197                  expand_if_none_available: 'bar'
1198                  flag: '%{foo}'
1199                }
1200              }
1201            }
1202          }
1203          """)
1204    migrate_legacy_fields(crosstool)
1205    output = crosstool.toolchain[0]
1206
1207    self.assertEqual(output.feature[0].name, "something")
1208    self.assertEqual(len(output.feature[0].flag_set[0].flag_group), 2)
1209    self.assertEqual(
1210        len(output.feature[0].flag_set[0].flag_group[0].expand_if_all_available
1211           ), 0)
1212    self.assertEqual(
1213        output.feature[0].flag_set[0].flag_group[0].flag_group[0]
1214        .expand_if_all_available, ["foo"])
1215    self.assertEqual(
1216        output.feature[0].flag_set[0].flag_group[0].flag_group[0].flag_group[0]
1217        .expand_if_all_available, ["bar"])
1218    self.assertEqual(
1219        output.feature[0].flag_set[0].flag_group[0].flag_group[0].flag_group[0]
1220        .flag, ["%{foo}"])
1221
1222    self.assertEqual(
1223        output.feature[0].flag_set[0].flag_group[1].flag_group[0]
1224        .expand_if_all_available, ["foo"])
1225    self.assertEqual(
1226        output.feature[0].flag_set[0].flag_group[1].flag_group[0]
1227        .expand_if_none_available, ["foo"])
1228    self.assertEqual(
1229        output.feature[0].flag_set[0].flag_group[1].flag_group[0].flag_group[0]
1230        .expand_if_none_available, ["bar"])
1231    self.assertEqual(
1232        output.feature[0].flag_set[0].flag_group[1].flag_group[0].flag_group[0]
1233        .expand_if_all_available, ["bar"])
1234    self.assertEqual(
1235        output.feature[0].flag_set[0].flag_group[1].flag_group[0].flag_group[0]
1236        .flag, ["%{foo}"])
1237
1238
1239if __name__ == "__main__":
1240  unittest.main()
1241