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