]> granicus.if.org Git - esp-idf/commitdiff
ldgen: update tests for common fragment parsing
authorRenz Christian Bagaporo <renz@espressif.com>
Tue, 19 Mar 2019 06:36:04 +0000 (14:36 +0800)
committerRenz Christian Bagaporo <renz@espressif.com>
Thu, 4 Apr 2019 07:56:46 +0000 (15:56 +0800)
tools/ldgen/test/data/Kconfig
tools/ldgen/test/test_fragments.py
tools/ldgen/test/test_generation.py

index c813c008cface7e7b95fef61bb70f32c76962855..cb0b364d17df8cca3eb2fe661cde6d8d7c0f02de 100644 (file)
@@ -1,7 +1,19 @@
 menu "Test config"
 
     config PERFORMANCE_LEVEL
-        int "Performance level"
+        int
         range 0 3
+        prompt "Performance level"
 
+    config A
+        bool
+        default "y"
+
+    config B
+        bool
+        default "n"
+
+    config C
+        bool
+        default "y"
 endmenu
index d246a2262549a27e3fa2e5d5da2348a9bcb4d632..1d2efbe309832568b511aa48edc41fa18da6fe3d 100755 (executable)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-
-import unittest
 import sys
-from pyparsing import ParseException
-from pyparsing import restOfLine
+import unittest
+
+from io import StringIO
+from pyparsing import Word, ParseException, ParseFatalException, alphanums
 
 try:
-    import fragments
+    from fragments import FragmentFile, FRAGMENT_TYPES, Fragment, KeyGrammar
+    from sdkconfig import SDKConfig
 except ImportError:
     sys.path.append('../')
-    import fragments
-
-from sdkconfig import SDKConfig
-
-
-class FragmentTest(unittest.TestCase):
-
-    def parse(self, text):
-        self.parser.ignore("#" + restOfLine)
-        fragment = self.parser.parseString(text, parseAll=True)
-        return fragment[0]
-
-
-class SectionsTest(FragmentTest):
-
-    def setUp(self):
-        self.parser = fragments.Sections.get_fragment_grammar()
-
-    def test_valid_entries(self):
-        valid_entries = """
-        [sections:test]
-        entries:
-            .section1
-                .section2
-
-            # Section 3 should not exist
-            # section3
-            .section4
+    from fragments import FragmentFile, FRAGMENT_TYPES, Fragment, KeyGrammar
+    from sdkconfig import SDKConfig
 
-            # This is a comment
 
-            .section5
-        """
+class SampleFragment(Fragment):
 
-        sections = self.parse(valid_entries)
+    grammars = {
+        "key_1": KeyGrammar(Word(alphanums + "_").setResultsName("value"), 0, None, True),
+        "key_2": KeyGrammar(Word(alphanums + "_").setResultsName("value"), 0, None, False),
+        "key_3": KeyGrammar(Word(alphanums + "_").setResultsName("value"), 3, 5, False)
+    }
 
-        self.assertEqual("test", sections.name)
+    def set_key_value(self, key, parse_results):
+        if key == "key_1":
+            self.key_1 = list()
+            for result in parse_results:
+                self.key_1.append(result["value"])
+        elif key == "key_2":
+            self.key_2 = list()
+            for result in parse_results:
+                self.key_2.append(result["value"])
 
-        entries = sections.entries
+    def get_key_grammars(self):
+        return self.__class__.grammars
 
-        expected = {
-            ".section1",
-            ".section2",
-            ".section4",
-            ".section5"
-        }
 
-        self.assertEqual(set(entries), expected)
+FRAGMENT_TYPES["test"] = SampleFragment
 
-    def test_blank_entries(self):
-        blank_entries = """
-        [sections:test]
-        entries:
-        """
 
-        with self.assertRaises(ParseException):
-            self.parse(blank_entries)
-
-    def test_invalid_names(self):
-        with_spaces = """
-        [sections:invalid name 1]
-        entries:
-        """
-
-        begins_with_number = """
-        [sections:2invalid_name]
-        entries:
-        """
-
-        with_special_character = """
-        [sections:invalid_name~]
-        entries:
-        """
-
-        with self.assertRaises(ParseException):
-            self.parse(with_spaces)
+class FragmentTest(unittest.TestCase):
 
+    def setUp(self):
+        self.sdkconfig = SDKConfig("data/Kconfig", "data/sdkconfig")
+
+    @staticmethod
+    def create_fragment_file(contents, name="test_fragment.lf"):
+        f = StringIO(contents)
+        f.name = name
+        return f
+
+    def test_basic(self):
+        test_fragment = self.create_fragment_file(u"""
+[test:test]
+key_1:
+    value_1
+    value_2 # comments should be ignored
+    value_3
+# this is a comment as well
+key_2: value_a
+
+# this is the last comment
+""")
+        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
+
+        self.assertEqual(len(fragment_file.fragments[0].key_1), 3)
+        self.assertEqual(fragment_file.fragments[0].key_1[0], "value_1")
+        self.assertEqual(fragment_file.fragments[0].key_1[1], "value_2")
+        self.assertEqual(fragment_file.fragments[0].key_1[2], "value_3")
+        self.assertEqual(len(fragment_file.fragments[0].key_2), 1)
+        self.assertEqual(fragment_file.fragments[0].key_2[0], "value_a")
+
+    def test_duplicate_keys(self):
+        test_fragment = self.create_fragment_file(u"""
+[test:test]
+key_1: value_1
+key_1: value_a
+""")
+        with self.assertRaises(ParseFatalException):
+            FragmentFile(test_fragment, self.sdkconfig)
+
+    def test_empty_key(self):
+        test_fragment = self.create_fragment_file(u"""
+[test:test]
+key_1:
+""")
         with self.assertRaises(ParseException):
-            self.parse(begins_with_number)
+            FragmentFile(test_fragment, self.sdkconfig)
+
+    def test_conditional(self):
+        test_fragment = self.create_fragment_file(u"""
+[test:test]
+key_1:
+    value_1
+    if A = y:
+        value_2
+    value_3
+    if A = n:
+        value_4
+    if B = n:
+        value_5
+""")
+        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
+        self.assertEqual(fragment_file.fragments[0].key_1[0], "value_1")
+        self.assertEqual(fragment_file.fragments[0].key_1[1], "value_2")
+        self.assertEqual(fragment_file.fragments[0].key_1[2], "value_3")
+        self.assertEqual(fragment_file.fragments[0].key_1[3], "value_5")
+
+        test_fragment = self.create_fragment_file(u"""
+[test:test]
+key_1:
+    value_1
+    if B = y:
+        value_2
+    elif C = y:
+        value_3
+    elif A = y:
+        value_4
+    else:
+        value_5
+    value_6
+""")
+
+        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
+        self.assertEqual(fragment_file.fragments[0].key_1[0], "value_1")
+        self.assertEqual(fragment_file.fragments[0].key_1[1], "value_3")
+        self.assertEqual(fragment_file.fragments[0].key_1[2], "value_6")
+
+        test_fragment = self.create_fragment_file(u"""
+[test:test]
+key_1:
+    value_1
+    if A = y:
+        value_2
+        if B = y:
+            value_3
+        else:
+            value_4
+            if C = y:
+                value_5
+            value_6
+        value_7
+key_2:
+    value_a
+    if B != y:
+        value_b
+""")
+
+        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
+        self.assertEqual(fragment_file.fragments[0].key_1[0], "value_1")
+        self.assertEqual(fragment_file.fragments[0].key_1[1], "value_2")
+        self.assertEqual(fragment_file.fragments[0].key_1[2], "value_4")
+        self.assertEqual(fragment_file.fragments[0].key_1[3], "value_5")
+        self.assertEqual(fragment_file.fragments[0].key_1[4], "value_6")
+        self.assertEqual(fragment_file.fragments[0].key_1[5], "value_7")
+        self.assertEqual(fragment_file.fragments[0].key_2[0], "value_a")
+        self.assertEqual(fragment_file.fragments[0].key_2[1], "value_b")
+
+        test_fragment = self.create_fragment_file(u"""
+[test:test]
+key_1:
+    if A = n:
+        value_2
+""")
+
+        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
+        self.assertEqual(len(fragment_file.fragments[0].key_1), 0)
+
+    def test_empty_file(self):
+        test_fragment = self.create_fragment_file(u"""
+
+
+
+
+""")
+
+        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
+        self.assertEqual(len(fragment_file.fragments), 0)
+
+    def test_setting_indent(self):
+        test_fragment = self.create_fragment_file(u"""
+[test:test]
+key_1:
+ value_1
+ value_2
+ value_3
+""")
+        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
+
+        self.assertEqual(len(fragment_file.fragments[0].key_1), 3)
+        self.assertEqual(fragment_file.fragments[0].key_1[0], "value_1")
+        self.assertEqual(fragment_file.fragments[0].key_1[1], "value_2")
+        self.assertEqual(fragment_file.fragments[0].key_1[2], "value_3")
+
+        test_fragment = self.create_fragment_file(u"""
+[test:test]
+key_1:
+ value_1
+  value_2 # first element dictates indent
+  value_3
+""")
+        with self.assertRaises(ParseFatalException):
+            FragmentFile(test_fragment, self.sdkconfig)
+
+    def test_values_num_limit(self):
+        test_fragment = self.create_fragment_file(u"""
+[test:test]
+key_1:
+    value_a
+key_3:
+    value_1
+    value_2
+    value_3
+""")
+        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
+
+        test_fragment = self.create_fragment_file(u"""
+[test:test]
+key_1:
+    value_a
+key_3:
+    value_1
+    value_2
+    value_3
+    value_4
+""")
+        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
+        self.assertEqual(len(fragment_file.fragments), 1)
+
+        test_fragment = self.create_fragment_file(u"""
+[test:test]
+key_1:
+    value_a
+key_3:
+    value_1
+    value_2
+    value_3
+    value_4
+    value_5
+""")
+        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
+        self.assertEqual(len(fragment_file.fragments), 1)
+
+        test_fragment = self.create_fragment_file(u"""
+[test:test]
+key_1:
+    value_a
+key_3:
+    value_1
+    value_2
+""")
+
+        with self.assertRaises(ParseFatalException):
+            FragmentFile(test_fragment, self.sdkconfig)
+
+        test_fragment = self.create_fragment_file(u"""
+[test:test]
+key_1:
+    value_a
+key_3:
+    value_1
+    value_2
+    value_3
+    value_4
+    value_5
+    value_6
+""")
+
+        with self.assertRaises(ParseFatalException):
+            FragmentFile(test_fragment, self.sdkconfig)
+
+    def test_unsupported_key(self):
+        test_fragment = self.create_fragment_file(u"""
+[test:test]
+key_1:
+    value_a
+key_4:
+    value_1
+""")
+
+        with self.assertRaises(ParseFatalException):
+            FragmentFile(test_fragment, self.sdkconfig)
+
+    def test_empty_fragment(self):
+        test_fragment = self.create_fragment_file(u"""
+[test:test]
+""")
 
         with self.assertRaises(ParseException):
