• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2# Copyright 2014 The Chromium Authors
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Tests for enum_preprocess.py.
7
8This test suite contains various tests for the C++ -> Java enum generator.
9"""
10
11import collections
12from datetime import date
13import unittest
14
15import java_cpp_enum
16from java_cpp_enum import EnumDefinition, GenerateOutput
17from java_cpp_enum import HeaderParser
18from util import java_cpp_utils
19
20
21class TestPreprocess(unittest.TestCase):
22  def testOutput(self):
23    definition = EnumDefinition(original_enum_name='ClassName',
24                                enum_package='some.package',
25                                entries=[('E1', 1), ('E2', '2 << 2')],
26                                comments=[('E2', 'This is a comment.'),
27                                          ('E1', 'This is a multiple line '
28                                                 'comment that is really long. '
29                                                 'This is a multiple line '
30                                                 'comment that is really '
31                                                 'really long.')])
32    output = GenerateOutput('path/to/file', definition)
33    expected = """
34// Copyright %d The Chromium Authors
35// Use of this source code is governed by a BSD-style license that can be
36// found in the LICENSE file.
37
38// This file is autogenerated by
39//     %s
40// From
41//     path/to/file
42
43package some.package;
44
45import androidx.annotation.IntDef;
46
47import java.lang.annotation.ElementType;
48import java.lang.annotation.Retention;
49import java.lang.annotation.RetentionPolicy;
50import java.lang.annotation.Target;
51
52@IntDef({
53    ClassName.E1, ClassName.E2
54})
55@Target(ElementType.TYPE_USE)
56@Retention(RetentionPolicy.SOURCE)
57public @interface ClassName {
58  /**
59   * %s
60   * really really long.
61   */
62  int E1 = 1;
63  /**
64   * This is a comment.
65   */
66  int E2 = 2 << 2;
67}
68"""
69    long_comment = ('This is a multiple line comment that is really long. '
70                    'This is a multiple line comment that is')
71    self.assertEqual(
72        expected % (date.today().year, java_cpp_utils.GetScriptName(),
73                    long_comment), output)
74
75  def testParseSimpleEnum(self):
76    test_data = """
77      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
78      enum EnumName {
79        VALUE_ZERO,
80        VALUE_ONE,
81      };
82    """.split('\n')
83    definitions = HeaderParser(test_data).ParseDefinitions()
84    self.assertEqual(1, len(definitions))
85    definition = definitions[0]
86    self.assertEqual('EnumName', definition.class_name)
87    self.assertEqual('test.namespace', definition.enum_package)
88    self.assertEqual(collections.OrderedDict([('VALUE_ZERO', 0),
89                                              ('VALUE_ONE', 1)]),
90                     definition.entries)
91
92  def testOutputFlag(self):
93    for [attr, want_flag] in [
94        ['0', False],
95        ['1', True],
96        ['false', False],
97        ['true', True],
98    ]:
99      test_data = ("""
100        // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
101        // GENERATED_JAVA_IS_FLAG: %s
102        enum EnumName {
103          ZERO = 1 << 0,
104          ONE = 1 << 1,
105        };
106      """ % attr).split('\n')
107      definitions = HeaderParser(test_data).ParseDefinitions()
108      output = GenerateOutput('/path/to/file', definitions[0])
109      int_def = output[output.index("@IntDef"):]
110      expected = """@IntDef(%s{
111    EnumName.ZERO, EnumName.ONE
112})
113@Target(ElementType.TYPE_USE)
114@Retention(RetentionPolicy.SOURCE)
115public @interface EnumName {
116  int ZERO = 1 << 0;
117  int ONE = 1 << 1;
118}
119""" % ('flag = true, value = ' if want_flag else '')
120      self.assertEqual(int_def, expected)
121
122  def testParseBitShifts(self):
123    test_data = """
124      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
125      enum EnumName {
126        VALUE_ZERO = 1 << 0,
127        VALUE_ONE = 1 << 1,
128      };
129
130      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
131      enum EnumName {
132        ENUM_NAME_ZERO = 1 << 0,
133        ENUM_NAME_ONE = 1 << 1,
134        ENUM_NAME_TWO = ENUM_NAME_ZERO | ENUM_NAME_ONE,
135      };
136    """.split('\n')
137    definitions = HeaderParser(test_data).ParseDefinitions()
138    self.assertEqual(2, len(definitions))
139    definition = definitions[0]
140    self.assertEqual('EnumName', definition.class_name)
141    self.assertEqual('test.namespace', definition.enum_package)
142    self.assertEqual(collections.OrderedDict([('VALUE_ZERO', '1 << 0'),
143                                              ('VALUE_ONE', '1 << 1')]),
144                     definition.entries)
145
146    definition = definitions[1]
147    expected_entries = collections.OrderedDict([
148        ('ZERO', '1 << 0'),
149        ('ONE', '1 << 1'),
150        ('TWO', 'ZERO | ONE')])
151    self.assertEqual(expected_entries, definition.entries)
152
153  def testParseMultilineEnumEntry(self):
154    test_data = """
155      // GENERATED_JAVA_ENUM_PACKAGE: bar.namespace
156      enum Foo {
157        VALUE_ZERO = 1 << 0,
158        VALUE_ONE =
159            SymbolKey | FnKey | AltGrKey | MetaKey | AltKey | ControlKey,
160        VALUE_TWO = 1 << 18,
161      };
162    """.split('\n')
163    expected_entries = collections.OrderedDict([
164        ('VALUE_ZERO', '1 << 0'),
165        ('VALUE_ONE', 'SymbolKey | FnKey | AltGrKey | MetaKey | AltKey | '
166         'ControlKey'),
167        ('VALUE_TWO', '1 << 18')])
168    definitions = HeaderParser(test_data).ParseDefinitions()
169    self.assertEqual(1, len(definitions))
170    definition = definitions[0]
171    self.assertEqual('Foo', definition.class_name)
172    self.assertEqual('bar.namespace', definition.enum_package)
173    self.assertEqual(expected_entries, definition.entries)
174
175  def testParseEnumEntryWithTrailingMultilineEntry(self):
176    test_data = """
177      // GENERATED_JAVA_ENUM_PACKAGE: bar.namespace
178      enum Foo {
179        VALUE_ZERO = 1,
180        VALUE_ONE =
181            SymbolKey | FnKey | AltGrKey | MetaKey |
182            AltKey | ControlKey | ShiftKey,
183      };
184    """.split('\n')
185    expected_entries = collections.OrderedDict([
186        ('VALUE_ZERO', '1'),
187        ('VALUE_ONE', 'SymbolKey | FnKey | AltGrKey | MetaKey | AltKey | '
188         'ControlKey | ShiftKey')])
189    definitions = HeaderParser(test_data).ParseDefinitions()
190    self.assertEqual(1, len(definitions))
191    definition = definitions[0]
192    self.assertEqual('Foo', definition.class_name)
193    self.assertEqual('bar.namespace', definition.enum_package)
194    self.assertEqual(expected_entries, definition.entries)
195
196  def testParseNoCommaAfterLastEntry(self):
197    test_data = """
198      // GENERATED_JAVA_ENUM_PACKAGE: bar.namespace
199      enum Foo {
200        VALUE_ZERO = 1,
201
202        // This is a multiline
203        //
204        // comment with an empty line.
205        VALUE_ONE = 2
206      };
207    """.split('\n')
208    expected_entries = collections.OrderedDict([
209        ('VALUE_ZERO', '1'),
210        ('VALUE_ONE', '2')])
211    expected_comments = collections.OrderedDict([
212        ('VALUE_ONE', 'This is a multiline comment with an empty line.')])
213    definitions = HeaderParser(test_data).ParseDefinitions()
214    self.assertEqual(1, len(definitions))
215    definition = definitions[0]
216    self.assertEqual('Foo', definition.class_name)
217    self.assertEqual('bar.namespace', definition.enum_package)
218    self.assertEqual(expected_entries, definition.entries)
219    self.assertEqual(expected_comments, definition.comments)
220
221  def testParseClassNameOverride(self):
222    test_data = """
223      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
224      // GENERATED_JAVA_CLASS_NAME_OVERRIDE: OverrideName
225      enum EnumName {
226        FOO
227      };
228
229      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
230      // GENERATED_JAVA_CLASS_NAME_OVERRIDE: OtherOverride
231      enum PrefixTest {
232        PREFIX_TEST_A,
233        PREFIX_TEST_B,
234      };
235    """.split('\n')
236    definitions = HeaderParser(test_data).ParseDefinitions()
237    self.assertEqual(2, len(definitions))
238    definition = definitions[0]
239    self.assertEqual('OverrideName', definition.class_name)
240
241    definition = definitions[1]
242    self.assertEqual('OtherOverride', definition.class_name)
243    self.assertEqual(collections.OrderedDict([('A', 0),
244                                              ('B', 1)]),
245                     definition.entries)
246
247  def testParsePreservesCommentsWhenPrefixStripping(self):
248    test_data = """
249      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
250      enum EnumOne {
251        ENUM_ONE_A = 1,
252        // Comment there
253        ENUM_ONE_B = A,
254      };
255
256      enum EnumIgnore {
257        C, D, E
258      };
259
260      // GENERATED_JAVA_ENUM_PACKAGE: other.package
261      // GENERATED_JAVA_PREFIX_TO_STRIP: P_
262      enum EnumTwo {
263        P_A,
264        // This comment spans
265        // two lines.
266        P_B
267      };
268    """.split('\n')
269    definitions = HeaderParser(test_data).ParseDefinitions()
270    self.assertEqual(2, len(definitions))
271    definition = definitions[0]
272    self.assertEqual('EnumOne', definition.class_name)
273    self.assertEqual('test.namespace', definition.enum_package)
274    self.assertEqual(collections.OrderedDict([('A', '1'),
275                                              ('B', 'A')]),
276                     definition.entries)
277    self.assertEqual(collections.OrderedDict([('B', 'Comment there')]),
278                     definition.comments)
279    definition = definitions[1]
280    self.assertEqual('EnumTwo', definition.class_name)
281    self.assertEqual('other.package', definition.enum_package)
282    self.assertEqual(collections.OrderedDict(
283        [('B', 'This comment spans two lines.')]), definition.comments)
284    self.assertEqual(collections.OrderedDict([('A', 0),
285                                              ('B', 1)]),
286                     definition.entries)
287
288  def testParseTwoEnums(self):
289    test_data = """
290      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
291      enum AnEnum {
292        ENUM_ONE_A = 1,
293        ENUM_ONE_B = A,
294      };
295
296      enum EnumIgnore {
297        C, D, E
298      };
299
300      // GENERATED_JAVA_ENUM_PACKAGE: other.package
301      enum EnumTwo {
302        P_A,
303        P_B
304      };
305    """.split('\n')
306    definitions = HeaderParser(test_data).ParseDefinitions()
307    self.assertEqual(2, len(definitions))
308    definition = definitions[0]
309    self.assertEqual('AnEnum', definition.class_name)
310    self.assertEqual('test.namespace', definition.enum_package)
311    self.assertEqual(collections.OrderedDict([('ENUM_ONE_A', '1'),
312                                              ('ENUM_ONE_B', 'A')]),
313                     definition.entries)
314    definition = definitions[1]
315    self.assertEqual('EnumTwo', definition.class_name)
316    self.assertEqual('other.package', definition.enum_package)
317    self.assertEqual(collections.OrderedDict([('P_A', 0),
318                                              ('P_B', 1)]),
319                     definition.entries)
320
321  def testParseSingleLineEnum(self):
322    test_data = """
323      // GENERATED_JAVA_ENUM_PACKAGE: other.package
324      // GENERATED_JAVA_PREFIX_TO_STRIP: P_
325      enum EnumTwo { P_A, P_B };
326    """.split('\n')
327    definitions = HeaderParser(test_data).ParseDefinitions()
328    definition = definitions[0]
329    self.assertEqual('EnumTwo', definition.class_name)
330    self.assertEqual('other.package', definition.enum_package)
331    self.assertEqual(collections.OrderedDict([('A', 0),
332                                              ('B', 1)]),
333                     definition.entries)
334
335  def testParseWithStrippingAndRelativeReferences(self):
336    test_data = """
337      // GENERATED_JAVA_ENUM_PACKAGE: other.package
338      // GENERATED_JAVA_PREFIX_TO_STRIP: P_
339      enum EnumTwo {
340        P_A = 1,
341        // P_A is old-don't use P_A.
342        P_B = P_A,
343      };
344    """.split('\n')
345    definitions = HeaderParser(test_data).ParseDefinitions()
346    definition = definitions[0]
347    self.assertEqual('EnumTwo', definition.class_name)
348    self.assertEqual('other.package', definition.enum_package)
349    self.assertEqual(collections.OrderedDict([('A', '1'),
350                                              ('B', 'A')]),
351                     definition.entries)
352    self.assertEqual(collections.OrderedDict([('B', 'A is old-don\'t use A.')]),
353                     definition.comments)
354
355  def testParseSingleLineAndRegularEnum(self):
356    test_data = """
357      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
358      enum EnumOne {
359        ENUM_ONE_A = 1,
360        // Comment there
361        ENUM_ONE_B = A,
362      };
363
364      // GENERATED_JAVA_ENUM_PACKAGE: other.package
365      enum EnumTwo { P_A, P_B };
366
367      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
368      // GENERATED_JAVA_CLASS_NAME_OVERRIDE: OverrideName
369      enum EnumName {
370        ENUM_NAME_FOO
371      };
372    """.split('\n')
373    definitions = HeaderParser(test_data).ParseDefinitions()
374    definition = definitions[0]
375    self.assertEqual(
376        collections.OrderedDict([('A', '1'), ('B', 'A')]), definition.entries)
377    self.assertEqual(collections.OrderedDict([('B', 'Comment there')]),
378                     definition.comments)
379
380    self.assertEqual(3, len(definitions))
381    definition = definitions[1]
382    self.assertEqual(
383        collections.OrderedDict([('P_A', 0), ('P_B', 1)]), definition.entries)
384
385    definition = definitions[2]
386    self.assertEqual(collections.OrderedDict([('FOO', 0)]), definition.entries)
387
388  def testParseWithCamelCaseNames(self):
389    test_data = """
390      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
391      enum EnumTest {
392        EnumTestA = 1,
393        // comment for EnumTestB.
394        EnumTestB = 2,
395      };
396
397      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
398      // GENERATED_JAVA_PREFIX_TO_STRIP: Test
399      enum AnEnum {
400        TestHTTPOption,
401        TestHTTPSOption,
402      };
403
404    """.split('\n')
405    definitions = HeaderParser(test_data).ParseDefinitions()
406    definition = definitions[0]
407    self.assertEqual(
408        collections.OrderedDict([('A', '1'), ('B', '2')]),
409        definition.entries)
410    self.assertEqual(
411        collections.OrderedDict([('B', 'comment for B.')]),
412        definition.comments)
413
414    definition = definitions[1]
415    self.assertEqual(
416        collections.OrderedDict([('HTTP_OPTION', 0), ('HTTPS_OPTION', 1)]),
417        definition.entries)
418
419  def testParseWithKCamelCaseNames(self):
420    test_data = """
421      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
422      enum EnumOne {
423        kEnumOne = 1,
424        // comment for kEnumTwo.
425        kEnumTwo = 2,
426      };
427
428      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
429      // GENERATED_JAVA_CLASS_NAME_OVERRIDE: OverrideName
430      enum EnumName {
431        kEnumNameFoo,
432        kEnumNameBar
433      };
434
435      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
436      enum EnumName {
437        kEnumNameFoo,
438        kEnumBar,
439      };
440
441      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
442      enum Keys {
443        kSymbolKey = 1 << 0,
444        kAltKey = 1 << 1,
445        kUpKey = 1 << 2,
446        kKeyModifiers = kSymbolKey | kAltKey | kUpKey | kKeyModifiers,
447      };
448
449      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
450      enum Mixed {
451        kTestVal,
452        kCodecMPEG2
453      };
454    """.split('\n')
455    definitions = HeaderParser(test_data).ParseDefinitions()
456    definition = definitions[0]
457    self.assertEqual(
458        collections.OrderedDict([('ENUM_ONE', '1'), ('ENUM_TWO', '2')]),
459        definition.entries)
460    self.assertEqual(
461        collections.OrderedDict([('ENUM_TWO', 'comment for ENUM_TWO.')]),
462        definition.comments)
463
464    definition = definitions[1]
465    self.assertEqual(
466        collections.OrderedDict([('FOO', 0), ('BAR', 1)]),
467        definition.entries)
468
469    definition = definitions[2]
470    self.assertEqual(
471        collections.OrderedDict([('ENUM_NAME_FOO', 0), ('ENUM_BAR', 1)]),
472        definition.entries)
473
474    definition = definitions[3]
475    expected_entries = collections.OrderedDict([
476        ('SYMBOL_KEY', '1 << 0'),
477        ('ALT_KEY', '1 << 1'),
478        ('UP_KEY', '1 << 2'),
479        ('KEY_MODIFIERS', 'SYMBOL_KEY | ALT_KEY | UP_KEY | KEY_MODIFIERS')])
480    self.assertEqual(expected_entries, definition.entries)
481
482    definition = definitions[4]
483    self.assertEqual(
484        collections.OrderedDict([('TEST_VAL', 0), ('CODEC_MPEG2', 1)]),
485        definition.entries)
486
487  def testParseThrowsOnUnknownDirective(self):
488    test_data = """
489      // GENERATED_JAVA_UNKNOWN: Value
490      enum EnumName {
491        VALUE_ONE,
492      };
493    """.split('\n')
494    with self.assertRaises(Exception):
495      HeaderParser(test_data).ParseDefinitions()
496
497  def testParseReturnsEmptyListWithoutDirectives(self):
498    test_data = """
499      enum EnumName {
500        VALUE_ONE,
501      };
502    """.split('\n')
503    self.assertEqual([], HeaderParser(test_data).ParseDefinitions())
504
505  def testParseEnumClass(self):
506    test_data = """
507      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
508      enum class Foo {
509        FOO_A,
510      };
511    """.split('\n')
512    definitions = HeaderParser(test_data).ParseDefinitions()
513    self.assertEqual(1, len(definitions))
514    definition = definitions[0]
515    self.assertEqual('Foo', definition.class_name)
516    self.assertEqual('test.namespace', definition.enum_package)
517    self.assertEqual(collections.OrderedDict([('A', 0)]),
518                     definition.entries)
519
520  def testParseEnumClassOneValueSubstringOfAnother(self):
521    test_data = """
522      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
523      enum class SafeBrowsingStatus {
524        kChecking = 0,
525        kEnabled = 1,
526        kDisabled = 2,
527        kDisabledByAdmin = 3,
528        kDisabledByExtension = 4,
529        kEnabledStandard = 5,
530        kEnabledEnhanced = 6,
531        // New enum values must go above here.
532        kMaxValue = kEnabledEnhanced,
533      };
534    """.split('\n')
535    definitions = HeaderParser(test_data).ParseDefinitions()
536    self.assertEqual(1, len(definitions))
537    definition = definitions[0]
538    self.assertEqual('SafeBrowsingStatus', definition.class_name)
539    self.assertEqual('test.namespace', definition.enum_package)
540    self.assertEqual(
541        collections.OrderedDict([
542            ('CHECKING', '0'),
543            ('ENABLED', '1'),
544            ('DISABLED', '2'),
545            ('DISABLED_BY_ADMIN', '3'),
546            ('DISABLED_BY_EXTENSION', '4'),
547            ('ENABLED_STANDARD', '5'),
548            ('ENABLED_ENHANCED', '6'),
549            ('MAX_VALUE', 'ENABLED_ENHANCED'),
550        ]), definition.entries)
551    self.assertEqual(
552        collections.OrderedDict([
553            ('MAX_VALUE', 'New enum values must go above here.')
554        ]), definition.comments)
555
556  def testParseEnumWithConditionallyDefinedValues(self):
557    test_data = """
558// GENERATED_JAVA_ENUM_PACKAGE: test.namespace
559// GENERATED_JAVA_PREFIX_TO_STRIP: TERMINATION_STATUS_
560enum TerminationStatus {
561  // Zero exit status.
562  TERMINATION_STATUS_NORMAL_TERMINATION = 0,
563  // Child hasn't exited yet.
564  TERMINATION_STATUS_STILL_RUNNING = 4,
565#if BUILDFLAG(IS_CHROMEOS)
566  // OOM-killer killed the process on ChromeOS.
567  TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM = 5,
568#endif
569#if BUILDFLAG(IS_ANDROID)
570  // On Android processes are spawned from the system Zygote and we do not get
571  // the termination status.
572  TERMINATION_STATUS_OOM_PROTECTED = 6,
573#endif
574  // Out of memory.
575  TERMINATION_STATUS_OOM = 8,
576#if BUILDFLAG(IS_WIN)
577  // On Windows, the OS terminated process due to code integrity failure.
578  TERMINATION_STATUS_INTEGRITY_FAILURE = 9,
579#endif
580#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX)
581  TERMINATION_STATUS_TEN = 10,
582#if BUILDFLAG(IS_POSIX)
583  TERMINATION_STATUS_ELEVEN = 11,
584#endif
585#endif
586#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
587  TERMINATION_STATUS_TWELVE = 12,
588#endif
589};
590    """.split('\n')
591    definitions = HeaderParser(test_data).ParseDefinitions()
592    self.assertEqual(1, len(definitions))
593    definition = definitions[0]
594    self.assertEqual('TerminationStatus', definition.class_name)
595    self.assertEqual('test.namespace', definition.enum_package)
596    self.assertEqual(
597        collections.OrderedDict([
598            ('NORMAL_TERMINATION', '0'),
599            ('STILL_RUNNING', '4'),
600            # PROCESS_WAS_KILLED_BY_OOM value should not appear here.
601            #
602            # OOM_PROTECTED should appear because the script supports the case
603            # where '#if BUILDFLAG(IS_ANDROID)' is used.
604            ('OOM_PROTECTED', '6'),
605            ('OOM', '8'),
606            # INTEGRITY_FAILURE value should not appear here.
607            # TEN and ELEVEN should not appear here.
608            ('TWELVE', '12'),
609        ]),
610        definition.entries)
611    self.assertEqual(
612        collections.OrderedDict([
613            ('NORMAL_TERMINATION', 'Zero exit status.'),
614            ('STILL_RUNNING', 'Child hasn\'t exited yet.'),
615            ('OOM_PROTECTED',
616             'On Android processes are spawned from the system Zygote and we ' +
617             'do not get the termination status.'),
618            ('OOM', 'Out of memory.'),
619        ]), definition.comments)
620
621  def testParseEnumStruct(self):
622    test_data = """
623      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
624      enum struct Foo {
625        FOO_A,
626      };
627    """.split('\n')
628    definitions = HeaderParser(test_data).ParseDefinitions()
629    self.assertEqual(1, len(definitions))
630    definition = definitions[0]
631    self.assertEqual('Foo', definition.class_name)
632    self.assertEqual('test.namespace', definition.enum_package)
633    self.assertEqual(collections.OrderedDict([('A', 0)]),
634                     definition.entries)
635
636  def testParseFixedTypeEnum(self):
637    test_data = """
638      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
639      enum Foo : int {
640        FOO_A,
641      };
642    """.split('\n')
643    definitions = HeaderParser(test_data).ParseDefinitions()
644    self.assertEqual(1, len(definitions))
645    definition = definitions[0]
646    self.assertEqual('Foo', definition.class_name)
647    self.assertEqual('test.namespace', definition.enum_package)
648    self.assertEqual('int', definition.fixed_type)
649    self.assertEqual(collections.OrderedDict([('A', 0)]),
650                     definition.entries)
651
652  def testParseFixedTypeEnum(self):
653    test_data = """
654      // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.components.signin.metrics
655      // GENERATED_JAVA_CLASS_NAME_OVERRIDE: SigninAccessPoint
656      enum class AccessPoint : int {
657        ACCESS_POINT_DRIVE_FILE_PICKER_IOS = 0,
658        ACCESS_POINT_COLLABORATION_TAB_GROUP = 1,
659        ACCESS_POINT_MAX,
660      };
661    """.split('\n')
662    definitions = HeaderParser(test_data).ParseDefinitions()
663    self.assertEqual(1, len(definitions))
664    definition = definitions[0]
665    self.assertEqual('SigninAccessPoint', definition.class_name)
666    self.assertEqual('org.chromium.components.signin.metrics',
667                     definition.enum_package)
668    self.assertEqual('int', definition.fixed_type)
669    self.assertEqual(
670        collections.OrderedDict([('DRIVE_FILE_PICKER_IOS', 0),
671                                 ('COLLABORATION_TAB_GROUP', 1), ('MAX', 2)]),
672        definition.entries)
673
674  def testParseFixedTypeEnumWithMaxValue(self):
675    test_data = """
676      // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.components.signin.metrics
677      // GENERATED_JAVA_CLASS_NAME_OVERRIDE: SigninAccessPoint
678      enum class AccessPoint : int {
679        ACCESS_POINT_DRIVE_FILE_PICKER_IOS = 0,
680        ACCESS_POINT_COLLABORATION_TAB_GROUP = 1,
681        kMaxValue = ACCESS_POINT_COLLABORATION_TAB_GROUP,
682      };
683    """.split('\n')
684    definitions = HeaderParser(test_data).ParseDefinitions()
685    self.assertEqual(1, len(definitions))
686    definition = definitions[0]
687    self.assertEqual('SigninAccessPoint', definition.class_name)
688    self.assertEqual('org.chromium.components.signin.metrics',
689                     definition.enum_package)
690    self.assertEqual('int', definition.fixed_type)
691    self.assertEqual(
692        collections.OrderedDict([('DRIVE_FILE_PICKER_IOS', '0'),
693                                 ('COLLABORATION_TAB_GROUP', '1'),
694                                 ('MAX_VALUE', 'COLLABORATION_TAB_GROUP')]),
695        definition.entries)
696
697  def testParseFixedTypeEnumClass(self):
698    test_data = """
699      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
700      enum class Foo: unsigned short {
701        FOO_A,
702      };
703    """.split('\n')
704    definitions = HeaderParser(test_data).ParseDefinitions()
705    self.assertEqual(1, len(definitions))
706    definition = definitions[0]
707    self.assertEqual('Foo', definition.class_name)
708    self.assertEqual('test.namespace', definition.enum_package)
709    self.assertEqual('unsigned short', definition.fixed_type)
710    self.assertEqual(collections.OrderedDict([('A', 0)]),
711                     definition.entries)
712
713  def testParseUnknownFixedTypeRaises(self):
714    test_data = """
715      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
716      enum class Foo: foo_type {
717        FOO_A,
718      };
719    """.split('\n')
720    with self.assertRaises(Exception):
721      HeaderParser(test_data).ParseDefinitions()
722
723  def testParseSimpleMultiLineDirective(self):
724    test_data = """
725      // GENERATED_JAVA_ENUM_PACKAGE: (
726      //   test.namespace)
727      // GENERATED_JAVA_CLASS_NAME_OVERRIDE: Bar
728      enum Foo {
729        FOO_A,
730      };
731    """.split('\n')
732    definitions = HeaderParser(test_data).ParseDefinitions()
733    self.assertEqual('test.namespace', definitions[0].enum_package)
734    self.assertEqual('Bar', definitions[0].class_name)
735
736  def testParseMultiLineDirective(self):
737    test_data = """
738      // GENERATED_JAVA_ENUM_PACKAGE: (te
739      //   st.name
740      //   space)
741      enum Foo {
742        FOO_A,
743      };
744    """.split('\n')
745    definitions = HeaderParser(test_data).ParseDefinitions()
746    self.assertEqual('test.namespace', definitions[0].enum_package)
747
748  def testParseMultiLineDirectiveWithOtherDirective(self):
749    test_data = """
750      // GENERATED_JAVA_ENUM_PACKAGE: (
751      //   test.namespace)
752      // GENERATED_JAVA_CLASS_NAME_OVERRIDE: (
753      //   Ba
754      //   r
755      //   )
756      enum Foo {
757        FOO_A,
758      };
759    """.split('\n')
760    definitions = HeaderParser(test_data).ParseDefinitions()
761    self.assertEqual('test.namespace', definitions[0].enum_package)
762    self.assertEqual('Bar', definitions[0].class_name)
763
764  def testParseMalformedMultiLineDirectiveWithOtherDirective(self):
765    test_data = """
766      // GENERATED_JAVA_ENUM_PACKAGE: (
767      //   test.name
768      //   space
769      // GENERATED_JAVA_CLASS_NAME_OVERRIDE: Bar
770      enum Foo {
771        FOO_A,
772      };
773    """.split('\n')
774    with self.assertRaises(Exception):
775      HeaderParser(test_data).ParseDefinitions()
776
777  def testParseMalformedMultiLineDirective(self):
778    test_data = """
779      // GENERATED_JAVA_ENUM_PACKAGE: (
780      //   test.name
781      //   space
782      enum Foo {
783        FOO_A,
784      };
785    """.split('\n')
786    with self.assertRaises(Exception):
787      HeaderParser(test_data).ParseDefinitions()
788
789  def testParseMalformedMultiLineDirectiveShort(self):
790    test_data = """
791      // GENERATED_JAVA_ENUM_PACKAGE: (
792      enum Foo {
793        FOO_A,
794      };
795    """.split('\n')
796    with self.assertRaises(Exception):
797      HeaderParser(test_data).ParseDefinitions()
798
799  def testParseMalformedMultiLineDirectiveMissingBrackets(self):
800    test_data = """
801      // GENERATED_JAVA_ENUM_PACKAGE:
802      // test.namespace
803      enum Foo {
804        FOO_A,
805      };
806    """.split('\n')
807    with self.assertRaises(Exception):
808      HeaderParser(test_data).ParseDefinitions()
809
810  def testEnumValueAssignmentNoneDefined(self):
811    definition = EnumDefinition(original_enum_name='c', enum_package='p')
812    definition.AppendEntry('A', None)
813    definition.AppendEntry('B', None)
814    definition.AppendEntry('C', None)
815    definition.Finalize()
816    self.assertEqual(collections.OrderedDict([('A', 0),
817                                              ('B', 1),
818                                              ('C', 2)]),
819                     definition.entries)
820
821  def testEnumValueAssignmentAllDefined(self):
822    definition = EnumDefinition(original_enum_name='c', enum_package='p')
823    definition.AppendEntry('A', '1')
824    definition.AppendEntry('B', '2')
825    definition.AppendEntry('C', '3')
826    definition.Finalize()
827    self.assertEqual(collections.OrderedDict([('A', '1'),
828                                              ('B', '2'),
829                                              ('C', '3')]),
830                     definition.entries)
831
832  def testEnumValueAssignmentReferences(self):
833    definition = EnumDefinition(original_enum_name='c', enum_package='p')
834    definition.AppendEntry('A', None)
835    definition.AppendEntry('B', 'A')
836    definition.AppendEntry('C', None)
837    definition.AppendEntry('D', 'C')
838    definition.Finalize()
839    self.assertEqual(collections.OrderedDict([('A', 0),
840                                              ('B', 0),
841                                              ('C', 1),
842                                              ('D', 1)]),
843                     definition.entries)
844
845  def testEnumValueAssignmentSet(self):
846    definition = EnumDefinition(original_enum_name='c', enum_package='p')
847    definition.AppendEntry('A', None)
848    definition.AppendEntry('B', '2')
849    definition.AppendEntry('C', None)
850    definition.Finalize()
851    self.assertEqual(collections.OrderedDict([('A', 0),
852                                              ('B', 2),
853                                              ('C', 3)]),
854                     definition.entries)
855
856  def testEnumValueAssignmentSetReferences(self):
857    definition = EnumDefinition(original_enum_name='c', enum_package='p')
858    definition.AppendEntry('A', None)
859    definition.AppendEntry('B', 'A')
860    definition.AppendEntry('C', 'B')
861    definition.AppendEntry('D', None)
862    definition.Finalize()
863    self.assertEqual(collections.OrderedDict([('A', 0),
864                                              ('B', 0),
865                                              ('C', 0),
866                                              ('D', 1)]),
867                     definition.entries)
868
869  def testEnumValueAssignmentRaises(self):
870    definition = EnumDefinition(original_enum_name='c', enum_package='p')
871    definition.AppendEntry('A', None)
872    definition.AppendEntry('B', 'foo')
873    definition.AppendEntry('C', None)
874    with self.assertRaises(Exception):
875      definition.Finalize()
876
877  def testExplicitPrefixStripping(self):
878    definition = EnumDefinition(original_enum_name='c', enum_package='p')
879    definition.AppendEntry('P_A', None)
880    definition.AppendEntry('B', None)
881    definition.AppendEntry('P_C', None)
882    definition.AppendEntry('P_LAST', 'P_C')
883    definition.prefix_to_strip = 'P_'
884    definition.Finalize()
885    self.assertEqual(collections.OrderedDict([('A', 0),
886                                              ('B', 1),
887                                              ('C', 2),
888                                              ('LAST', 2)]),
889                     definition.entries)
890
891  def testImplicitPrefixStripping(self):
892    definition = EnumDefinition(original_enum_name='ClassName',
893                                enum_package='p')
894    definition.AppendEntry('CLASS_NAME_A', None)
895    definition.AppendEntry('CLASS_NAME_B', None)
896    definition.AppendEntry('CLASS_NAME_C', None)
897    definition.AppendEntry('CLASS_NAME_LAST', 'CLASS_NAME_C')
898    definition.Finalize()
899    self.assertEqual(collections.OrderedDict([('A', 0),
900                                              ('B', 1),
901                                              ('C', 2),
902                                              ('LAST', 2)]),
903                     definition.entries)
904
905  def testImplicitPrefixStrippingRequiresAllConstantsToBePrefixed(self):
906    definition = EnumDefinition(original_enum_name='Name',
907                                enum_package='p')
908    definition.AppendEntry('A', None)
909    definition.AppendEntry('B', None)
910    definition.AppendEntry('NAME_LAST', None)
911    definition.Finalize()
912    self.assertEqual(['A', 'B', 'NAME_LAST'], list(definition.entries.keys()))
913
914  def testGenerateThrowsOnEmptyInput(self):
915    with self.assertRaises(Exception):
916      original_do_parse = java_cpp_enum.DoParseHeaderFile
917      try:
918        java_cpp_enum.DoParseHeaderFile = lambda _: []
919        for _ in java_cpp_enum.DoGenerate(['file']):
920          pass
921      finally:
922        java_cpp_enum.DoParseHeaderFile = original_do_parse
923
924
925if __name__ == '__main__':
926  unittest.main()
927