1#!/usr/bin/env python
2#
3# Copyright 2021 Espressif Systems (Shanghai) CO LTD
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#     http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17
18import sys
19import unittest
20
21try:
22    from output_commands import AlignAtAddress, InputSectionDesc, SymbolAtAddress
23except ImportError:
24    sys.path.append('../')
25    from output_commands import InputSectionDesc, SymbolAtAddress, AlignAtAddress
26
27from entity import Entity
28
29SECTIONS = ['.text', '.text.*', '.literal', '.literal.*']
30
31FREERTOS = Entity('libfreertos.a')
32CROUTINE = Entity('libfreertos.a', 'croutine')
33
34
35class InputSectionDescTest(unittest.TestCase):
36
37    def test_catch_all_placement(self):
38        # Test default (catch-all) command
39        expected = '*(.literal .literal.* .text .text.*)'
40
41        desc = InputSectionDesc(Entity(), SECTIONS)
42        self.assertEqual(expected, str(desc))
43
44        desc = InputSectionDesc(Entity(Entity.ALL), SECTIONS)
45        self.assertEqual(expected, str(desc))
46
47    def test_lib_placement(self):
48        # Test library placement command
49        expected = '*libfreertos.a:(.literal .literal.* .text .text.*)'
50
51        desc = InputSectionDesc(Entity('libfreertos.a'), SECTIONS)
52        self.assertEqual(expected, str(desc))
53
54        desc = InputSectionDesc(Entity('libfreertos.a', Entity.ALL), SECTIONS)
55        self.assertEqual(expected, str(desc))
56
57        desc = InputSectionDesc(Entity('libfreertos.a', None, Entity.ALL), SECTIONS)
58        self.assertEqual(expected, str(desc))
59
60        desc = InputSectionDesc(Entity('libfreertos.a', Entity.ALL, Entity.ALL), SECTIONS)
61        self.assertEqual(expected, str(desc))
62
63    def test_obj_placement(self):
64        # Test object placement command
65        expected = '*libfreertos.a:croutine.*(.literal .literal.* .text .text.*)'
66
67        desc = InputSectionDesc(Entity('libfreertos.a', 'croutine'), SECTIONS)
68        self.assertEqual(expected, str(desc))
69
70        desc = InputSectionDesc(Entity('libfreertos.a', 'croutine'), SECTIONS)
71        self.assertEqual(expected, str(desc))
72
73        desc = InputSectionDesc(Entity('libfreertos.a', 'croutine', Entity.ALL), SECTIONS)
74        self.assertEqual(expected, str(desc))
75
76        # Disambugated placement
77        expected = '*libfreertos.a:croutine.c.*(.literal .literal.* .text .text.*)'
78
79        desc = InputSectionDesc(Entity('libfreertos.a', 'croutine.c'), SECTIONS)
80        self.assertEqual(expected, str(desc))
81
82    def test_invalid_entity(self):
83        # Invalid entity specification
84        with self.assertRaises(AssertionError):
85            InputSectionDesc(Entity('libfreertos.a', 'croutine', 'prvCheckPendingReadyList'), SECTIONS)
86
87        with self.assertRaises(AssertionError):
88            InputSectionDesc(Entity('libfreertos.a', 'croutine'), SECTIONS, [Entity()])
89
90        with self.assertRaises(AssertionError):
91            InputSectionDesc(Entity('libfreertos.a', 'croutine'), SECTIONS, [Entity('libfreertos.a', 'croutine', 'prvCheckPendingReadyList')])
92
93    def test_exclusions(self):
94        # Test exclusions
95
96        # Library
97        expected = ('*libfreertos.a:croutine.*'
98                    '(EXCLUDE_FILE(*libfreertos.a) '
99                    '.literal EXCLUDE_FILE(*libfreertos.a) '
100                    '.literal.* EXCLUDE_FILE(*libfreertos.a) '
101                    '.text EXCLUDE_FILE(*libfreertos.a) .text.*)')
102        desc = InputSectionDesc(CROUTINE, SECTIONS, [FREERTOS])
103        self.assertEqual(expected, str(desc))
104
105        # Object
106        expected = ('*libfreertos.a:croutine.*'
107                    '(EXCLUDE_FILE(*libfreertos.a:croutine.*) '
108                    '.literal EXCLUDE_FILE(*libfreertos.a:croutine.*) '
109                    '.literal.* EXCLUDE_FILE(*libfreertos.a:croutine.*) '
110                    '.text EXCLUDE_FILE(*libfreertos.a:croutine.*) .text.*)')
111        desc = InputSectionDesc(CROUTINE, SECTIONS, [CROUTINE])
112        self.assertEqual(expected, str(desc))
113
114        # Multiple exclusions
115        expected = ('*libfreertos.a:croutine.*'
116                    '(EXCLUDE_FILE(*libfreertos.a *libfreertos.a:croutine.*) '
117                    '.literal EXCLUDE_FILE(*libfreertos.a *libfreertos.a:croutine.*) '
118                    '.literal.* EXCLUDE_FILE(*libfreertos.a *libfreertos.a:croutine.*) '
119                    '.text EXCLUDE_FILE(*libfreertos.a *libfreertos.a:croutine.*) .text.*)')
120        desc = InputSectionDesc(CROUTINE, SECTIONS, [FREERTOS, CROUTINE])
121        self.assertEqual(expected, str(desc))
122
123        # Disambugated exclusion
124        expected = ('*libfreertos.a:croutine.*'
125                    '(EXCLUDE_FILE(*libfreertos.a:croutine.c.*) '
126                    '.literal EXCLUDE_FILE(*libfreertos.a:croutine.c.*) '
127                    '.literal.* EXCLUDE_FILE(*libfreertos.a:croutine.c.*) '
128                    '.text EXCLUDE_FILE(*libfreertos.a:croutine.c.*) .text.*)')
129        desc = InputSectionDesc(CROUTINE, SECTIONS, [Entity('libfreertos.a', 'croutine.c')])
130        self.assertEqual(expected, str(desc))
131
132    def test_empty_sections(self):
133        # Test empty sections
134        expected = '*libfreertos.a:croutine.*( )'
135
136        desc = InputSectionDesc(Entity('libfreertos.a', 'croutine'), [])
137        self.assertEqual(expected, str(desc))
138
139    def test_keep(self):
140        # Test KEEP
141        expected = 'KEEP(*libfreertos.a:croutine.*( ))'
142
143        desc = InputSectionDesc(Entity('libfreertos.a', 'croutine'), [], keep=True)
144        self.assertEqual(expected, str(desc))
145
146    def test_sort(self):
147        # Test sort
148        expected = ('*libfreertos.a:croutine.*('
149                    'SORT(EXCLUDE_FILE(*libfreertos.a:croutine.c.*) .literal) '
150                    'SORT(EXCLUDE_FILE(*libfreertos.a:croutine.c.*) .literal.*) '
151                    'SORT(EXCLUDE_FILE(*libfreertos.a:croutine.c.*) .text) '
152                    'SORT(EXCLUDE_FILE(*libfreertos.a:croutine.c.*) .text.*)'
153                    ')')
154        desc = InputSectionDesc(CROUTINE, SECTIONS, [Entity('libfreertos.a', 'croutine.c')], keep=False, sort=(None, None))
155        self.assertEqual(expected, str(desc))
156
157        expected = ('*libfreertos.a:croutine.*('
158                    'SORT_BY_NAME(EXCLUDE_FILE(*libfreertos.a:croutine.c.*) .literal) '
159                    'SORT_BY_NAME(EXCLUDE_FILE(*libfreertos.a:croutine.c.*) .literal.*) '
160                    'SORT_BY_NAME(EXCLUDE_FILE(*libfreertos.a:croutine.c.*) .text) '
161                    'SORT_BY_NAME(EXCLUDE_FILE(*libfreertos.a:croutine.c.*) .text.*)'
162                    ')')
163        desc = InputSectionDesc(CROUTINE, SECTIONS, [Entity('libfreertos.a', 'croutine.c')], keep=False, sort=('name', None))
164        self.assertEqual(expected, str(desc))
165
166        expected = ('*libfreertos.a:croutine.*('
167                    'SORT_BY_ALIGNMENT(EXCLUDE_FILE(*libfreertos.a:croutine.c.*) .literal) '
168                    'SORT_BY_ALIGNMENT(EXCLUDE_FILE(*libfreertos.a:croutine.c.*) .literal.*) '
169                    'SORT_BY_ALIGNMENT(EXCLUDE_FILE(*libfreertos.a:croutine.c.*) .text) '
170                    'SORT_BY_ALIGNMENT(EXCLUDE_FILE(*libfreertos.a:croutine.c.*) .text.*)'
171                    ')')
172        desc = InputSectionDesc(CROUTINE, SECTIONS, [Entity('libfreertos.a', 'croutine.c')], keep=False, sort=('alignment', None))
173        self.assertEqual(expected, str(desc))
174
175        expected = ('*libfreertos.a:croutine.*('
176                    'SORT_BY_INIT_PRIORITY(EXCLUDE_FILE(*libfreertos.a:croutine.c.*) .literal) '
177                    'SORT_BY_INIT_PRIORITY(EXCLUDE_FILE(*libfreertos.a:croutine.c.*) .literal.*) '
178                    'SORT_BY_INIT_PRIORITY(EXCLUDE_FILE(*libfreertos.a:croutine.c.*) .text) '
179                    'SORT_BY_INIT_PRIORITY(EXCLUDE_FILE(*libfreertos.a:croutine.c.*) .text.*)'
180                    ')')
181        desc = InputSectionDesc(CROUTINE, SECTIONS, [Entity('libfreertos.a', 'croutine.c')], keep=False, sort=('init_priority', None))
182        self.assertEqual(expected, str(desc))
183
184        expected = ('*libfreertos.a:croutine.*('
185                    'SORT_BY_NAME(SORT_BY_ALIGNMENT(EXCLUDE_FILE(*libfreertos.a:croutine.c.*) .literal)) '
186                    'SORT_BY_NAME(SORT_BY_ALIGNMENT(EXCLUDE_FILE(*libfreertos.a:croutine.c.*) .literal.*)) '
187                    'SORT_BY_NAME(SORT_BY_ALIGNMENT(EXCLUDE_FILE(*libfreertos.a:croutine.c.*) .text)) '
188                    'SORT_BY_NAME(SORT_BY_ALIGNMENT(EXCLUDE_FILE(*libfreertos.a:croutine.c.*) .text.*))'
189                    ')')
190        desc = InputSectionDesc(CROUTINE, SECTIONS, [Entity('libfreertos.a', 'croutine.c')], keep=False, sort=('name', 'alignment'))
191        self.assertEqual(expected, str(desc))
192
193        expected = ('*libfreertos.a:croutine.*('
194                    'SORT_BY_NAME(SORT_BY_NAME(EXCLUDE_FILE(*libfreertos.a:croutine.c.*) .literal)) '
195                    'SORT_BY_NAME(SORT_BY_NAME(EXCLUDE_FILE(*libfreertos.a:croutine.c.*) .literal.*)) '
196                    'SORT_BY_NAME(SORT_BY_NAME(EXCLUDE_FILE(*libfreertos.a:croutine.c.*) .text)) '
197                    'SORT_BY_NAME(SORT_BY_NAME(EXCLUDE_FILE(*libfreertos.a:croutine.c.*) .text.*))'
198                    ')')
199        desc = InputSectionDesc(CROUTINE, SECTIONS, [Entity('libfreertos.a', 'croutine.c')], keep=False, sort=('name', 'name'))
200        self.assertEqual(expected, str(desc))
201
202        expected = ('*libfreertos.a:croutine.*('
203                    'SORT_BY_ALIGNMENT(SORT_BY_NAME(EXCLUDE_FILE(*libfreertos.a:croutine.c.*) .literal)) '
204                    'SORT_BY_ALIGNMENT(SORT_BY_NAME(EXCLUDE_FILE(*libfreertos.a:croutine.c.*) .literal.*)) '
205                    'SORT_BY_ALIGNMENT(SORT_BY_NAME(EXCLUDE_FILE(*libfreertos.a:croutine.c.*) .text)) '
206                    'SORT_BY_ALIGNMENT(SORT_BY_NAME(EXCLUDE_FILE(*libfreertos.a:croutine.c.*) .text.*))'
207                    ')')
208        desc = InputSectionDesc(CROUTINE, SECTIONS, [Entity('libfreertos.a', 'croutine.c')], keep=False, sort=('alignment', 'name'))
209        self.assertEqual(expected, str(desc))
210
211        expected = ('*libfreertos.a:croutine.*('
212                    'SORT_BY_ALIGNMENT(SORT_BY_ALIGNMENT(EXCLUDE_FILE(*libfreertos.a:croutine.c.*) .literal)) '
213                    'SORT_BY_ALIGNMENT(SORT_BY_ALIGNMENT(EXCLUDE_FILE(*libfreertos.a:croutine.c.*) .literal.*)) '
214                    'SORT_BY_ALIGNMENT(SORT_BY_ALIGNMENT(EXCLUDE_FILE(*libfreertos.a:croutine.c.*) .text)) '
215                    'SORT_BY_ALIGNMENT(SORT_BY_ALIGNMENT(EXCLUDE_FILE(*libfreertos.a:croutine.c.*) .text.*))'
216                    ')')
217        desc = InputSectionDesc(CROUTINE, SECTIONS, [Entity('libfreertos.a', 'croutine.c')], keep=False, sort=('alignment', 'alignment'))
218        self.assertEqual(expected, str(desc))
219
220
221class SymbolAtAddressTest(unittest.TestCase):
222
223    def test_symbol(self):
224        symbol = 'test_symbol'
225        expected = '%s = ABSOLUTE(.);' % symbol
226
227        desc = SymbolAtAddress(symbol)
228        self.assertEqual(expected, str(desc))
229
230
231class AlignAtAddressTest(unittest.TestCase):
232
233    def test_align(self):
234        align = 8
235        expected = '. = ALIGN(%d);' % 8
236
237        desc = AlignAtAddress(align)
238        self.assertEqual(expected, str(desc))
239
240
241if __name__ == '__main__':
242    unittest.main()
243