-            self.parse(with_special_character)
+            FragmentFile(test_fragment, self.sdkconfig)
+
+    def test_empty_conditional(self):
+        test_fragment = self.create_fragment_file(u"""
+[test:test]
+key_1:
+    if B = y:
+    else:
+        value_1
+""")
+
+        with self.assertRaises(ParseFatalException):
+            FragmentFile(test_fragment, self.sdkconfig)
+
+        test_fragment = self.create_fragment_file(u"""
+[test:test]
+key_1:
+    if B = y:
+        value_1
+    else B = y:
+""")
+
+        with self.assertRaises(ParseFatalException):
+            FragmentFile(test_fragment, self.sdkconfig)
+
+        test_fragment = self.create_fragment_file(u"""
+[test:test]
+key_1:
+    if B = y:
+        value_1
+    elif B = y:
+    else:
+        value_2
+""")
+
+        with self.assertRaises(ParseFatalException):
+            FragmentFile(test_fragment, self.sdkconfig)
+
+    def test_out_of_order_conditional(self):
+        test_fragment = self.create_fragment_file(u"""
+[test:test]
+key_1:
+    elif B = y:
+        value_1
+    else:
+        value_2
+""")
+
+        with self.assertRaises(ParseFatalException):
+            FragmentFile(test_fragment, self.sdkconfig)
+
+        test_fragment = self.create_fragment_file(u"""
+[test:test]
+key_1:
+    else:
+        value_2
+""")
+
+        with self.assertRaises(ParseFatalException):
+            FragmentFile(test_fragment, self.sdkconfig)
+
+    def test_required_keys(self):
+        test_fragment = self.create_fragment_file(u"""
+[test:test]
+key_2:
+    value_1
+""")
+
+        with self.assertRaises(ParseFatalException):
+            FragmentFile(test_fragment, self.sdkconfig)
+
+    def test_multiple_fragments(self):
+        test_fragment = self.create_fragment_file(u"""
+[test:test1]
+key_1:
+    value_1
+
+[test:test2]
+key_1:
+    value_2
+""")
+
+        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
+
+        self.assertEqual(len(fragment_file.fragments), 2)
+        self.assertEqual(fragment_file.fragments[0].key_1[0], "value_1")
+        self.assertEqual(fragment_file.fragments[1].key_1[0], "value_2")
+
+    def test_whole_conditional_fragment(self):
+        test_fragment = self.create_fragment_file(u"""
+if B = y:
+    [test:test1]
+    key_1:
+        value_1
+else:
+    [test:test2]
+    key_1:
+        value_2
+
+    if A = y:
+        [test:test3]
+        key_1:
+            value_3
+            if C = y:
+                value_6
+
+    [test:test4]
+    key_1:
+        value_4
+
+[test:test5]
+key_1:
+    value_5
+""")
+
+        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
+        self.assertEqual(len(fragment_file.fragments), 4)
+        self.assertEqual(fragment_file.fragments[0].name, "test2")
+        self.assertEqual(fragment_file.fragments[1].name, "test3")
+        self.assertEqual(fragment_file.fragments[1].key_1[1], "value_6")
+        self.assertEqual(fragment_file.fragments[2].name, "test4")
+        self.assertEqual(fragment_file.fragments[3].name, "test5")
+
+    def test_equivalent_conditional_fragment(self):
+        test_fragment1 = self.create_fragment_file(u"""
+if A = y:
+    [test:test1]
+    key_1:
+        value_1
+else:
+    [test:test2]
+    key_1:
+        value_2
+""")
+
+        fragment_file1 = FragmentFile(test_fragment1, self.sdkconfig)
+        self.assertEqual(len(fragment_file1.fragments), 1)
+        self.assertEqual(fragment_file1.fragments[0].key_1[0], "value_1")
+
+        test_fragment2 = self.create_fragment_file(u"""
+[test:test1]
+key_1:
+    if A = y:
+        value_1
+    else:
+        value_2
+""")
+
+        fragment_file2 = FragmentFile(test_fragment2, self.sdkconfig)
+        self.assertEqual(len(fragment_file2.fragments), 1)
+        self.assertEqual(fragment_file2.fragments[0].key_1[0], "value_1")
 
-    def test_non_existent_entries(self):
-        misspelled_entries_field = """
-        [sections:test]
-        entrie:
-            .section1
-        """
 
-        missing_entries_field = """
-        [sections:test]
-        """
+class SectionsTest(FragmentTest):
 
-        with self.assertRaises(ParseException):
-            self.parse(misspelled_entries_field)
+    def test_basic(self):
+        test_fragment = self.create_fragment_file(u"""
+[sections:test]
+entries:
+    .section1
+    .section2
+""")
 
-        with self.assertRaises(ParseException):
-            self.parse(missing_entries_field)
+        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
+        self.assertEqual(fragment_file.fragments[0].entries, {".section1", ".section2"})
 
     def test_duplicate_entries(self):
-        duplicate_entries = """
-        [sections:test]
-        entries:
-            .section1
-            .section3
-            .section1
-            .section1
-            .section2
-            .section3
-            .section1
-        """
-
-        sections = self.parse(duplicate_entries)
+        test_fragment = self.create_fragment_file(u"""
+[sections:test]
+entries:
+    .section1
+    .section2
+    .section3
+    .section2
+""")
+
+        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
+        self.assertEqual(fragment_file.fragments[0].entries, {".section1", ".section2", ".section3"})
+
+    def test_empty_entries(self):
+        test_fragment = self.create_fragment_file(u"""
+[sections:test]
+entries:
+""")
 
-        entries = sections.entries
+        with self.assertRaises(ParseException):
+            FragmentFile(test_fragment, self.sdkconfig)
 
-        expected = {
-            ".section1",
-            ".section2",
-            ".section3",
-        }
+        test_fragment = self.create_fragment_file(u"""
+[sections:test]
+entries:
+    if B = y:
+        .section1
+""")
 
-        self.assertEqual(set(entries), expected)
+        with self.assertRaises(ParseFatalException):
+            FragmentFile(test_fragment, self.sdkconfig)
 
 
 class SchemeTest(FragmentTest):
 
-    def setUp(self):
-        self.parser = fragments.Scheme.get_fragment_grammar()
-
-    def test_valid_entries(self):
-        valid_entries = """
-        [scheme:test]
-        entries:
-            sections1 -> target1
-            sections2   ->    target2
-        """
+    def test_basic(self):
+        test_fragment = self.create_fragment_file(u"""
+[scheme:test]
+entries:
+    sections1 -> target1
+    sections2 -> target2
+""")
 
-        scheme = self.parse(valid_entries)
+        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
+        self.assertEqual(fragment_file.fragments[0].entries,
+                         {("sections1", "target1"),
+                          ("sections2", "target2")})
 
-        entries = scheme.entries
-
-        expected = {
-            ("sections1", "target1"),
-            ("sections2", "target2")
-        }
-
-        self.assertEqual(entries, expected)
-
-    def test_duplicate_same_mapping(self):
-        duplicate_entries = """
-        [scheme:duplicate_same_mapping]
-        entries:
-            sections1 -> target1
-            sections2 -> target2
-            sections1 -> target1
-        """
-
-        scheme = self.parse(duplicate_entries)
-
-        entries = scheme.entries
-
-        expected = {
-            ("sections1", "target1"),
-            ("sections2", "target2")
-        }
-
-        self.assertEqual(len(entries), 2)
-        self.assertEqual(entries, expected)
-
-    def test_invalid_separator(self):
-        wrong_character = """
-        [scheme:test]
-        entries:
-            sections1, target1
-        """
-
-        single_word = """
-        [scheme:test]
-        entries:
-            sections1
-        """
-
-        with self.assertRaises(ParseException):
-            self.parse(wrong_character)
-
-        with self.assertRaises(ParseException):
-            self.parse(single_word)
-
-    def test_blank_entries(self):
-        blank_entries = """
-        [scheme:test]
-        entries:
-        """
+    def test_duplicate_entries(self):
+        test_fragment = self.create_fragment_file(u"""
+[scheme:test]
+entries:
+    sections1 -> target1
+    sections2 -> target2
+    sections2 -> target2
+""")
+
+        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
+        self.assertEqual(fragment_file.fragments[0].entries,
+                         {("sections1", "target1"),
+                          ("sections2", "target2")})
+
+    def test_empty_entries(self):
+        test_fragment = self.create_fragment_file(u"""
+[scheme:test]
+entries:
+""")
 
         with self.assertRaises(ParseException):
-            self.parse(blank_entries)
+            FragmentFile(test_fragment, self.sdkconfig)
 
-    def test_non_existent_entries(self):
-        misspelled_entries_field = """
-        [scheme:test]
-        entrie:
-            section -> target
-        """
+        test_fragment = self.create_fragment_file(u"""
+[scheme:test]
+entries:
+    if B = y:
+        sections1 -> target1
+""")
 
-        missing_entries_field = """
-        [scheme:test]
-        """
+        with self.assertRaises(ParseFatalException):
+            FragmentFile(test_fragment, self.sdkconfig)
 
-        with self.assertRaises(ParseException):
-            self.parse(misspelled_entries_field)
+    def test_improper_grammar(self):
+        test_fragment = self.create_fragment_file(u"""
+[scheme:test]
+entries:
+    sections1, target1 # improper separator
+""")
 
         with self.assertRaises(ParseException):
-            self.parse(missing_entries_field)
+            FragmentFile(test_fragment, self.sdkconfig)
 
 
 class MappingTest(FragmentTest):
 
-    def setUp(self):
-        self.parser = fragments.Mapping.get_fragment_grammar()
-
-    def parse_expression(self, expression):
-        parser = SDKConfig.get_expression_grammar()
-        return parser.parseString(expression, parseAll=True)
-
-    def test_valid_grammar(self):
-        valid_entries = """
-        [mapping]
-        archive: lib.a
-        entries:
-            obj:symbol (noflash)
-            # Comments should not matter
-            obj (noflash)
-            # Nor should whitespace
-                            obj  :     symbol_2 (    noflash )
-              obj_2  (    noflash )
-            * (noflash)
-        """
-
-        mapping = self.parse(valid_entries)
-
-        self.assertEqual("lib.a", mapping.archive)
-        self.assertEqual("lib_a", mapping.name)
-
-        entries = mapping.entries
-
-        expected = [("default", {
-                    ("obj", "symbol", "noflash"),
+    def test_basic(self):
+        test_fragment = self.create_fragment_file(u"""
+[mapping:test]
+archive: lib.a
+entries:
+    obj:symbol (noflash)
+    obj (noflash)
+    obj:symbol_2 (noflash)
+    obj_2 (noflash)
+    * (noflash)
+""")
+
+        expected = {("obj", "symbol", "noflash"),
                     ("obj", None, "noflash"),
                     ("obj", "symbol_2", "noflash"),
                     ("obj_2", None, "noflash"),
-                    ("*", None, "noflash")
-                    })]
+                    ("*", None, "noflash")}
 
-        self.assertEqual(entries, expected)
+        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
+        self.assertEqual(expected, fragment_file.fragments[0].entries)
 
