1#!/usr/bin/env python
2#
3# SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
4# SPDX-License-Identifier: Apache-2.0
5#
6
7import os
8import sys
9import tempfile
10import unittest
11from io import StringIO
12
13from pyparsing import ParseException, ParseFatalException, Word, alphanums
14
15try:
16    from fragments import FRAGMENT_TYPES, Fragment, FragmentFile, Mapping
17    from sdkconfig import SDKConfig
18except ImportError:
19    sys.path.append('../')
20    from fragments import FRAGMENT_TYPES, Fragment, FragmentFile, Mapping
21    from sdkconfig import SDKConfig
22
23
24class SampleFragment(Fragment):
25
26    grammars = {
27        'key_1': Fragment.KeyValue(Word(alphanums + '_').setResultsName('value'), 0, None, True),
28        'key_2': Fragment.KeyValue(Word(alphanums + '_').setResultsName('value'), 0, None, False),
29        'key_3': Fragment.KeyValue(Word(alphanums + '_').setResultsName('value'), 3, 5, False)
30    }
31
32    def set_key_value(self, key, parse_results):
33        if key == 'key_1':
34            self.key_1 = list()
35            for result in parse_results:
36                self.key_1.append(result['value'])
37        elif key == 'key_2':
38            self.key_2 = list()
39            for result in parse_results:
40                self.key_2.append(result['value'])
41
42    def get_key_grammars(self):
43        return self.__class__.grammars
44
45
46FRAGMENT_TYPES['test'] = SampleFragment
47
48
49class FragmentTest(unittest.TestCase):
50
51    def setUp(self):
52        with tempfile.NamedTemporaryFile(delete=False) as f:
53            self.kconfigs_source_file = os.path.join(tempfile.gettempdir(), f.name)
54        with tempfile.NamedTemporaryFile(delete=False) as f:
55            self.kconfig_projbuilds_source_file = os.path.join(tempfile.gettempdir(), f.name)
56
57        os.environ['COMPONENT_KCONFIGS_SOURCE_FILE'] = self.kconfigs_source_file
58        os.environ['COMPONENT_KCONFIGS_PROJBUILD_SOURCE_FILE'] = self.kconfig_projbuilds_source_file
59        os.environ['COMPONENT_KCONFIGS'] = ''
60        os.environ['COMPONENT_KCONFIGS_PROJBUILD'] = ''
61
62        # prepare_kconfig_files.py doesn't have to be called because COMPONENT_KCONFIGS and
63        # COMPONENT_KCONFIGS_PROJBUILD are empty
64
65        self.sdkconfig = SDKConfig('data/Kconfig', 'data/sdkconfig')
66
67    def tearDown(self):
68        try:
69            os.remove(self.kconfigs_source_file)
70            os.remove(self.kconfig_projbuilds_source_file)
71        except Exception:
72            pass
73
74    @staticmethod
75    def create_fragment_file(contents, name='test_fragment.lf'):
76        f = StringIO(contents)
77        f.name = name
78        return f
79
80    def test_basic(self):
81        test_fragment = self.create_fragment_file(u"""
82[test:test]
83key_1:
84    value_1
85    value_2 # comments should be ignored
86    value_3
87# this is a comment as well
88key_2: value_a
89
90# this is the last comment
91""")
92        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
93
94        self.assertEqual(len(fragment_file.fragments[0].key_1), 3)
95        self.assertEqual(fragment_file.fragments[0].key_1[0], 'value_1')
96        self.assertEqual(fragment_file.fragments[0].key_1[1], 'value_2')
97        self.assertEqual(fragment_file.fragments[0].key_1[2], 'value_3')
98        self.assertEqual(len(fragment_file.fragments[0].key_2), 1)
99        self.assertEqual(fragment_file.fragments[0].key_2[0], 'value_a')
100
101    def test_duplicate_keys(self):
102        test_fragment = self.create_fragment_file(u"""
103[test:test]
104key_1: value_1
105key_1: value_a
106""")
107        with self.assertRaises(ParseFatalException):
108            FragmentFile(test_fragment, self.sdkconfig)
109
110    def test_empty_key(self):
111        test_fragment = self.create_fragment_file(u"""
112[test:test]
113key_1:
114""")
115        with self.assertRaises(ParseException):
116            FragmentFile(test_fragment, self.sdkconfig)
117
118    def test_conditional(self):
119        test_fragment = self.create_fragment_file(u"""
120[test:test]
121key_1:
122    value_1
123    if A = y:
124        value_2
125    value_3
126    if A = n:
127        value_4
128    if B = n:
129        value_5
130""")
131        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
132        self.assertEqual(fragment_file.fragments[0].key_1[0], 'value_1')
133        self.assertEqual(fragment_file.fragments[0].key_1[1], 'value_2')
134        self.assertEqual(fragment_file.fragments[0].key_1[2], 'value_3')
135        self.assertEqual(fragment_file.fragments[0].key_1[3], 'value_5')
136
137        test_fragment = self.create_fragment_file(u"""
138[test:test]
139key_1:
140    value_1
141    if B = y:
142        value_2
143    elif C = y:
144        value_3
145    elif A = y:
146        value_4
147    else:
148        value_5
149    value_6
150""")
151
152        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
153        self.assertEqual(fragment_file.fragments[0].key_1[0], 'value_1')
154        self.assertEqual(fragment_file.fragments[0].key_1[1], 'value_3')
155        self.assertEqual(fragment_file.fragments[0].key_1[2], 'value_6')
156
157        test_fragment = self.create_fragment_file(u"""
158[test:test]
159key_1:
160    value_1
161    if A = y:
162        value_2
163        if B = y:
164            value_3
165        else:
166            value_4
167            if C = y:
168                value_5
169            value_6
170        value_7
171key_2:
172    value_a
173    if B != y:
174        value_b
175""")
176
177        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
178        self.assertEqual(fragment_file.fragments[0].key_1[0], 'value_1')
179        self.assertEqual(fragment_file.fragments[0].key_1[1], 'value_2')
180        self.assertEqual(fragment_file.fragments[0].key_1[2], 'value_4')
181        self.assertEqual(fragment_file.fragments[0].key_1[3], 'value_5')
182        self.assertEqual(fragment_file.fragments[0].key_1[4], 'value_6')
183        self.assertEqual(fragment_file.fragments[0].key_1[5], 'value_7')
184        self.assertEqual(fragment_file.fragments[0].key_2[0], 'value_a')
185        self.assertEqual(fragment_file.fragments[0].key_2[1], 'value_b')
186
187        test_fragment = self.create_fragment_file(u"""
188[test:test]
189key_1:
190    if A = n:
191        value_2
192""")
193
194        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
195        self.assertEqual(len(fragment_file.fragments[0].key_1), 0)
196
197    def test_empty_file(self):
198        test_fragment = self.create_fragment_file(u"""
199
200
201
202
203""")
204
205        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
206        self.assertEqual(len(fragment_file.fragments), 0)
207
208    def test_setting_indent(self):
209        test_fragment = self.create_fragment_file(u"""
210[test:test]
211key_1:
212 value_1
213 value_2
214 value_3
215""")
216        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
217
218        self.assertEqual(len(fragment_file.fragments[0].key_1), 3)
219        self.assertEqual(fragment_file.fragments[0].key_1[0], 'value_1')
220        self.assertEqual(fragment_file.fragments[0].key_1[1], 'value_2')
221        self.assertEqual(fragment_file.fragments[0].key_1[2], 'value_3')
222
223        test_fragment = self.create_fragment_file(u"""
224[test:test]
225key_1:
226 value_1
227  value_2 # first element dictates indent
228  value_3
229""")
230        with self.assertRaises(ParseFatalException):
231            FragmentFile(test_fragment, self.sdkconfig)
232
233    def test_values_num_limit(self):
234        test_fragment = self.create_fragment_file(u"""
235[test:test]
236key_1:
237    value_a
238key_3:
239    value_1
240    value_2
241    value_3
242""")
243        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
244
245        test_fragment = self.create_fragment_file(u"""
246[test:test]
247key_1:
248    value_a
249key_3:
250    value_1
251    value_2
252    value_3
253    value_4
254""")
255        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
256        self.assertEqual(len(fragment_file.fragments), 1)
257
258        test_fragment = self.create_fragment_file(u"""
259[test:test]
260key_1:
261    value_a
262key_3:
263    value_1
264    value_2
265    value_3
266    value_4
267    value_5
268""")
269        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
270        self.assertEqual(len(fragment_file.fragments), 1)
271
272        test_fragment = self.create_fragment_file(u"""
273[test:test]
274key_1:
275    value_a
276key_3:
277    value_1
278    value_2
279""")
280
281        with self.assertRaises(ParseFatalException):
282            FragmentFile(test_fragment, self.sdkconfig)
283
284        test_fragment = self.create_fragment_file(u"""
285[test:test]
286key_1:
287    value_a
288key_3:
289    value_1
290    value_2
291    value_3
292    value_4
293    value_5
294    value_6
295""")
296
297        with self.assertRaises(ParseFatalException):
298            FragmentFile(test_fragment, self.sdkconfig)
299
300    def test_unsupported_key(self):
301        test_fragment = self.create_fragment_file(u"""
302[test:test]
303key_1:
304    value_a
305key_4:
306    value_1
307""")
308
309        with self.assertRaises(ParseFatalException):
310            FragmentFile(test_fragment, self.sdkconfig)
311
312    def test_empty_fragment(self):
313        test_fragment = self.create_fragment_file(u"""
314[test:test]
315""")
316
317        with self.assertRaises(ParseException):
318            FragmentFile(test_fragment, self.sdkconfig)
319
320    def test_empty_conditional(self):
321        test_fragment = self.create_fragment_file(u"""
322[test:test]
323key_1:
324    if B = y:
325    else:
326        value_1
327""")
328
329        with self.assertRaises(ParseFatalException):
330            FragmentFile(test_fragment, self.sdkconfig)
331
332        test_fragment = self.create_fragment_file(u"""
333[test:test]
334key_1:
335    if B = y:
336        value_1
337    else B = y:
338""")
339
340        with self.assertRaises(ParseFatalException):
341            FragmentFile(test_fragment, self.sdkconfig)
342
343        test_fragment = self.create_fragment_file(u"""
344[test:test]
345key_1:
346    if B = y:
347        value_1
348    elif B = y:
349    else:
350        value_2
351""")
352
353        with self.assertRaises(ParseFatalException):
354            FragmentFile(test_fragment, self.sdkconfig)
355
356    def test_out_of_order_conditional(self):
357        test_fragment = self.create_fragment_file(u"""
358[test:test]
359key_1:
360    elif B = y:
361        value_1
362    else:
363        value_2
364""")
365
366        with self.assertRaises(ParseFatalException):
367            FragmentFile(test_fragment, self.sdkconfig)
368
369        test_fragment = self.create_fragment_file(u"""
370[test:test]
371key_1:
372    else:
373        value_2
374""")
375
376        with self.assertRaises(ParseFatalException):
377            FragmentFile(test_fragment, self.sdkconfig)
378
379    def test_required_keys(self):
380        test_fragment = self.create_fragment_file(u"""
381[test:test]
382key_2:
383    value_1
384""")
385
386        with self.assertRaises(ParseFatalException):
387            FragmentFile(test_fragment, self.sdkconfig)
388
389    def test_multiple_fragments(self):
390        test_fragment = self.create_fragment_file(u"""
391[test:test1]
392key_1:
393    value_1
394
395[test:test2]
396key_1:
397    value_2
398""")
399
400        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
401
402        self.assertEqual(len(fragment_file.fragments), 2)
403        self.assertEqual(fragment_file.fragments[0].key_1[0], 'value_1')
404        self.assertEqual(fragment_file.fragments[1].key_1[0], 'value_2')
405
406    def test_whole_conditional_fragment(self):
407        test_fragment = self.create_fragment_file(u"""
408if B = y:
409    [test:test1]
410    key_1:
411        value_1
412else:
413    [test:test2]
414    key_1:
415        value_2
416
417    if A = y:
418        [test:test3]
419        key_1:
420            value_3
421            if C = y:
422                value_6
423
424    [test:test4]
425    key_1:
426        value_4
427
428[test:test5]
429key_1:
430    value_5
431""")
432
433        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
434        self.assertEqual(len(fragment_file.fragments), 4)
435        self.assertEqual(fragment_file.fragments[0].name, 'test2')
436        self.assertEqual(fragment_file.fragments[1].name, 'test3')
437        self.assertEqual(fragment_file.fragments[1].key_1[1], 'value_6')
438        self.assertEqual(fragment_file.fragments[2].name, 'test4')
439        self.assertEqual(fragment_file.fragments[3].name, 'test5')
440
441    def test_equivalent_conditional_fragment(self):
442        test_fragment1 = self.create_fragment_file(u"""
443if A = y:
444    [test:test1]
445    key_1:
446        value_1
447else:
448    [test:test2]
449    key_1:
450        value_2
451""")
452
453        fragment_file1 = FragmentFile(test_fragment1, self.sdkconfig)
454        self.assertEqual(len(fragment_file1.fragments), 1)
455        self.assertEqual(fragment_file1.fragments[0].key_1[0], 'value_1')
456
457        test_fragment2 = self.create_fragment_file(u"""
458[test:test1]
459key_1:
460    if A = y:
461        value_1
462    else:
463        value_2
464""")
465
466        fragment_file2 = FragmentFile(test_fragment2, self.sdkconfig)
467        self.assertEqual(len(fragment_file2.fragments), 1)
468        self.assertEqual(fragment_file2.fragments[0].key_1[0], 'value_1')
469
470
471class SectionsTest(FragmentTest):
472
473    def test_basic(self):
474        test_fragment = self.create_fragment_file(u"""
475[sections:test]
476entries:
477    .section1
478    .section2
479""")
480
481        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
482        self.assertEqual(fragment_file.fragments[0].entries, {'.section1', '.section2'})
483
484    def test_duplicate_entries(self):
485        test_fragment = self.create_fragment_file(u"""
486[sections:test]
487entries:
488    .section1
489    .section2
490    .section3
491    .section2
492""")
493
494        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
495        self.assertEqual(fragment_file.fragments[0].entries, {'.section1', '.section2', '.section3'})
496
497    def test_empty_entries(self):
498        test_fragment = self.create_fragment_file(u"""
499[sections:test]
500entries:
501""")
502
503        with self.assertRaises(ParseException):
504            FragmentFile(test_fragment, self.sdkconfig)
505
506        test_fragment = self.create_fragment_file(u"""
507[sections:test]
508entries:
509    if B = y:
510        .section1
511""")
512
513        with self.assertRaises(ParseFatalException):
514            FragmentFile(test_fragment, self.sdkconfig)
515
516    def test_entries_grammar(self):
517
518        test_fragment = self.create_fragment_file(u"""
519[sections:test]
520entries:
521    _valid1
522    valid2.
523    .valid3_-
524""")
525
526        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
527        self.assertEqual(fragment_file.fragments[0].entries,
528                         {'_valid1', 'valid2.', '.valid3_-'})
529
530        # invalid starting char
531        test_fragment = self.create_fragment_file(u"""
532[sections:test]
533entries:
534    1invalid
535""")
536
537        with self.assertRaises(ParseException):
538            FragmentFile(test_fragment, self.sdkconfig)
539
540        test_fragment = self.create_fragment_file(u"""
541[sections:test]
542entries:
543    -invalid
544""")
545
546        with self.assertRaises(ParseException):
547            FragmentFile(test_fragment, self.sdkconfig)
548
549        # + notation
550        test_fragment = self.create_fragment_file(u"""
551[sections:test]
552entries:
553    valid+
554""")
555
556        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
557        self.assertEqual(fragment_file.fragments[0].entries,
558                         {'valid+'})
559
560        test_fragment = self.create_fragment_file(u"""
561[sections:test]
562entries:
563    inva+lid+
564""")
565
566        with self.assertRaises(ParseFatalException):
567            FragmentFile(test_fragment, self.sdkconfig)
568
569
570class SchemeTest(FragmentTest):
571
572    def test_basic(self):
573        test_fragment = self.create_fragment_file(u"""
574[scheme:test]
575entries:
576    sections1 -> target1
577    sections2 -> target2
578""")
579
580        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
581        self.assertEqual(fragment_file.fragments[0].entries,
582                         {('sections1', 'target1'),
583                          ('sections2', 'target2')})
584
585    def test_duplicate_entries(self):
586        test_fragment = self.create_fragment_file(u"""
587[scheme:test]
588entries:
589    sections1 -> target1
590    sections2 -> target2
591    sections2 -> target2
592""")
593
594        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
595        self.assertEqual(fragment_file.fragments[0].entries,
596                         {('sections1', 'target1'),
597                          ('sections2', 'target2')})
598
599    def test_empty_entries(self):
600        test_fragment = self.create_fragment_file(u"""
601[scheme:test]
602entries:
603""")
604
605        with self.assertRaises(ParseException):
606            FragmentFile(test_fragment, self.sdkconfig)
607
608        test_fragment = self.create_fragment_file(u"""
609[scheme:test]
610entries:
611    if B = y:
612        sections1 -> target1
613""")
614
615        with self.assertRaises(ParseFatalException):
616            FragmentFile(test_fragment, self.sdkconfig)
617
618    def test_improper_grammar(self):
619        test_fragment = self.create_fragment_file(u"""
620[scheme:test]
621entries:
622    sections1, target1 # improper separator
623""")
624
625        with self.assertRaises(ParseException):
626            FragmentFile(test_fragment, self.sdkconfig)
627
628
629class MappingTest(FragmentTest):
630
631    def test_basic(self):
632        test_fragment = self.create_fragment_file(u"""
633[mapping:test]
634archive: lib.a
635entries:
636    obj:symbol (noflash)
637    obj (noflash)
638    obj:symbol_2 (noflash)
639    obj_2 (noflash)
640    * (noflash)
641""")
642
643        expected = {('obj', 'symbol', 'noflash'),
644                    ('obj', None, 'noflash'),
645                    ('obj', 'symbol_2', 'noflash'),
646                    ('obj_2', None, 'noflash'),
647                    ('*', None, 'noflash')}
648
649        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
650        self.assertEqual(expected, fragment_file.fragments[0].entries)
651
652    def test_archive(self):
653        test_fragment = self.create_fragment_file(u"""
654[mapping:test]
655archive:
656entries:
657    * (default)
658""")
659
660        with self.assertRaises(ParseException):
661            FragmentFile(test_fragment, self.sdkconfig)
662
663        test_fragment = self.create_fragment_file(u"""
664[mapping:test]
665archive:
666    lib1.a
667    lib2.a
668entries:
669    * (default)
670""")
671
672        with self.assertRaises(ParseFatalException):
673            FragmentFile(test_fragment, self.sdkconfig)
674
675    def test_archive_allowed_names(self):
676        test_fragment = self.create_fragment_file(u"""
677[mapping:test]
678archive:
679    libstdc++.a
680entries:
681    * (default)
682""")
683
684        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
685        self.assertEqual('libstdc++.a', fragment_file.fragments[0].archive)
686
687    def test_empty_entries(self):
688        test_fragment = self.create_fragment_file(u"""
689[mapping:test]
690archive:
691    lib.a
692entries:
693    if B = y:
694        * (noflash) # if condition is false, then no 'entries' key value
695""")
696
697        expected = set()
698
699        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
700        self.assertEqual(expected, fragment_file.fragments[0].entries)
701
702        test_fragment = self.create_fragment_file(u"""
703[mapping:test]
704archive:
705    lib.a
706entries:
707""")
708
709        with self.assertRaises(ParseException):
710            FragmentFile(test_fragment, self.sdkconfig)
711
712    def test_duplicate_entries(self):
713        test_fragment = self.create_fragment_file(u"""
714[mapping:test]
715archive:
716    lib.a
717entries:
718    obj:symbol (noflash)
719    obj:symbol (noflash)
720""")
721
722        expected = {('obj', 'symbol', 'noflash')}
723
724        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
725        self.assertEqual(expected, fragment_file.fragments[0].entries)
726
727    def test_invalid_grammar(self):
728        test_fragment = self.create_fragment_file(u"""
729[mapping:test]
730archive:
731    lib.a
732""")
733
734        with self.assertRaises(ParseFatalException):
735            FragmentFile(test_fragment, self.sdkconfig)
736
737        test_fragment = self.create_fragment_file(u"""
738[mapping:test]
739entries:
740    * (default)
741""")
742
743        with self.assertRaises(ParseFatalException):
744            FragmentFile(test_fragment, self.sdkconfig)
745
746        test_fragment = self.create_fragment_file(u"""
747[mapping:test]
748archive: lib.a
749entries:
750    obj: (noflash)
751""")
752
753        with self.assertRaises(ParseException):
754            FragmentFile(test_fragment, self.sdkconfig)
755
756        test_fragment = self.create_fragment_file(u"""
757[mapping:test]
758archive: lib.a
759entries:
760    obj: ()
761""")
762
763        with self.assertRaises(ParseException):
764            FragmentFile(test_fragment, self.sdkconfig)
765
766        test_fragment = self.create_fragment_file(u"""
767[mapping:test]
768archive: lib.a
769entries:
770    obj:symbol
771""")
772
773        with self.assertRaises(ParseException):
774            FragmentFile(test_fragment, self.sdkconfig)
775
776        test_fragment = self.create_fragment_file(u"""
777[mapping:test]
778archive: lib.a
779entries:
780    (noflash)
781""")
782
783        with self.assertRaises(ParseException):
784            FragmentFile(test_fragment, self.sdkconfig)
785
786        test_fragment = self.create_fragment_file(u"""
787[mapping:test]
788archive: lib.a
789entries:
790    obj:* (noflash)
791""")
792
793        with self.assertRaises(ParseException):
794            FragmentFile(test_fragment, self.sdkconfig)
795
796        test_fragment = self.create_fragment_file(u"""
797[mapping:test]
798archive: lib.a
799entries:
800    :symbol (noflash)
801""")
802
803        with self.assertRaises(ParseException):
804            FragmentFile(test_fragment, self.sdkconfig)
805
806        test_fragment = self.create_fragment_file(u"""
807[mapping:test]
808archive: lib.a
809entries:
810    *:symbol (noflash)
811""")
812
813        with self.assertRaises(ParseException):
814            FragmentFile(test_fragment, self.sdkconfig)
815
816    def test_keep_flag(self):
817        # Test parsing combinations and orders of flags
818        test_fragment = self.create_fragment_file(u"""
819[mapping:map]
820archive: libmain.a
821entries:
822    obj1 (default);
823        text->flash_text KEEP(),
824        rodata->flash_rodata KEEP() KEEP()
825""")
826        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
827
828        fragment = fragment_file.fragments[0]
829
830        expected = [('text', 'flash_text', [Mapping.Keep()]),
831                    ('rodata', 'flash_rodata', [Mapping.Keep(), Mapping.Keep()])]
832        actual = fragment.flags[('obj1', None, 'default')]
833
834        self.assertEqual(expected, actual)
835
836    def test_align_flag(self):
837        # Test parsing combinations and orders of flags
838        test_fragment = self.create_fragment_file(u"""
839[mapping:map]
840archive: libmain.a
841entries:
842    obj1 (default);
843        text->flash_text ALIGN(8),
844        rodata->flash_rodata ALIGN(8, pre),
845        data->dram0_data ALIGN(8, pre, post),
846        bss->dram0_bss ALIGN(8, post),
847        common->dram0_bss ALIGN(8, pre, post) ALIGN(8)
848""")
849
850        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
851        fragment = fragment_file.fragments[0]
852
853        expected = [('text', 'flash_text', [Mapping.Align(8, True, False)]),
854                    ('rodata', 'flash_rodata', [Mapping.Align(8, True, False)]),
855                    ('data', 'dram0_data', [Mapping.Align(8, True, True)]),
856                    ('bss', 'dram0_bss', [Mapping.Align(8, False, True)]),
857                    ('common', 'dram0_bss', [Mapping.Align(8, True, True), Mapping.Align(8, True, False)])]
858        actual = fragment.flags[('obj1', None, 'default')]
859
860        self.assertEqual(expected, actual)
861
862        # Wrong post, pre order
863        test_fragment = self.create_fragment_file(u"""
864[mapping:map]
865archive: libmain.a
866entries:
867    obj1 (noflash)
868        text->iram0_text ALIGN(8, post, pre)
869""")
870
871        with self.assertRaises(ParseFatalException):
872            FragmentFile(test_fragment, self.sdkconfig)
873
874    def test_sort_flag(self):
875        # Test parsing combinations and orders of flags
876        test_fragment = self.create_fragment_file(u"""
877[mapping:map]
878archive: libmain.a
879entries:
880    obj1 (default);
881        text->flash_text SORT(name),
882        rodata->flash_rodata SORT(alignment),
883        data->dram0_data SORT(init_priority),
884        bss->dram0_bss SORT(name, alignment),
885        common->dram0_bss SORT(alignment, name),
886        iram->iram0_text SORT(name, name),
887        dram->dram0_data SORT(alignment, alignment)
888""")
889
890        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
891        fragment = fragment_file.fragments[0]
892
893        expected = [('text', 'flash_text', [Mapping.Sort('name')]),
894                    ('rodata', 'flash_rodata', [Mapping.Sort('alignment')]),
895                    ('data', 'dram0_data', [Mapping.Sort('init_priority')]),
896                    ('bss', 'dram0_bss', [Mapping.Sort('name', 'alignment')]),
897                    ('common', 'dram0_bss', [Mapping.Sort('alignment', 'name')]),
898                    ('iram', 'iram0_text', [Mapping.Sort('name', 'name')]),
899                    ('dram', 'dram0_data', [Mapping.Sort('alignment', 'alignment')])]
900        actual = fragment.flags[('obj1', None, 'default')]
901        self.assertEqual(expected, actual)
902
903        test_fragment = self.create_fragment_file(u"""
904[mapping:map]
905archive: libmain.a
906entries:
907    obj1 (default)
908        text->iram0_text SORT(name) SORT(alignment)
909""")
910
911    def test_surround_flag(self):
912        # Test parsing combinations and orders of flags
913        test_fragment = self.create_fragment_file(u"""
914[mapping:map]
915archive: libmain.a
916entries:
917    obj1 (default);
918        text->flash_text SURROUND(sym1)
919""")
920
921        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
922        fragment = fragment_file.fragments[0]
923
924        expected = [('text', 'flash_text', [Mapping.Surround('sym1')])]
925        actual = fragment.flags[('obj1', None, 'default')]
926        self.assertEqual(expected, actual)
927
928    def test_flag_order(self):
929        # Test that the order in which the flags are specified is retained
930        test_fragment = self.create_fragment_file(u"""
931[mapping:map]
932archive: libmain.a
933entries:
934    obj1 (default);
935        text->flash_text ALIGN(4) KEEP() SURROUND(sym1) ALIGN(8) SORT(name),
936        rodata->flash_rodata KEEP() ALIGN(4) KEEP() SURROUND(sym1) ALIGN(8) ALIGN(4) SORT(name)
937""")
938        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
939        fragment = fragment_file.fragments[0]
940
941        expected = [('text', 'flash_text', [Mapping.Align(4, True, False),
942                                            Mapping.Keep(),
943                                            Mapping.Surround('sym1'),
944                                            Mapping.Align(8, True, False),
945                                            Mapping.Sort('name')]),
946                    ('rodata', 'flash_rodata', [Mapping.Keep(),
947                                                Mapping.Align(4, True, False),
948                                                Mapping.Keep(),
949                                                Mapping.Surround('sym1'),
950                                                Mapping.Align(8, True, False),
951                                                Mapping.Align(4, True, False),
952                                                Mapping.Sort('name')])]
953        actual = fragment.flags[('obj1', None, 'default')]
954        self.assertEqual(expected, actual)
955
956    def test_flags_entries_multiple_flags(self):
957        # Not an error, generation step handles this, since
958        # it that step has a more complete information
959        # about all mappings.
960        test_fragment = self.create_fragment_file(u"""
961[mapping:map]
962archive: libmain.a
963entries:
964    obj1 (default);
965        text->flash_text ALIGN(4) KEEP() SURROUND(sym1) SORT(name),
966        text->flash_text ALIGN(4) KEEP() SURROUND(sym1) SORT(name)
967""")
968        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
969        fragment = fragment_file.fragments[0]
970
971        expected = [('text', 'flash_text', [Mapping.Align(4, True, False),
972                                            Mapping.Keep(),
973                                            Mapping.Surround('sym1'),
974                                            Mapping.Sort('name')]),
975                    ('text', 'flash_text', [Mapping.Align(4, True, False),
976                                            Mapping.Keep(),
977                                            Mapping.Surround('sym1'),
978                                            Mapping.Sort('name')])]
979        actual = fragment.flags[('obj1', None, 'default')]
980        self.assertEqual(expected, actual)
981
982    def test_flags_entries_multiple_flags_and_entries(self):
983        # Not an error, generation step handles this, since
984        # it that step has a more complete information
985        # about all mappings. This can happen across multiple
986        # mapping fragments.
987        test_fragment = self.create_fragment_file(u"""
988[mapping:map]
989archive: libmain.a
990entries:
991    obj1 (default);
992        text->flash_text ALIGN(4) KEEP() SURROUND(sym1) SORT(name)
993    obj1 (default);
994        text->flash_text ALIGN(4) KEEP() SURROUND(sym1) SORT(name)
995""")
996        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
997        fragment = fragment_file.fragments[0]
998
999        expected = [('text', 'flash_text', [Mapping.Align(4, True, False),
1000                                            Mapping.Keep(),
1001                                            Mapping.Surround('sym1'),
1002                                            Mapping.Sort('name')]),
1003                    ('text', 'flash_text', [Mapping.Align(4, True, False),
1004                                            Mapping.Keep(),
1005                                            Mapping.Surround('sym1'),
1006                                            Mapping.Sort('name')])]
1007        actual = fragment.flags[('obj1', None, 'default')]
1008        self.assertEqual(expected, actual)
1009
1010
1011class DeprecatedMappingTest(FragmentTest):
1012
1013    def test_valid_grammar(self):
1014        test_fragment = self.create_fragment_file(u"""
1015[mapping]
1016archive: lib.a
1017entries:
1018    obj:symbol (noflash)
1019    # Comments should not matter
1020    obj (noflash)
1021    # Nor should whitespace
1022                    obj  :     symbol_2 (    noflash )
1023        obj_2  (    noflash )
1024    * (noflash)
1025""")
1026        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
1027        self.assertEqual('lib.a', fragment_file.fragments[0].archive)
1028        self.assertEqual('lib_a', fragment_file.fragments[0].name)
1029
1030        expected = {('obj', 'symbol', 'noflash'),
1031                    ('obj', None, 'noflash'),
1032                    ('obj', 'symbol_2', 'noflash'),
1033                    ('obj_2', None, 'noflash'),
1034                    ('*', None, 'noflash')
1035                    }
1036
1037        self.assertEqual(expected, fragment_file.fragments[0].entries)
1038
1039    def test_explicit_blank_default_w_others(self):
1040        test_fragment = self.create_fragment_file(u"""
1041[mapping]
1042archive: lib.a
1043entries:
1044    : A = n
1045    obj_a (noflash)
1046    : default
1047""")
1048        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
1049        expected = {('*', None, 'default')}
1050
1051        self.assertEqual(expected, fragment_file.fragments[0].entries)
1052
1053    def test_implicit_blank_default_w_others(self):
1054        test_fragment = self.create_fragment_file(u"""
1055[mapping]
1056archive: lib.a
1057entries:
1058    : A = n
1059    obj_a (noflash)
1060""")
1061
1062        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
1063        expected = {('*', None, 'default')}
1064
1065        self.assertEqual(expected, fragment_file.fragments[0].entries)
1066
1067    def test_explicit_blank_default(self):
1068        test_fragment = self.create_fragment_file(u"""
1069[mapping]
1070archive: lib.a
1071entries:
1072    : default
1073""")
1074        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
1075        expected = {('*', None, 'default')}
1076
1077        self.assertEqual(expected, fragment_file.fragments[0].entries)
1078
1079    def test_implicit_blank_default(self):
1080        test_fragment = self.create_fragment_file(u"""
1081[mapping]
1082archive: lib.a
1083entries:
1084    : default
1085""")
1086        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
1087        expected = {('*', None, 'default')}
1088
1089        self.assertEqual(expected, fragment_file.fragments[0].entries)
1090
1091    def test_multiple_entries(self):
1092        test_fragment = self.create_fragment_file(u"""
1093[mapping]
1094archive: lib.a
1095entries:
1096    : A = n
1097    obj_a1 (noflash)
1098    obj_a2 (noflash)
1099    : B = n
1100    obj_b1 (noflash)
1101    obj_b2 (noflash)
1102    obj_b3 (noflash)
1103    : C = n
1104    obj_c1 (noflash)
1105""")
1106
1107        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
1108        expected = {('obj_b1', None, 'noflash'),
1109                    ('obj_b2', None, 'noflash'),
1110                    ('obj_b3', None, 'noflash')}
1111        self.assertEqual(expected, fragment_file.fragments[0].entries)
1112
1113    def test_blank_entries(self):
1114        test_fragment = self.create_fragment_file(u"""
1115[mapping]
1116archive: lib.a
1117entries:
1118    : A = n
1119    obj_a (noflash)
1120    : B = n
1121    : C = n
1122    obj_c (noflash)
1123    : default
1124    obj (noflash)
1125""")
1126        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
1127        expected = {('*', None, 'default')}
1128        self.assertEqual(expected, fragment_file.fragments[0].entries)
1129
1130    def test_blank_first_condition(self):
1131        test_fragment = self.create_fragment_file(u"""
1132[mapping]
1133archive: lib.a
1134entries:
1135    obj_a (noflash)
1136    : CONFIG_B = y
1137    obj_b (noflash)
1138""")
1139
1140        with self.assertRaises(ParseException):
1141            FragmentFile(test_fragment, self.sdkconfig)
1142
1143    def test_nonlast_default_1(self):
1144        test_fragment = self.create_fragment_file(u"""
1145[mapping]
1146archive: lib.a
1147entries:
1148    : default
1149    obj_a (noflash)
1150    : CONFIG_A = y
1151    obj_A (noflash)
1152""")
1153
1154        with self.assertRaises(ParseException):
1155            FragmentFile(test_fragment, self.sdkconfig)
1156
1157    def test_nonlast_default_2(self):
1158        test_fragment = self.create_fragment_file(u"""
1159[mapping]
1160archive: lib.a
1161entries:
1162    : A = y
1163    obj_A (noflash)
1164    : default
1165    obj_a (noflash)
1166    : B = y
1167    obj_B (noflash
1168""")
1169
1170        with self.assertRaises(ParseException):
1171            FragmentFile(test_fragment, self.sdkconfig)
1172
1173    def test_nonlast_default_3(self):
1174        test_fragment = self.create_fragment_file(u"""
1175[mapping]
1176archive: lib.a
1177entries:
1178    : A = y
1179    obj_A (noflash)
1180    :
1181    obj_a (noflash)
1182    : B = y
1183    obj_B (noflash
1184""")
1185
1186        with self.assertRaises(ParseException):
1187            FragmentFile(test_fragment, self.sdkconfig)
1188
1189    def test_duplicate_default_1(self):
1190        test_fragment = self.create_fragment_file(u"""
1191[mapping]
1192archive: lib.a
1193entries:
1194    : CONFIG_A = y
1195    obj_A (noflash)
1196    : default
1197    obj_a (noflash)
1198    : CONFIG_B = y
1199    obj_B (noflash)
1200    : default
1201    obj_a (noflash)
1202""")
1203
1204        with self.assertRaises(ParseException):
1205            FragmentFile(test_fragment, self.sdkconfig)
1206
1207    def test_duplicate_default_2(self):
1208        test_fragment = self.create_fragment_file(u"""
1209[mapping]
1210archive: lib.a
1211entries:
1212    : CONFIG_A = y
1213    obj_A (noflash)
1214    : CONFIG_B = y
1215    obj_a (noflash)
1216    : default
1217    obj_B (noflash)
1218    :
1219    obj_a (noflash)
1220""")
1221
1222        with self.assertRaises(ParseException):
1223            FragmentFile(test_fragment, self.sdkconfig)
1224
1225    def test_mixed_deprecated_mapping(self):
1226        test_fragment = self.create_fragment_file(u"""
1227[mapping]
1228archive: lib.a
1229entries:
1230    : A = n
1231    obj_A (noflash)
1232    : default
1233    obj_B (noflash)
1234
1235
1236[mapping:test]
1237archive: lib.a
1238entries:
1239    if A = n:
1240        obj_A (noflash)
1241    else:
1242        obj_B (noflash)
1243""")
1244
1245        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
1246        self.assertEqual(2, len(fragment_file.fragments))
1247
1248        self.assertEqual(fragment_file.fragments[0].entries,
1249                         fragment_file.fragments[1].entries)
1250
1251
1252if __name__ == '__main__':
1253    unittest.main()
1254