-    def test_invalid_grammar(self):
-        with_fragment_name = """
-        [mapping:name]
-        archive: lib.a
-        entries:
-            obj:symbol (noflash)
-        """
-
-        missing_archive = """
-        [mapping:name]
-        entries:
-            obj:symbol (noflash)
-        """
-
-        misspelled_archive = """
-        [mapping:name]
-        archi: lib.a
-        entries:
-            obj:symbol (noflash)
-        """
-
-        missing_entries = """
-        [mapping]
-        archive: lib.a
-        """
-
-        misspelled_entries = """
-        [mapping]
-        archive: lib.a
-        entrie:
-            obj:symbol (noflash)
-        """
-
-        missing_symbols = """
-        [mapping]
-        archive: lib.a
-        entries:
-            obj: (noflash)
-        """
-
-        missing_scheme_1 = """
-        [mapping]
-        archive: lib.a
-        entries:
-            obj: ()
-        """
-
-        missing_scheme_2 = """
-        [mapping]
-        archive: lib.a
-        entries:
-            obj:symbol
-        """
-
-        missing_entity = """
-        [mapping]
-        archive: lib.a
-        entries:
-            (noflash)
-        """
-
-        wilcard_symbol = """
-        [mapping]
-        archive: lib.a
-        entries:
-            obj:* (noflash)
-        """
-
-        empty_object_with_symbol = """
-        [mapping]
-        archive: lib.a
-        entries:
-            :symbol (noflash)
-        """
-
-        wildcard_object_with_symbol = """
-        [mapping]
-        archive: lib.a
-        entries:
-            *:symbol (noflash)
-        """
-
-        empty_definition = """
-        [mapping]
-        """
+    def test_archive(self):
+        test_fragment = self.create_fragment_file(u"""
+[mapping:test]
+archive:
+entries:
+    * (default)
+""")
 
         with self.assertRaises(ParseException):
-            self.parse(with_fragment_name)
+            FragmentFile(test_fragment, self.sdkconfig)
+
+        test_fragment = self.create_fragment_file(u"""
+[mapping:test]
+archive:
+    lib1.a
+    lib2.a
+entries:
+    * (default)
+""")
+
+        with self.assertRaises(ParseFatalException):
+            FragmentFile(test_fragment, self.sdkconfig)
+
+    def test_empty_entries(self):
+        test_fragment = self.create_fragment_file(u"""
+[mapping:test]
+archive:
+    lib.a
+entries:
+    if B = y:
+        * (noflash) # if condition is false, then no 'entries' key value
+""")
+
+        with self.assertRaises(ParseFatalException):
+            FragmentFile(test_fragment, self.sdkconfig)
+
+        test_fragment = self.create_fragment_file(u"""
+[mapping:test]
+archive:
+    lib.a
+entries:
+""")
 
         with self.assertRaises(ParseException):
-            self.parse(missing_archive)
+            FragmentFile(test_fragment, self.sdkconfig)
 
-        with self.assertRaises(ParseException):
-            self.parse(misspelled_archive)
+    def test_duplicate_entries(self):
+        test_fragment = self.create_fragment_file(u"""
+[mapping:test]
+archive:
+    lib.a
+entries:
+    obj:symbol (noflash)
+    obj:symbol (noflash)
+""")
 
-        with self.assertRaises(ParseException):
-            self.parse(missing_entries)
+        expected = {("obj", "symbol", "noflash")}
 
-        with self.assertRaises(ParseException):
-            self.parse(misspelled_entries)
+        fragment_file = FragmentFile(test_fragment, self.sdkconfig)
+        self.assertEqual(expected, fragment_file.fragments[0].entries)
 
-        with self.assertRaises(ParseException):
-            self.parse(missing_symbols)
+    def test_invalid_grammar(self):
+        test_fragment = self.create_fragment_file(u"""
+[mapping:test]
+archive:
+    lib.a
+""")
+
+        with self.assertRaises(ParseFatalException):
+            FragmentFile(test_fragment, self.sdkconfig)
+
+        test_fragment = self.create_fragment_file(u"""
+[mapping:test]
+entries:
+    * (default)
+""")
+
+        with self.assertRaises(ParseFatalException):
+            FragmentFile(test_fragment, self.sdkconfig)
+
+        test_fragment = self.create_fragment_file(u"""
+[mapping:test]
+archive: lib.a
+entries:
+    obj: (noflash)
+""")
 
         with self.assertRaises(ParseException):
-            self.parse(missing_scheme_1)
+            FragmentFile(test_fragment, self.sdkconfig)
 
-        with self.assertRaises(ParseException):
-            self.parse(missing_scheme_2)
+        test_fragment = self.create_fragment_file(u"""
+[mapping:test]
+archive: lib.a
+entries:
+    obj: ()
+""")
 
         with self.assertRaises(ParseException):
-            self.parse(missing_entity)
+            FragmentFile(test_fragment, self.sdkconfig)
 
-        with self.assertRaises(ParseException):
-            self.parse(wilcard_symbol)
+        test_fragment = self.create_fragment_file(u"""
+[mapping:test]
+archive: lib.a
+entries:
+    obj:symbol
+""")
 
         with self.assertRaises(ParseException):
-            self.parse(empty_object_with_symbol)
+            FragmentFile(test_fragment, self.sdkconfig)
 
-        with self.assertRaises(ParseException):
-            self.parse(wildcard_object_with_symbol)
+        test_fragment = self.create_fragment_file(u"""
+[mapping:test]
+archive: lib.a
+entries:
+    (noflash)
+""")
 
         with self.assertRaises(ParseException):
-            self.parse(empty_definition)
-
-    def test_explicit_blank_default_w_others(self):
-        expl_blnk_w_oth = """
-        [mapping]
-        archive: lib.a
-        entries:
-            : CONFIG_A = y
-            obj_a (noflash)
-            : default
-        """
-
-        mapping = self.parse(expl_blnk_w_oth)
-
-        entries = mapping.entries
-
-        expected = [(entries[0][0], {
-                    ("obj_a", None, "noflash"),
-                    }),
-                    ("default", set())]
-
-        self.assertEqual(entries, expected)
-
-    def test_implicit_blank_default_w_others(self):
-        impl_blnk_w_oth = """
-        [mapping]
-        archive: lib.a
-        entries:
-            : CONFIG_A = y
-            obj_a (noflash)
-        """
-
-        mapping = self.parse(impl_blnk_w_oth)
-
-        entries = mapping.entries
-
-        expected = [(entries[0][0], {
-                    ("obj_a", None, "noflash"),
-                    }),
-                    ("default", set())]
-
-        self.assertEqual(entries, expected)
-
-    def test_explicit_blank_default(self):
-        expl_blnk_def = """
-        [mapping]
-        archive: lib.a
-        entries:
-            : default
-        """
-        mapping = self.parse(expl_blnk_def)
-        entries = mapping.entries
-        expected = [("default", set())]
-
-        self.assertEqual(entries, expected)
-
-    def test_implicit_blank_default(self):
-        impl_blnk_def = """
-        [mapping]
-        archive: lib.a
-        entries:
-            : default
-        """
-        mapping = self.parse(impl_blnk_def)
-        entries = mapping.entries
-        expected = [("default", set())]
-
-        self.assertEqual(entries, expected)
-
-    def test_multiple_entries(self):
-        multiple_entries = """
-        [mapping]
-        archive: lib.a
-        entries:
-            : CONFIG_A = y
-            obj_a1 (noflash)
-            obj_a2 (noflash)
-            : CONFIG_B = y
-            obj_b1 (noflash)
-            obj_b2 (noflash)
-            obj_b3 (noflash)
-            : CONFIG_C = y
-            obj_c1 (noflash)
-        """
-
-        mapping = self.parse(multiple_entries)
-
-        entries = mapping.entries
-
-        expected = [(entries[0][0], {
-                    ("obj_a1", None, "noflash"),
-                    ("obj_a2", None, "noflash"),
-                    }),
-                    (entries[1][0], {
-                        ("obj_b1", None, "noflash"),
-                        ("obj_b2", None, "noflash"),
-                        ("obj_b3", None, "noflash"),
-                    }),
-                    (entries[2][0], {
-                        ("obj_c1", None, "noflash"),
-                    }),
-                    ("default", set())]
-
-        self.assertEqual(entries, expected)
-
-    def test_blank_entries(self):
-        blank_entries = """
-        [mapping]
-        archive: lib.a
-        entries:
-            : CONFIG_A = y
-            obj_a (noflash)
-            : CONFIG_B = y
-            : CONFIG_C = y
-            obj_c (noflash)
-            : CONFIG_D = y
-            : CONFIG_E = y
-            : default
-            obj (noflash)
-        """
-
-        mapping = self.parse(blank_entries)
-
-        entries = mapping.entries
-
-        expected = [(entries[0][0], {
-                    ("obj_a", None, "noflash")
-                    }),
-                    (entries[1][0], set()),
-                    (entries[2][0], {
-                        ("obj_c", None, "noflash")
-                    }),
-                    (entries[3][0], set()),
-                    (entries[4][0], set()),
-                    ("default", {
-                        ("obj", None, "noflash")
-                    })]
-
-        self.assertEqual(entries, expected)
-
-    def test_blank_first_condition(self):
-        blank_first_condition = """
-        [mapping]
-        archive: lib.a
-        entries:
-            obj_a (noflash)
-            : CONFIG_B = y
-            obj_b (noflash)
-        """
+            FragmentFile(test_fragment, self.sdkconfig)
 
-        with self.assertRaises(ParseException):
-            self.parse(blank_first_condition)
-
-    def test_nonlast_default(self):
-        nonlast_default_1 = """
-        [mapping]
-        archive: lib.a
-        entries:
-            : default
-            obj_a (noflash)
-            : CONFIG_A = y
-            obj_A (noflash)
-        """
-
-        nonlast_default_2 = """
-        [mapping]
-        archive: lib.a
-        entries:
-            : CONFIG_A = y
-            obj_A (noflash)
-            : default
-            obj_a (noflash)
-            : CONFIG_B = y
-            obj_B (noflash)
-        """
-
-        nonlast_default_3 = """
-        [mapping]
-        archive: lib.a
-        entries:
-            : CONFIG_A = y
-            obj_A (noflash)
-            :
-            obj_a (noflash)
-            : CONFIG_B = y
-            obj_B (noflash)
-        """
+        test_fragment = self.create_fragment_file(u"""
+[mapping:test]
+archive: lib.a
+entries:
+    obj:* (noflash)
+""")
 
         with self.assertRaises(ParseException):
-            self.parse(nonlast_default_1)
+            FragmentFile(test_fragment, self.sdkconfig)
 
-        with self.assertRaises(ParseException):
-            self.parse(nonlast_default_2)
+        test_fragment = self.create_fragment_file(u"""
+[mapping:test]
+archive: lib.a
+entries:
+    :symbol (noflash)
+""")
 
         with self.assertRaises(ParseException):
-            self.parse(nonlast_default_3)
-
-    def test_duplicate_default(self):
-        duplicate_default_1 = """
-        archive: lib.a
-        entries:
-            : CONFIG_A = y
-            obj_A (noflash)
-            : default
-            obj_a (noflash)
-            : CONFIG_B = y
-            obj_B (noflash)
-            : default
-            obj_a (noflash)
-        """
-
-        duplicate_default_2 = """
-        archive: lib.a
-        entries:
-            : CONFIG_A = y
-            obj_A (noflash)
-            : CONFIG_B = y
-            obj_a (noflash)
-            : default
-            obj_B (noflash)
-            :
-            obj_a (noflash)
-        """
+            FragmentFile(test_fragment, self.sdkconfig)
 
-        with self.assertRaises(ParseException):
-            self.parse(duplicate_default_1)
+        test_fragment = self.create_fragment_file(u"""
+[mapping:test]
+archive: lib.a
+entries:
+    *:symbol (noflash)
+""")
 
         with self.assertRaises(ParseException):
-            self.parse(duplicate_default_2)
+            FragmentFile(test_fragment, self.sdkconfig)
 
 
 if __name__ == "__main__":
index 3a6eed35cad65eb4d777042df06cb70138181ebd..a09701576b4b4e0897b1c7b5563d57132dab7a14 100755 (executable)
@@ -29,28 +29,23 @@ from generation import SectionsInfo
 from generation import TemplateModel
 from generation import GenerationModel
 
-from fragments import FragmentFileModel
-from fragments import Mapping
-from fragments import Sections
-from fragments import Scheme
+from fragments import FragmentFile
 
 from sdkconfig import SDKConfig
+from io import StringIO
 
 
 class GenerationModelTest(unittest.TestCase):
 
     def setUp(self):
         self.model = GenerationModel()
-        self.sdkconfig = None
         self.sections_info = None
         self.script_model = None
 
-        with open("data/Kconfig") as kconfig_file_obj:
-            with open("data/sdkconfig") as sdkconfig_file_obj:
-                self.sdkconfig = SDKConfig(kconfig_file_obj, sdkconfig_file_obj)
+        self.sdkconfig = SDKConfig("data/Kconfig", "data/sdkconfig")
 
         with open("data/sample.lf") as fragment_file_obj:
-            fragment_file = FragmentFileModel(fragment_file_obj)
+            fragment_file = FragmentFile(fragment_file_obj, self.sdkconfig)
             self.model.add_fragments_from_file(fragment_file)
 
         self.sections_info = SectionsInfo()
@@ -61,29 +56,25 @@ class GenerationModelTest(unittest.TestCase):
         with open("data/template.ld") as template_file_obj:
             self.script_model = TemplateModel(template_file_obj)
 
-    def _add_mapping(self, text):
-        parser = Mapping.get_fragment_grammar()
-        fragment = parser.parseString(text, parseAll=True)
-        self.model.mappings[fragment[0].name] = fragment[0]
+    @staticmethod
+    def create_fragment_file(contents, name="test_fragment.lf"):
+        f = StringIO(contents)
+        f.name = name
+        return f
 
-    def _add_sections(self, text):
-        parser = Sections.get_fragment_grammar()
-        fragment = parser.parseString(text, parseAll=True)
-        self.model.sections[fragment[0].name] = fragment[0]
+    def add_fragments(self, text):
+        fragment_file = self.create_fragment_file(text)
+        fragment_file = FragmentFile(fragment_file, self.sdkconfig)
+        self.model.add_fragments_from_file(fragment_file)
 
-    def _add_scheme(self, text):
-        parser = Scheme.get_fragment_grammar()
-        fragment = parser.parseString(text, parseAll=True)
-        self.model.schemes[fragment[0].name] = fragment[0]
-
-    def _write(self, expected, actual):
-        self.script_model.fill(expected, self.sdkconfig)
+    def write(self, expected, actual):
+        self.script_model.fill(expected)
         self.script_model.write(open("expected.ld", "w"))
 
-        self.script_model.fill(actual, self.sdkconfig)
+        self.script_model.fill(actual)
         self.script_model.write(open("actual.ld", "w"))
 
-    def _generate_default_rules(self):
+    def generate_default_rules(self):
         rules = dict()
 
         # flash_text
@@ -100,13 +91,13 @@ class GenerationModelTest(unittest.TestCase):
 
         # dram0_data
         placement_rules = list()
-        rule = PlacementRule(None, None, None, self.model.sections["data"].entries + self.model.sections["dram"].entries, "dram0_data")
+        rule = PlacementRule(None, None, None, self.model.sections["data"].entries | self.model.sections["dram"].entries, "dram0_data")
         placement_rules.append(rule)
         rules["dram0_data"] = placement_rules
 
         # dram0_bss
         placement_rules = list()
-        rule = PlacementRule(None, None, None, self.model.sections["bss"].entries + self.model.sections["common"].entries, "dram0_bss")
+        rule = PlacementRule(None, None, None, self.model.sections["bss"].entries | self.model.sections["common"].entries, "dram0_bss")
         placement_rules.append(rule)
         rules["dram0_bss"] = placement_rules
 
@@ -124,7 +115,7 @@ class GenerationModelTest(unittest.TestCase):
 
         # rtc_data
         placement_rules = list()
-        rule = PlacementRule(None, None, None, self.model.sections["rtc_data"].entries + self.model.sections["rtc_rodata"].entries, "rtc_data")
+        rule = PlacementRule(None, None, None, self.model.sections["rtc_data"].entries | self.model.sections["rtc_rodata"].entries, "rtc_data")
         placement_rules.append(rule)
         rules["rtc_data"] = placement_rules
 
@@ -136,7 +127,7 @@ class GenerationModelTest(unittest.TestCase):
 
         return rules
 
-    def _compare_rules(self, expected, actual):
+    def compare_rules(self, expected, actual):
         self.assertEqual(set(expected.keys()), set(actual.keys()))
 
         for (target, rules) in actual.items():
@@ -154,39 +145,38 @@ class GenerationModelTest(unittest.TestCase):
             for expected_target_rule in expected_target_rules:
                 self.assertTrue(expected_target_rule in actual_target_rules, message + str(expected_target_rule))
 
-    def _get_default(self, target, rules):
+    def get_default(self, target, rules):
         return rules[target][0]
 
-    def test_rule_generation_blank(self):
-        normal = """
-        [mapping]
-        archive: libfreertos.a
-        entries:
-        """
-
-        self._add_mapping(normal)
+    def test_rule_generation_default(self):
+        normal = u"""
+[mapping:test]
+archive: libfreertos.a
+entries:
+    * (default)
+"""
 
-        actual = self.model.generate_rules(self.sdkconfig, self.sections_info)
+        self.add_fragments(normal)
+        actual = self.model.generate_rules(self.sections_info)
+        expected = self.generate_default_rules()
 
-        expected = self._generate_default_rules()
-
-        self.assertEqual(expected, actual)
+        self.compare_rules(expected, actual)
 
     def test_rule_generation_nominal_1(self):
-        normal = """
-        [mapping]
-        archive: libfreertos.a
-        entries:
-            * (noflash)
-        """
-        self._add_mapping(normal)
+        normal = u"""
+[mapping:test]
+archive: libfreertos.a
+entries:
+    * (noflash)
+"""
+        self.add_fragments(normal)
 
-        actual = self.model.generate_rules(self.sdkconfig, self.sections_info)
+        actual = self.model.generate_rules(self.sections_info)
 
-        expected = self._generate_default_rules()
+        expected = self.generate_default_rules()
 
-        flash_text_default = self._get_default("flash_text", expected)
-        flash_rodata_default = self._get_default("flash_rodata", expected)
+        flash_text_default = self.get_default("flash_text", expected)
+        flash_rodata_default = self.get_default("flash_rodata", expected)
 
         iram0_text_E1 = PlacementRule("libfreertos.a", "*", None, self.model.sections["text"].entries, "iram0_text")
         dram0_data_E1 = PlacementRule("libfreertos.a", "*", None, self.model.sections["rodata"].entries, "dram0_data")
@@ -199,30 +189,30 @@ class GenerationModelTest(unittest.TestCase):
         expected["iram0_text"].append(iram0_text_E1)
         expected["dram0_data"].append(dram0_data_E1)
 
-        self._compare_rules(expected, actual)
+        self.compare_rules(expected, actual)
 
     def test_rule_generation_nominal_2(self):
-        normal = """
-        [mapping]
-        archive: libfreertos.a
-        entries:
-            timers (rtc)
-        """
+        normal = u"""
+[mapping:test]
+archive: libfreertos.a
+entries:
+    timers (rtc)
+"""
 
-        self._add_mapping(normal)
+        self.add_fragments(normal)
 
-        actual = self.model.generate_rules(self.sdkconfig, self.sections_info)
+        actual = self.model.generate_rules(self.sections_info)
 
-        expected = self._generate_default_rules()
+        expected = self.generate_default_rules()
 
-        flash_text_default = self._get_default("flash_text", expected)
-        flash_rodata_default = self._get_default("flash_rodata", expected)
-        dram0_data_default = self._get_default("dram0_data", expected)
-        dram0_bss_default = self._get_default("dram0_bss", expected)
+        flash_text_default = self.get_default("flash_text", expected)
+        flash_rodata_default = self.get_default("flash_rodata", expected)
+        dram0_data_default = self.get_default("dram0_data", expected)
+        dram0_bss_default = self.get_default("dram0_bss", expected)
 
         rtc_text_E1 = PlacementRule("libfreertos.a", "timers", None, self.model.sections["text"].entries, "rtc_text")
-        rtc_data_E1 = PlacementRule("libfreertos.a", "timers", None, self.model.sections["data"].entries + self.model.sections["rodata"].entries, "rtc_data")
-        rtc_bss_E1 = PlacementRule("libfreertos.a", "timers", None, self.model.sections["bss"].entries + self.model.sections["common"].entries, "rtc_bss")
+        rtc_data_E1 = PlacementRule("libfreertos.a", "timers", None, self.model.sections["data"].entries | self.model.sections["rodata"].entries, "rtc_data")
+        rtc_bss_E1 = PlacementRule("libfreertos.a", "timers", None, self.model.sections["bss"].entries | self.model.sections["common"].entries, "rtc_bss")
 
         # Add the exclusions
         flash_text_default.add_exclusion(rtc_text_E1)
@@ -235,31 +225,31 @@ class GenerationModelTest(unittest.TestCase):
         expected["rtc_data"].append(rtc_data_E1)
         expected["rtc_bss"].append(rtc_bss_E1)
 
-        self._compare_rules(expected, actual)
+        self.compare_rules(expected, actual)
 
     def test_rule_generation_nominal_3(self):
-        normal = """
-        [mapping]
-        archive: libfreertos.a
-        entries:
-            timers (rtc)
-            * (noflash)
-        """
+        normal = u"""
+[mapping:test]
+archive: libfreertos.a
+entries:
+    timers (rtc)
+    * (noflash)
+"""
 
-        self._add_mapping(normal)
+        self.add_fragments(normal)
 
-        actual = self.model.generate_rules(self.sdkconfig, self.sections_info)
+        actual = self.model.generate_rules(self.sections_info)
 
-        expected = self._generate_default_rules()
+        expected = self.generate_default_rules()
 
-        flash_text_default = self._get_default("flash_text", expected)
-        flash_rodata_default = self._get_default("flash_rodata", expected)
-        dram0_data_default = self._get_default("dram0_data", expected)
-        dram0_bss_default = self._get_default("dram0_bss", expected)
+        flash_text_default = self.get_default("flash_text", expected)
+        flash_rodata_default = self.get_default("flash_rodata", expected)
+        dram0_data_default = self.get_default("dram0_data", expected)
+        dram0_bss_default = self.get_default("dram0_bss", expected)
 
         rtc_text_E1 = PlacementRule("libfreertos.a", "timers", None, self.model.sections["text"].entries, "rtc_text")
-        rtc_data_E1 = PlacementRule("libfreertos.a", "timers", None, self.model.sections["data"].entries + self.model.sections["rodata"].entries, "rtc_data")
-        rtc_bss_E1 = PlacementRule("libfreertos.a", "timers", None, self.model.sections["bss"].entries + self.model.sections["common"].entries, "rtc_bss")
+        rtc_data_E1 = PlacementRule("libfreertos.a", "timers", None, self.model.sections["data"].entries | self.model.sections["rodata"].entries, "rtc_data")
+        rtc_bss_E1 = PlacementRule("libfreertos.a", "timers", None, self.model.sections["bss"].entries | self.model.sections["common"].entries, "rtc_bss")
 
         iram0_text_E2 = PlacementRule("libfreertos.a", "*", None, self.model.sections["text"].entries, "iram0_text")
         dram0_data_E2 = PlacementRule("libfreertos.a", "*", None, self.model.sections["rodata"].entries, "dram0_data")
@@ -282,39 +272,39 @@ class GenerationModelTest(unittest.TestCase):
         expected["rtc_data"].append(rtc_data_E1)
         expected["rtc_bss"].append(rtc_bss_E1)
 
-        self._compare_rules(expected, actual)
+        self.compare_rules(expected, actual)
 
     def test_rule_generation_nominal_4(self):
-        normal = """
-        [mapping]
-        archive: libfreertos.a
-        entries:
-            croutine (rtc)
-            event_groups (noflash)
-            timers (rtc)
-        """
+        normal = u"""
+[mapping:test]
+archive: libfreertos.a
+entries:
+    croutine (rtc)
+    event_groups (noflash)
+    timers (rtc)
+"""
 
-        self._add_mapping(normal)
+        self.add_fragments(normal)
 
-        actual = self.model.generate_rules(self.sdkconfig, self.sections_info)
+        actual = self.model.generate_rules(self.sections_info)
 
-        expected = self._generate_default_rules()
+        expected = self.generate_default_rules()
 
-        flash_text_default = self._get_default("flash_text", expected)
-        flash_rodata_default = self._get_default("flash_rodata", expected)
-        dram0_data_default = self._get_default("dram0_data", expected)
-        dram0_bss_default = self._get_default("dram0_bss", expected)
+        flash_text_default = self.get_default("flash_text", expected)
+        flash_rodata_default = self.get_default("flash_rodata", expected)
+        dram0_data_default = self.get_default("dram0_data", expected)
+        dram0_bss_default = self.get_default("dram0_bss", expected)
 
         rtc_text_E1 = PlacementRule("libfreertos.a", "croutine", None, self.model.sections["text"].entries, "rtc_text")
-        rtc_data_E1 = PlacementRule("libfreertos.a", "croutine", None, self.model.sections["data"].entries + self.model.sections["rodata"].entries, "rtc_data")
-        rtc_bss_E1 = PlacementRule("libfreertos.a", "croutine", None, self.model.sections["bss"].entries + self.model.sections["common"].entries, "rtc_bss")
+        rtc_data_E1 = PlacementRule("libfreertos.a", "croutine", None, self.model.sections["data"].entries | self.model.sections["rodata"].entries, "rtc_data")
+        rtc_bss_E1 = PlacementRule("libfreertos.a", "croutine", None, self.model.sections["bss"].entries | self.model.sections["common"].entries, "rtc_bss")
 
         iram0_text_E2 = PlacementRule("libfreertos.a", "event_groups", None, self.model.sections["text"].entries, "iram0_text")
         dram0_data_E2 = PlacementRule("libfreertos.a", "event_groups", None, self.model.sections["rodata"].entries, "dram0_data")
 
         rtc_text_E3 = PlacementRule("libfreertos.a", "timers", None, self.model.sections["text"].entries, "rtc_text")
-        rtc_data_E3 = PlacementRule("libfreertos.a", "timers", None, self.model.sections["data"].entries + self.model.sections["rodata"].entries, "rtc_data")
-        rtc_bss_E3 = PlacementRule("libfreertos.a", "timers", None, self.model.sections["bss"].entries + self.model.sections["common"].entries, "rtc_bss")
+        rtc_data_E3 = PlacementRule("libfreertos.a", "timers", None, self.model.sections["data"].entries | self.model.sections["rodata"].entries, "rtc_data")
+        rtc_bss_E3 = PlacementRule("libfreertos.a", "timers", None, self.model.sections["bss"].entries | self.model.sections["common"].entries, "rtc_bss")
 
         # Add the exclusions
         flash_text_default.add_exclusion(rtc_text_E3)
@@ -342,40 +332,40 @@ class GenerationModelTest(unittest.TestCase):
         expected["rtc_data"].append(rtc_data_E1)
         expected["rtc_bss"].append(rtc_bss_E1)
 
-        self._compare_rules(expected, actual)
+        self.compare_rules(expected, actual)
 
     def test_rule_generation_nominal_5(self):
-        normal = """
-        [mapping]
-        archive: libfreertos.a
-        entries:
-            croutine (rtc)
-            event_groups (noflash)
-            timers (rtc)
-            * (noflash)
-        """
+        normal = u"""
+[mapping:test]
+archive: libfreertos.a
+entries:
+    croutine (rtc)
+    event_groups (noflash)
+    timers (rtc)
+    * (noflash)
+"""
 
-        self._add_mapping(normal)
+        self.add_fragments(normal)
 
-        actual = self.model.generate_rules(self.sdkconfig, self.sections_info)
+        actual = self.model.generate_rules(self.sections_info)
 
-        expected = self._generate_default_rules()
+        expected = self.generate_default_rules()
 
-        flash_text_default = self._get_default("flash_text", expected)
-        flash_rodata_default = self._get_default("flash_rodata", expected)
-        dram0_data_default = self._get_default("dram0_data", expected)
-        dram0_bss_default = self._get_default("dram0_bss", expected)
+        flash_text_default = self.get_default("flash_text", expected)
+        flash_rodata_default = self.get_default("flash_rodata", expected)
+        dram0_data_default = self.get_default("dram0_data", expected)
+        dram0_bss_default = self.get_default("dram0_bss", expected)
 
         rtc_text_E1 = PlacementRule("libfreertos.a", "croutine", None, self.model.sections["text"].entries, "rtc_text")
-        rtc_data_E1 = PlacementRule("libfreertos.a", "croutine", None, self.model.sections["data"].entries + self.model.sections["rodata"].entries, "rtc_data")
-        rtc_bss_E1 = PlacementRule("libfreertos.a", "croutine", None, self.model.sections["bss"].entries + self.model.sections["common"].entries, "rtc_bss")
+        rtc_data_E1 = PlacementRule("libfreertos.a", "croutine", None, self.model.sections["data"].entries | self.model.sections["rodata"].entries, "rtc_data")
+        rtc_bss_E1 = PlacementRule("libfreertos.a", "croutine", None, self.model.sections["bss"].entries | self.model.sections["common"].entries, "rtc_bss")
 
         iram0_text_E2 = PlacementRule("libfreertos.a", "event_groups", None, self.model.sections["text"].entries, "iram0_text")
         dram0_data_E2 = PlacementRule("libfreertos.a", "event_groups", None, self.model.sections["rodata"].entries, "dram0_data")
 
         rtc_text_E3 = PlacementRule("libfreertos.a", "timers", None, self.model.sections["text"].entries, "rtc_text")
-        rtc_data_E3 = PlacementRule("libfreertos.a", "timers", None, self.model.sections["data"].entries + self.model.sections["rodata"].entries, "rtc_data")
-        rtc_bss_E3 = PlacementRule("libfreertos.a", "timers", None, self.model.sections["bss"].entries + self.model.sections["common"].entries, "rtc_bss")
+        rtc_data_E3 = PlacementRule("libfreertos.a", "timers", None, self.model.sections["data"].entries | self.model.sections["rodata"].entries, "rtc_data")
+        rtc_bss_E3 = PlacementRule("libfreertos.a", "timers", None, self.model.sections["bss"].entries | self.model.sections["common"].entries, "rtc_bss")
 
         iram0_text_E4 = PlacementRule("libfreertos.a", "*", None, self.model.sections["text"].entries, "iram0_text")
         dram0_data_E4 = PlacementRule("libfreertos.a", "*", None, self.model.sections["rodata"].entries, "dram0_data")
@@ -412,24 +402,24 @@ class GenerationModelTest(unittest.TestCase):
         expected["rtc_data"].append(rtc_data_E1)
         expected["rtc_bss"].append(rtc_bss_E1)
 
-        self._compare_rules(expected, actual)
+        self.compare_rules(expected, actual)
 
     def test_rule_generation_nominal_6(self):
-        normal = """
-        [mapping]
-        archive: libfreertos.a
-        entries:
-            croutine:prvCheckPendingReadyList (noflash)
-        """
+        normal = u"""
+[mapping:test]
+archive: libfreertos.a
+entries:
+    croutine:prvCheckPendingReadyList (noflash)
+"""
 
-        self._add_mapping(normal)
+        self.add_fragments(normal)
 
-        actual = self.model.generate_rules(self.sdkconfig, self.sections_info)
+        actual = self.model.generate_rules(self.sections_info)
 
-        expected = self._generate_default_rules()
+        expected = self.generate_default_rules()
 
-        flash_text_default = self._get_default("flash_text", expected)
-        flash_rodata_default = self._get_default("flash_rodata", expected)
+        flash_text_default = self.get_default("flash_text", expected)
+        flash_rodata_default = self.get_default("flash_rodata", expected)
 
         iram0_text_E1 = PlacementRule("libfreertos.a", "croutine", "prvCheckPendingReadyList", self.model.sections["text"].entries, "iram0_text")
         dram0_data_E1 = PlacementRule("libfreertos.a", "croutine", "prvCheckPendingReadyList", self.model.sections["rodata"].entries, "dram0_data")
@@ -451,26 +441,26 @@ class GenerationModelTest(unittest.TestCase):
         expected["iram0_text"].append(iram0_text_E1)
         expected["dram0_data"].append(dram0_data_E1)
 
-        self._compare_rules(expected, actual)
+        self.compare_rules(expected, actual)
 
     def test_rule_generation_nominal_7(self):
-        normal = """
-        [mapping]
-        archive: libfreertos.a
-        entries:
-            croutine:prvCheckPendingReadyList (noflash)
-            croutine:prvCheckDelayedList (noflash)
-            croutine:xCoRoutineCreate (noflash)
-        """
+        normal = u"""
+[mapping:test]
+archive: libfreertos.a
+entries:
+    croutine:prvCheckPendingReadyList (noflash)
+    croutine:prvCheckDelayedList (noflash)
+    croutine:xCoRoutineCreate (noflash)
+"""
 
-        self._add_mapping(normal)
+        self.add_fragments(normal)
 
-        actual = self.model.generate_rules(self.sdkconfig, self.sections_info)
+        actual = self.model.generate_rules(self.sections_info)
 
-        expected = self._generate_default_rules()
+        expected = self.generate_default_rules()
 
-        flash_text_default = self._get_default("flash_text", expected)
-        flash_rodata_default = self._get_default("flash_rodata", expected)
+        flash_text_default = self.get_default("flash_text", expected)
+        flash_rodata_default = self.get_default("flash_rodata", expected)
 
         iram0_text_E1 = PlacementRule("libfreertos.a", "croutine", "prvCheckPendingReadyList", self.model.sections["text"].entries, "iram0_text")
         dram0_data_E1 = PlacementRule("libfreertos.a", "croutine", "prvCheckPendingReadyList", self.model.sections["rodata"].entries, "dram0_data")
@@ -510,37 +500,37 @@ class GenerationModelTest(unittest.TestCase):
         expected["iram0_text"].append(iram0_text_E3)
         expected["dram0_data"].append(dram0_data_E3)
 
-        self._compare_rules(expected, actual)
+        self.compare_rules(expected, actual)
 
     def test_rule_generation_nominal_8(self):
-        normal = """
-        [mapping]
-        archive: libfreertos.a
-        entries:
-            croutine:prvCheckPendingReadyList (noflash)
-            croutine:prvCheckDelayedList (rtc)
-            croutine:xCoRoutineCreate (noflash)
-        """
+        normal = u"""
+[mapping:test]
+archive: libfreertos.a
+entries:
+    croutine:prvCheckPendingReadyList (noflash)
+    croutine:prvCheckDelayedList (rtc)
+    croutine:xCoRoutineCreate (noflash)
+"""
 
-        self._add_mapping(normal)
+        self.add_fragments(normal)
 
-        actual = self.model.generate_rules(self.sdkconfig, self.sections_info)
+        actual = self.model.generate_rules(self.sections_info)
 
-        expected = self._generate_default_rules()
+        expected = self.generate_default_rules()
 
-        flash_text_default = self._get_default("flash_text", expected)
-        flash_rodata_default = self._get_default("flash_rodata", expected)
-        dram0_data_default = self._get_default("dram0_data", expected)
-        dram0_bss_default = self._get_default("dram0_bss", expected)
+        flash_text_default = self.get_default("flash_text", expected)
+        flash_rodata_default = self.get_default("flash_rodata", expected)
+        dram0_data_default = self.get_default("dram0_data", expected)
+        dram0_bss_default = self.get_default("dram0_bss", expected)
 
         iram0_text_E1 = PlacementRule("libfreertos.a", "croutine", "prvCheckPendingReadyList", self.model.sections["text"].entries, "iram0_text")
         dram0_data_E1 = PlacementRule("libfreertos.a", "croutine", "prvCheckPendingReadyList", self.model.sections["rodata"].entries, "dram0_data")
 
         rtc_text_E2 = PlacementRule("libfreertos.a", "croutine", "prvCheckDelayedList", self.model.sections["text"].entries, "rtc_text")
         rtc_data_E2 = PlacementRule("libfreertos.a", "croutine", "prvCheckDelayedList",
-                                    self.model.sections["data"].entries + self.model.sections["rodata"].entries, "rtc_data")
+                                    self.model.sections["data"].entries | self.model.sections["rodata"].entries, "rtc_data")
         rtc_bss_E2 = PlacementRule("libfreertos.a", "croutine", "prvCheckDelayedList",
-                                   self.model.sections["bss"].entries + self.model.sections["common"].entries, "rtc_bss")
+                                   self.model.sections["bss"].entries | self.model.sections["common"].entries, "rtc_bss")
 
         iram0_text_E3 = PlacementRule("libfreertos.a", "croutine", "xCoRoutineCreate", self.model.sections["text"].entries, "iram0_text")
         dram0_data_E3 = PlacementRule("libfreertos.a", "croutine", "xCoRoutineCreate", self.model.sections["rodata"].entries, "dram0_data")
@@ -583,33 +573,33 @@ class GenerationModelTest(unittest.TestCase):
         expected["iram0_text"].append(iram0_text_E3)
         expected["dram0_data"].append(dram0_data_E3)
 
-        self._compare_rules(expected, actual)
+        self.compare_rules(expected, actual)
 
     def test_rule_generation_nominal_9(self):
-        normal = """
-        [mapping]
-        archive: libfreertos.a
-        entries:
-            croutine:prvCheckDelayedList (rtc)
-            croutine (noflash)
-        """
+        normal = u"""
+[mapping:test]
+archive: libfreertos.a
+entries:
+    croutine:prvCheckDelayedList (rtc)
+    croutine (noflash)
+"""
 
-        self._add_mapping(normal)
+        self.add_fragments(normal)
 
-        actual = self.model.generate_rules(self.sdkconfig, self.sections_info)
+        actual = self.model.generate_rules(self.sections_info)
 
-        expected = self._generate_default_rules()
+        expected = self.generate_default_rules()
 
-        flash_text_default = self._get_default("flash_text", expected)
-        flash_rodata_default = self._get_default("flash_rodata", expected)
-        dram0_data_default = self._get_default("dram0_data", expected)
-        dram0_bss_default = self._get_default("dram0_bss", expected)
+        flash_text_default = self.get_default("flash_text", expected)
+        flash_rodata_default = self.get_default("flash_rodata", expected)
+        dram0_data_default = self.get_default("dram0_data", expected)
+        dram0_bss_default = self.get_default("dram0_bss", expected)
 
         rtc_text_E1 = PlacementRule("libfreertos.a", "croutine", "prvCheckDelayedList", self.model.sections["text"].entries, "rtc_text")
         rtc_data_E1 = PlacementRule("libfreertos.a", "croutine", "prvCheckDelayedList",
-                                    self.model.sections["data"].entries + self.model.sections["rodata"].entries, "rtc_data")
+                                    self.model.sections["data"].entries | self.model.sections["rodata"].entries, "rtc_data")
         rtc_bss_E1 = PlacementRule("libfreertos.a", "croutine", "prvCheckDelayedList",
-                                   self.model.sections["bss"].entries + self.model.sections["common"].entries, "rtc_bss")
+                                   self.model.sections["bss"].entries | self.model.sections["common"].entries, "rtc_bss")
 
         iram0_text_E2 = PlacementRule("libfreertos.a", "croutine", None, self.model.sections["text"].entries, "iram0_text")
         dram0_data_E2 = PlacementRule("libfreertos.a", "croutine", None, self.model.sections["rodata"].entries, "dram0_data")
@@ -641,34 +631,34 @@ class GenerationModelTest(unittest.TestCase):
         expected["rtc_data"].append(rtc_data_E1)
         expected["rtc_bss"].append(rtc_bss_E1)
 
-        self._compare_rules(expected, actual)
+        self.compare_rules(expected, actual)
 
     def test_rule_generation_nominal_10(self):
-        normal = """
-        [mapping]
-        archive: libfreertos.a
-        entries:
-            croutine:prvCheckDelayedList (rtc)
-            * (noflash)
-        """
+        normal = u"""
+[mapping:test]
+archive: libfreertos.a
+entries:
+    croutine:prvCheckDelayedList (rtc)
+    * (noflash)
+"""
 
-        self._add_mapping(normal)
+        self.add_fragments(normal)
 
-        actual = self.model.generate_rules(self.sdkconfig, self.sections_info)
+        actual = self.model.generate_rules(self.sections_info)
 
-        expected = self._generate_default_rules()
+        expected = self.generate_default_rules()
 
-        flash_text_default = self._get_default("flash_text", expected)
-        flash_rodata_default = self._get_default("flash_rodata", expected)
-        iram0_text_default = self._get_default("iram0_text", expected)
-        dram0_data_default = self._get_default("dram0_data", expected)
-        dram0_bss_default = self._get_default("dram0_bss", expected)
+        flash_text_default = self.get_default("flash_text", expected)
+        flash_rodata_default = self.get_default("flash_rodata", expected)
+        iram0_text_default = self.get_default("iram0_text", expected)
+        dram0_data_default = self.get_default("dram0_data", expected)
+        dram0_bss_default = self.get_default("dram0_bss", expected)
 
         rtc_text_E1 = PlacementRule("libfreertos.a", "croutine", "prvCheckDelayedList", self.model.sections["text"].entries, "rtc_text")
         rtc_data_E1 = PlacementRule("libfreertos.a", "croutine", "prvCheckDelayedList",
-                                    self.model.sections["data"].entries + self.model.sections["rodata"].entries, "rtc_data")
+                                    self.model.sections["data"].entries | self.model.sections["rodata"].entries, "rtc_data")
         rtc_bss_E1 = PlacementRule("libfreertos.a", "croutine", "prvCheckDelayedList",
-                                   self.model.sections["bss"].entries + self.model.sections["common"].entries, "rtc_bss")
+                                   self.model.sections["bss"].entries | self.model.sections["common"].entries, "rtc_bss")
 
         iram0_text_E2 = PlacementRule("libfreertos.a", None, None, self.model.sections["text"].entries, "iram0_text")
         dram0_data_E2 = PlacementRule("libfreertos.a", None, None, self.model.sections["rodata"].entries, "dram0_data")
@@ -704,36 +694,36 @@ class GenerationModelTest(unittest.TestCase):
         expected["rtc_data"].append(rtc_data_E1)
         expected["rtc_bss"].append(rtc_bss_E1)
 
-        self._compare_rules(expected, actual)
+        self.compare_rules(expected, actual)
 
     def test_rule_generation_nominal_11(self):
-        normal = """
-        [mapping]
-        archive: libfreertos.a
-        entries:
-            croutine:prvCheckDelayedList (noflash)
-            croutine (rtc)
-            * (noflash)
-        """
+        normal = u"""
+[mapping:test]
+archive: libfreertos.a
+entries:
+    croutine:prvCheckDelayedList (noflash)
+    croutine (rtc)
+    * (noflash)
+"""
 
-        self._add_mapping(normal)
+        self.add_fragments(normal)
 
-        actual = self.model.generate_rules(self.sdkconfig, self.sections_info)
+        actual = self.model.generate_rules(self.sections_info)
 
-        expected = self._generate_default_rules()
+        expected = self.generate_default_rules()
 
-        flash_text_default = self._get_default("flash_text", expected)
-        flash_rodata_default = self._get_default("flash_rodata", expected)
-        iram0_text_default = self._get_default("iram0_text", expected)
-        dram0_data_default = self._get_default("dram0_data", expected)
-        dram0_bss_default = self._get_default("dram0_bss", expected)
+        flash_text_default = self.get_default("flash_text", expected)
+        flash_rodata_default = self.get_default("flash_rodata", expected)
+        iram0_text_default = self.get_default("iram0_text", expected)
+        dram0_data_default = self.get_default("dram0_data", expected)
+        dram0_bss_default = self.get_default("dram0_bss", expected)
 
         iram0_text_E1 = PlacementRule("libfreertos.a", "croutine", "prvCheckDelayedList", self.model.sections["text"].entries, "iram0_text")
         dram0_data_E1 = PlacementRule("libfreertos.a", "croutine", "prvCheckDelayedList", self.model.sections["rodata"].entries, "dram0_data")
 
         rtc_text_E2 = PlacementRule("libfreertos.a", "croutine", None, self.model.sections["text"].entries, "rtc_text")
-        rtc_data_E2 = PlacementRule("libfreertos.a", "croutine", None, self.model.sections["data"].entries + self.model.sections["rodata"].entries, "rtc_data")
-        rtc_bss_E2 = PlacementRule("libfreertos.a", "croutine", None, self.model.sections["bss"].entries + self.model.sections["common"].entries, "rtc_bss")
+        rtc_data_E2 = PlacementRule("libfreertos.a", "croutine", None, self.model.sections["data"].entries | self.model.sections["rodata"].entries, "rtc_data")
+        rtc_bss_E2 = PlacementRule("libfreertos.a", "croutine", None, self.model.sections["bss"].entries | self.model.sections["common"].entries, "rtc_bss")
 
         iram0_text_E3 = PlacementRule("libfreertos.a", None, None, self.model.sections["text"].entries, "iram0_text")
         dram0_data_E3 = PlacementRule("libfreertos.a", None, None, self.model.sections["rodata"].entries, "dram0_data")
@@ -762,41 +752,41 @@ class GenerationModelTest(unittest.TestCase):
         expected["iram0_text"].append(iram0_text_E3)
         expected["dram0_data"].append(dram0_data_E3)
 
-        self._compare_rules(expected, actual)
+        self.compare_rules(expected, actual)
 
     def test_rule_generation_nominal_12(self):
-        normal = """
-        [mapping]
-        archive: libfreertos.a
-        entries:
-            croutine:prvCheckDelayedList (rtc)
-            croutine (noflash)
-            * (rtc)
-        """
+        normal = u"""
+[mapping:test]
+archive: libfreertos.a
+entries:
+    croutine:prvCheckDelayedList (rtc)
+    croutine (noflash)
+    * (rtc)
+"""
 
-        self._add_mapping(normal)
+        self.add_fragments(normal)
 
-        actual = self.model.generate_rules(self.sdkconfig, self.sections_info)
+        actual = self.model.generate_rules(self.sections_info)
 
-        expected = self._generate_default_rules()
+        expected = self.generate_default_rules()
 
-        flash_text_default = self._get_default("flash_text", expected)
-        flash_rodata_default = self._get_default("flash_rodata", expected)
-        dram0_data_default = self._get_default("dram0_data", expected)
-        dram0_bss_default = self._get_default("dram0_bss", expected)
+        flash_text_default = self.get_default("flash_text", expected)
+        flash_rodata_default = self.get_default("flash_rodata", expected)
+        dram0_data_default = self.get_default("dram0_data", expected)
+        dram0_bss_default = self.get_default("dram0_bss", expected)
 
         rtc_text_E1 = PlacementRule("libfreertos.a", "croutine", "prvCheckDelayedList", self.model.sections["text"].entries, "rtc_text")
         rtc_data_E1 = PlacementRule("libfreertos.a", "croutine", "prvCheckDelayedList",
-                                    self.model.sections["data"].entries + self.model.sections["rodata"].entries, "rtc_data")
+                                    self.model.sections["data"].entries | self.model.sections["rodata"].entries, "rtc_data")
         rtc_bss_E1 = PlacementRule("libfreertos.a", "croutine", "prvCheckDelayedList",
-                                   self.model.sections["bss"].entries + self.model.sections["common"].entries, "rtc_bss")
+                                   self.model.sections["bss"].entries | self.model.sections["common"].entries, "rtc_bss")
 
         iram0_text_E2 = PlacementRule("libfreertos.a", "croutine", None, self.model.sections["text"].entries, "iram0_text")
         dram0_data_E2 = PlacementRule("libfreertos.a", "croutine", None, self.model.sections["rodata"].entries, "dram0_data")
 
         rtc_text_E3 = PlacementRule("libfreertos.a", None, None, self.model.sections["text"].entries, "rtc_text")
-        rtc_data_E3 = PlacementRule("libfreertos.a", None, None, self.model.sections["data"].entries + self.model.sections["rodata"].entries, "rtc_data")
-        rtc_bss_E3 = PlacementRule("libfreertos.a", None, None, self.model.sections["bss"].entries + self.model.sections["common"].entries, "rtc_bss")
+        rtc_data_E3 = PlacementRule("libfreertos.a", None, None, self.model.sections["data"].entries | self.model.sections["rodata"].entries, "rtc_data")
+        rtc_bss_E3 = PlacementRule("libfreertos.a", None, None, self.model.sections["bss"].entries | self.model.sections["common"].entries, "rtc_bss")
 
         rtc_data_extra = PlacementRule("libfreertos.a", "croutine", None, [".data.*"], "rtc_data")
         rtc_bss_extra = PlacementRule("libfreertos.a", "croutine", None, [".bss.*"], "rtc_bss")
@@ -832,30 +822,30 @@ class GenerationModelTest(unittest.TestCase):
         expected["rtc_data"].append(rtc_data_E3)
         expected["rtc_bss"].append(rtc_bss_E3)
 
-        self._compare_rules(expected, actual)
+        self.compare_rules(expected, actual)
 
     def test_rule_generation_nominal_13(self):
-        normal = """
-        [mapping]
-        archive: libfreertos.a
-        entries:
-            croutine:prvCheckDelayedList (noflash)
-            event_groups:xEventGroupCreate (noflash)
-            croutine (rtc)
-            event_groups (rtc)
-            * (noflash)
-        """
+        normal = u"""
+[mapping:test]
+archive: libfreertos.a
+entries:
+    croutine:prvCheckDelayedList (noflash)
+    event_groups:xEventGroupCreate (noflash)
+    croutine (rtc)
+    event_groups (rtc)
+    * (noflash)
+"""
 
-        self._add_mapping(normal)
+        self.add_fragments(normal)
 
-        actual = self.model.generate_rules(self.sdkconfig, self.sections_info)
+        actual = self.model.generate_rules(self.sections_info)
 
-        expected = self._generate_default_rules()
+        expected = self.generate_default_rules()
 
-        flash_text_default = self._get_default("flash_text", expected)
-        flash_rodata_default = self._get_default("flash_rodata", expected)
-        dram0_data_default = self._get_default("dram0_data", expected)
-        dram0_bss_default = self._get_default("dram0_bss", expected)
+        flash_text_default = self.get_default("flash_text", expected)
+        flash_rodata_default = self.get_default("flash_rodata", expected)
+        dram0_data_default = self.get_default("dram0_data", expected)
+        dram0_bss_default = self.get_default("dram0_bss", expected)
 
         iram0_text_E1 = PlacementRule("libfreertos.a", "croutine", "prvCheckDelayedList", self.model.sections["text"].entries, "iram0_text")
         dram0_data_E1 = PlacementRule("libfreertos.a", "croutine", "prvCheckDelayedList", self.model.sections["rodata"].entries, "dram0_data")
@@ -864,14 +854,14 @@ class GenerationModelTest(unittest.TestCase):
         dram0_data_E2 = PlacementRule("libfreertos.a", "event_groups", "xEventGroupCreate", self.model.sections["rodata"].entries, "dram0_data")
 
         rtc_text_E3 = PlacementRule("libfreertos.a", "croutine", None, self.model.sections["text"].entries, "rtc_text")
-        rtc_data_E3 = PlacementRule("libfreertos.a", "croutine", None, self.model.sections["data"].entries + self.model.sections["rodata"].entries, "rtc_data")
-        rtc_bss_E3 = PlacementRule("libfreertos.a", "croutine", None, self.model.sections["bss"].entries + self.model.sections["common"].entries, "rtc_bss")
+        rtc_data_E3 = PlacementRule("libfreertos.a", "croutine", None, self.model.sections["data"].entries | self.model.sections["rodata"].entries, "rtc_data")
+        rtc_bss_E3 = PlacementRule("libfreertos.a", "croutine", None, self.model.sections["bss"].entries | self.model.sections["common"].entries, "rtc_bss")
 
         rtc_text_E4 = PlacementRule("libfreertos.a", "event_groups", None, self.model.sections["text"].entries, "rtc_text")
         rtc_data_E4 = PlacementRule("libfreertos.a", "event_groups", None,
-                                    self.model.sections["data"].entries + self.model.sections["rodata"].entries, "rtc_data")
+                                    self.model.sections["data"].entries | self.model.sections["rodata"].entries, "rtc_data")
         rtc_bss_E4 = PlacementRule("libfreertos.a", "event_groups", None,
-                                   self.model.sections["bss"].entries + self.model.sections["common"].entries, "rtc_bss")
+                                   self.model.sections["bss"].entries | self.model.sections["common"].entries, "rtc_bss")
 
         iram0_text_E5 = PlacementRule("libfreertos.a", None, None, self.model.sections["text"].entries, "iram0_text")
         dram0_data_E5 = PlacementRule("libfreertos.a", None, None, self.model.sections["rodata"].entries, "dram0_data")
@@ -913,42 +903,42 @@ class GenerationModelTest(unittest.TestCase):
         expected["iram0_text"].append(iram0_text_E5)
         expected["dram0_data"].append(dram0_data_E5)
 
-        self._compare_rules(expected, actual)
+        self.compare_rules(expected, actual)
 
     def test_rule_generation_nominal_14(self):
-        normal = """
-        [mapping]
-        archive: libfreertos.a
-        entries:
-            croutine:prvCheckDelayedList (noflash)
-            event_groups:xEventGroupCreate (rtc)
-            croutine (rtc)
-            event_groups (noflash)
-        """
+        normal = u"""
+[mapping:test]
+archive: libfreertos.a
+entries:
+    croutine:prvCheckDelayedList (noflash)
+    event_groups:xEventGroupCreate (rtc)
+    croutine (rtc)
+    event_groups (noflash)
+"""
 
-        self._add_mapping(normal)
+        self.add_fragments(normal)
 
-        actual = self.model.generate_rules(self.sdkconfig, self.sections_info)
+        actual = self.model.generate_rules(self.sections_info)
 
-        expected = self._generate_default_rules()
+        expected = self.generate_default_rules()
 
-        flash_text_default = self._get_default("flash_text", expected)
-        flash_rodata_default = self._get_default("flash_rodata", expected)
-        dram0_data_default = self._get_default("dram0_data", expected)
-        dram0_bss_default = self._get_default("dram0_bss", expected)
+        flash_text_default = self.get_default("flash_text", expected)
+        flash_rodata_default = self.get_default("flash_rodata", expected)
+        dram0_data_default = self.get_default("dram0_data", expected)
+        dram0_bss_default = self.get_default("dram0_bss", expected)
 
         iram0_text_E1 = PlacementRule("libfreertos.a", "croutine", "prvCheckDelayedList", self.model.sections["text"].entries, "iram0_text")
         dram0_data_E1 = PlacementRule("libfreertos.a", "croutine", "prvCheckDelayedList", self.model.sections["rodata"].entries, "dram0_data")
 
         rtc_text_E2 = PlacementRule("libfreertos.a", "event_groups", "xEventGroupCreate", self.model.sections["text"].entries, "rtc_text")
         rtc_data_E2 = PlacementRule("libfreertos.a", "event_groups", "xEventGroupCreate",
-                                    self.model.sections["data"].entries + self.model.sections["rodata"].entries, "rtc_data")
+                                    self.model.sections["data"].entries | self.model.sections["rodata"].entries, "rtc_data")
         rtc_bss_E2 = PlacementRule("libfreertos.a", "event_groups", "xEventGroupCreate",
-                                   self.model.sections["bss"].entries + self.model.sections["common"].entries, "rtc_bss")
+                                   self.model.sections["bss"].entries | self.model.sections["common"].entries, "rtc_bss")
 
         rtc_text_E3 = PlacementRule("libfreertos.a", "croutine", None, self.model.sections["text"].entries, "rtc_text")
-        rtc_data_E3 = PlacementRule("libfreertos.a", "croutine", None, self.model.sections["data"].entries + self.model.sections["rodata"].entries, "rtc_data")
-        rtc_bss_E3 = PlacementRule("libfreertos.a", "croutine", None, self.model.sections["bss"].entries + self.model.sections["common"].entries, "rtc_bss")
+        rtc_data_E3 = PlacementRule("libfreertos.a", "croutine", None, self.model.sections["data"].entries | self.model.sections["rodata"].entries, "rtc_data")
+        rtc_bss_E3 = PlacementRule("libfreertos.a", "croutine", None, self.model.sections["bss"].entries | self.model.sections["common"].entries, "rtc_bss")
 
         iram0_text_E4 = PlacementRule("libfreertos.a", "event_groups", None, self.model.sections["text"].entries, "iram0_text")
         dram0_data_E4 = PlacementRule("libfreertos.a", "event_groups", None, self.model.sections["rodata"].entries, "dram0_data")
@@ -993,25 +983,25 @@ class GenerationModelTest(unittest.TestCase):
         expected["dram0_data"].append(dram0_data_extra)
         expected["dram0_bss"].append(dram0_bss_extra)
 
-        self._compare_rules(expected, actual)
+        self.compare_rules(expected, actual)
 
     def test_rule_generation_nominal_15(self):
-        normal = """
-        [mapping]
-        archive: libfreertos.a
-        entries:
-            croutine (noflash_data)
-            croutine (noflash_text)
-        """
+        normal = u"""
+[mapping:test]
+archive: libfreertos.a
+entries:
+    croutine (noflash_data)
+    croutine (noflash_text)
+"""
 
-        self._add_mapping(normal)
+        self.add_fragments(normal)
 
-        actual = self.model.generate_rules(self.sdkconfig, self.sections_info)
+        actual = self.model.generate_rules(self.sections_info)
 
-        expected = self._generate_default_rules()
+        expected = self.generate_default_rules()
 
-        flash_text_default = self._get_default("flash_text", expected)
-        flash_rodata_default = self._get_default("flash_rodata", expected)
+        flash_text_default = self.get_default("flash_text", expected)
+        flash_rodata_default = self.get_default("flash_rodata", expected)
 
         iram0_text_E1 = PlacementRule("libfreertos.a", "croutine", None, self.model.sections["text"].entries, "iram0_text")
         dram0_data_E1 = PlacementRule("libfreertos.a", "croutine", None, self.model.sections["rodata"].entries, "dram0_data")
@@ -1024,25 +1014,25 @@ class GenerationModelTest(unittest.TestCase):
         expected["iram0_text"].append(iram0_text_E1)
         expected["dram0_data"].append(dram0_data_E1)
 
-        self._compare_rules(expected, actual)
+        self.compare_rules(expected, actual)
 
     def test_rule_generation_nominal_16(self):
-        normal = """
-        [mapping]
-        archive: libfreertos.a
-        entries:
-            croutine (noflash_data)
-            croutine (noflash)
-        """
+        normal = u"""
+[mapping:test]
+archive: libfreertos.a
+entries:
+    croutine (noflash_data)
+    croutine (noflash)
+"""
 
-        self._add_mapping(normal)
+        self.add_fragments(normal)
 
-        actual = self.model.generate_rules(self.sdkconfig, self.sections_info)
+        actual = self.model.generate_rules(self.sections_info)
 
-        expected = self._generate_default_rules()
+        expected = self.generate_default_rules()
 
-        flash_text_default = self._get_default("flash_text", expected)
-        flash_rodata_default = self._get_default("flash_rodata", expected)
+        flash_text_default = self.get_default("flash_text", expected)
+        flash_rodata_default = self.get_default("flash_rodata", expected)
 
         iram0_text_E1 = PlacementRule("libfreertos.a", "croutine", None, self.model.sections["text"].entries, "iram0_text")
         dram0_data_E1 = PlacementRule("libfreertos.a", "croutine", None, self.model.sections["rodata"].entries, "dram0_data")
@@ -1055,60 +1045,58 @@ class GenerationModelTest(unittest.TestCase):
         expected["iram0_text"].append(iram0_text_E1)
         expected["dram0_data"].append(dram0_data_E1)
 
-        self._compare_rules(expected, actual)
+        self.compare_rules(expected, actual)
 
     def test_rule_generation_conflict(self):
-        conflict_mapping = """
-        [mapping]
-        archive: libfreertos.a
-        entries:
-            croutine (conflict)
-            croutine (noflash)
-        """
-
-        conflict_scheme = """
-        [scheme:conflict]
-        entries:
-            rodata -> dram0_data
-            bss -> dram0_data
-        """
-
-        self._add_scheme(conflict_scheme)
-        self._add_mapping(conflict_mapping)
+        conflict_mapping = u"""
+[mapping:test]
+archive: libfreertos.a
+entries:
+    croutine (conflict)
+    croutine (noflash)
+
+[scheme:conflict]
+entries:
+    rodata -> dram0_data
+    bss -> dram0_data
+"""
+        self.add_fragments(conflict_mapping)
 
         with self.assertRaises(GenerationException):
-            self.model.generate_rules(self.sdkconfig, self.sections_info)
+            self.model.generate_rules(self.sections_info)
 
     def test_rule_generation_condition(self):
-        generation_with_condition = """
-        [mapping]
-        archive: lib.a
-        entries:
-            : PERFORMANCE_LEVEL = 0
-            : PERFORMANCE_LEVEL = 1
-            obj1 (noflash)
-            : PERFORMANCE_LEVEL = 2
-            obj1 (noflash)
-            obj2 (noflash)
-            : PERFORMANCE_LEVEL = 3
-            obj1 (noflash)
-            obj2 (noflash)
-            obj3 (noflash)
-        """
-
-        self._add_mapping(generation_with_condition)
+        generation_with_condition = u"""
+[mapping:test]
+archive: lib.a
+entries:
+    if PERFORMANCE_LEVEL = 1:
+        obj1 (noflash)
+    elif PERFORMANCE_LEVEL = 2:
+        obj1 (noflash)
+        obj2 (noflash)
+    elif PERFORMANCE_LEVEL = 3:
+        obj1 (noflash)
+        obj2 (noflash)
+        obj3 (noflash)
+    else: # PERFORMANCE_LEVEL = 0
+        * (default)
+"""
 
         for perf_level in range(0, 4):
             self.sdkconfig.config.syms["PERFORMANCE_LEVEL"].set_value(str(perf_level))
 
-            actual = self.model.generate_rules(self.sdkconfig, self.sections_info)
-            expected = self._generate_default_rules()
+            self.model.mappings = {}
+            self.add_fragments(generation_with_condition)
 
-            flash_text_default = self._get_default("flash_text", expected)
-            flash_rodata_default = self._get_default("flash_rodata", expected)
+            actual = self.model.generate_rules(self.sections_info)
+            expected = self.generate_default_rules()
 
             if perf_level < 4:
                 for append_no in range(1, perf_level + 1):
+                    flash_text_default = self.get_default("flash_text", expected)
+                    flash_rodata_default = self.get_default("flash_rodata", expected)
+
                     iram_rule = PlacementRule("lib.a", "obj" + str(append_no), None, self.model.sections["text"].entries, "iram0_text")
                     dram_rule = PlacementRule("lib.a", "obj" + str(append_no), None, self.model.sections["rodata"].entries, "dram0_data")
 
@@ -1118,7 +1106,89 @@ class GenerationModelTest(unittest.TestCase):
                     expected["iram0_text"].append(iram_rule)
                     expected["dram0_data"].append(dram_rule)
 
-            self._compare_rules(expected, actual)
+            self.compare_rules(expected, actual)
+
+    def test_conditional_sections_1(self):
+        generation_with_condition = u"""
+[sections:cond_text_data]
+entries:
+    if PERFORMANCE_LEVEL >= 1:
+        .text+
+        .literal+
+    else:
+        .data+
+
+[scheme:cond_noflash]
+entries:
+    if PERFORMANCE_LEVEL >= 1:
+        cond_text_data -> iram0_text
+    else:
+        cond_text_data -> dram0_data
+
+[mapping:test]
+archive: lib.a
+entries:
+    * (cond_noflash)
+"""
+
+        self.sdkconfig.config.syms["PERFORMANCE_LEVEL"].set_value("1")
+        self.add_fragments(generation_with_condition)
+
+        actual = self.model.generate_rules(self.sections_info)
+        expected = self.generate_default_rules()
+
+        flash_text_default = self.get_default("flash_text", expected)
+
+        iram0_text_E1 = PlacementRule("lib.a", "*", None, self.model.sections["text"].entries, "iram0_text")
+
+        # Add the exclusions
+        flash_text_default.add_exclusion(iram0_text_E1)
+
+        # Add to the placement rules list
+        expected["iram0_text"].append(iram0_text_E1)
+
+        self.compare_rules(expected, actual)
+
+    def test_conditional_sections_2(self):
+        generation_with_condition = u"""
+[sections:cond_text_data]
+entries:
+    if PERFORMANCE_LEVEL >= 1:
+        .text+
+        .literal+
+    else:
+        .rodata+
+
+[scheme:cond_noflash]
+entries:
+    if PERFORMANCE_LEVEL >= 1:
+        cond_text_data -> iram0_text
+    else:
+        cond_text_data -> dram0_data
+
+[mapping:test]
+archive: lib.a
+entries:
+    * (cond_noflash)
+"""
+
+        self.sdkconfig.config.syms["PERFORMANCE_LEVEL"].set_value("0")
+        self.add_fragments(generation_with_condition)
+
+        actual = self.model.generate_rules(self.sections_info)
+        expected = self.generate_default_rules()
+
+        flash_rodata_default = self.get_default("flash_rodata", expected)
+
+        dram0_data_E1 = PlacementRule("lib.a", "*", None, self.model.sections["rodata"].entries, "dram0_data")
+
+        # Add the exclusions
+        flash_rodata_default.add_exclusion(dram0_data_E1)
+
+        # Add to the placement rules list
+        expected["dram0_data"].append(dram0_data_E1)
+
+        self.compare_rules(expected, actual)
 
 
 if __name__ == "__main__":