17db96d56Sopenharmony_ci"""Tests to cover the Tools/i18n package"""
27db96d56Sopenharmony_ci
37db96d56Sopenharmony_ciimport os
47db96d56Sopenharmony_ciimport sys
57db96d56Sopenharmony_ciimport unittest
67db96d56Sopenharmony_cifrom textwrap import dedent
77db96d56Sopenharmony_ci
87db96d56Sopenharmony_cifrom test.support.script_helper import assert_python_ok
97db96d56Sopenharmony_cifrom test.test_tools import skip_if_missing, toolsdir
107db96d56Sopenharmony_cifrom test.support.os_helper import temp_cwd, temp_dir
117db96d56Sopenharmony_ci
127db96d56Sopenharmony_ci
137db96d56Sopenharmony_ciskip_if_missing()
147db96d56Sopenharmony_ci
157db96d56Sopenharmony_ci
167db96d56Sopenharmony_ciclass Test_pygettext(unittest.TestCase):
177db96d56Sopenharmony_ci    """Tests for the pygettext.py tool"""
187db96d56Sopenharmony_ci
197db96d56Sopenharmony_ci    script = os.path.join(toolsdir,'i18n', 'pygettext.py')
207db96d56Sopenharmony_ci
217db96d56Sopenharmony_ci    def get_header(self, data):
227db96d56Sopenharmony_ci        """ utility: return the header of a .po file as a dictionary """
237db96d56Sopenharmony_ci        headers = {}
247db96d56Sopenharmony_ci        for line in data.split('\n'):
257db96d56Sopenharmony_ci            if not line or line.startswith(('#', 'msgid','msgstr')):
267db96d56Sopenharmony_ci                continue
277db96d56Sopenharmony_ci            line = line.strip('"')
287db96d56Sopenharmony_ci            key, val = line.split(':',1)
297db96d56Sopenharmony_ci            headers[key] = val.strip()
307db96d56Sopenharmony_ci        return headers
317db96d56Sopenharmony_ci
327db96d56Sopenharmony_ci    def get_msgids(self, data):
337db96d56Sopenharmony_ci        """ utility: return all msgids in .po file as a list of strings """
347db96d56Sopenharmony_ci        msgids = []
357db96d56Sopenharmony_ci        reading_msgid = False
367db96d56Sopenharmony_ci        cur_msgid = []
377db96d56Sopenharmony_ci        for line in data.split('\n'):
387db96d56Sopenharmony_ci            if reading_msgid:
397db96d56Sopenharmony_ci                if line.startswith('"'):
407db96d56Sopenharmony_ci                    cur_msgid.append(line.strip('"'))
417db96d56Sopenharmony_ci                else:
427db96d56Sopenharmony_ci                    msgids.append('\n'.join(cur_msgid))
437db96d56Sopenharmony_ci                    cur_msgid = []
447db96d56Sopenharmony_ci                    reading_msgid = False
457db96d56Sopenharmony_ci                    continue
467db96d56Sopenharmony_ci            if line.startswith('msgid '):
477db96d56Sopenharmony_ci                line = line[len('msgid '):]
487db96d56Sopenharmony_ci                cur_msgid.append(line.strip('"'))
497db96d56Sopenharmony_ci                reading_msgid = True
507db96d56Sopenharmony_ci        else:
517db96d56Sopenharmony_ci            if reading_msgid:
527db96d56Sopenharmony_ci                msgids.append('\n'.join(cur_msgid))
537db96d56Sopenharmony_ci
547db96d56Sopenharmony_ci        return msgids
557db96d56Sopenharmony_ci
567db96d56Sopenharmony_ci    def extract_docstrings_from_str(self, module_content):
577db96d56Sopenharmony_ci        """ utility: return all msgids extracted from module_content """
587db96d56Sopenharmony_ci        filename = 'test_docstrings.py'
597db96d56Sopenharmony_ci        with temp_cwd(None) as cwd:
607db96d56Sopenharmony_ci            with open(filename, 'w', encoding='utf-8') as fp:
617db96d56Sopenharmony_ci                fp.write(module_content)
627db96d56Sopenharmony_ci            assert_python_ok(self.script, '-D', filename)
637db96d56Sopenharmony_ci            with open('messages.pot', encoding='utf-8') as fp:
647db96d56Sopenharmony_ci                data = fp.read()
657db96d56Sopenharmony_ci        return self.get_msgids(data)
667db96d56Sopenharmony_ci
677db96d56Sopenharmony_ci    def test_header(self):
687db96d56Sopenharmony_ci        """Make sure the required fields are in the header, according to:
697db96d56Sopenharmony_ci           http://www.gnu.org/software/gettext/manual/gettext.html#Header-Entry
707db96d56Sopenharmony_ci        """
717db96d56Sopenharmony_ci        with temp_cwd(None) as cwd:
727db96d56Sopenharmony_ci            assert_python_ok(self.script)
737db96d56Sopenharmony_ci            with open('messages.pot', encoding='utf-8') as fp:
747db96d56Sopenharmony_ci                data = fp.read()
757db96d56Sopenharmony_ci            header = self.get_header(data)
767db96d56Sopenharmony_ci
777db96d56Sopenharmony_ci            self.assertIn("Project-Id-Version", header)
787db96d56Sopenharmony_ci            self.assertIn("POT-Creation-Date", header)
797db96d56Sopenharmony_ci            self.assertIn("PO-Revision-Date", header)
807db96d56Sopenharmony_ci            self.assertIn("Last-Translator", header)
817db96d56Sopenharmony_ci            self.assertIn("Language-Team", header)
827db96d56Sopenharmony_ci            self.assertIn("MIME-Version", header)
837db96d56Sopenharmony_ci            self.assertIn("Content-Type", header)
847db96d56Sopenharmony_ci            self.assertIn("Content-Transfer-Encoding", header)
857db96d56Sopenharmony_ci            self.assertIn("Generated-By", header)
867db96d56Sopenharmony_ci
877db96d56Sopenharmony_ci            # not clear if these should be required in POT (template) files
887db96d56Sopenharmony_ci            #self.assertIn("Report-Msgid-Bugs-To", header)
897db96d56Sopenharmony_ci            #self.assertIn("Language", header)
907db96d56Sopenharmony_ci
917db96d56Sopenharmony_ci            #"Plural-Forms" is optional
927db96d56Sopenharmony_ci
937db96d56Sopenharmony_ci    @unittest.skipIf(sys.platform.startswith('aix'),
947db96d56Sopenharmony_ci                     'bpo-29972: broken test on AIX')
957db96d56Sopenharmony_ci    def test_POT_Creation_Date(self):
967db96d56Sopenharmony_ci        """ Match the date format from xgettext for POT-Creation-Date """
977db96d56Sopenharmony_ci        from datetime import datetime
987db96d56Sopenharmony_ci        with temp_cwd(None) as cwd:
997db96d56Sopenharmony_ci            assert_python_ok(self.script)
1007db96d56Sopenharmony_ci            with open('messages.pot', encoding='utf-8') as fp:
1017db96d56Sopenharmony_ci                data = fp.read()
1027db96d56Sopenharmony_ci            header = self.get_header(data)
1037db96d56Sopenharmony_ci            creationDate = header['POT-Creation-Date']
1047db96d56Sopenharmony_ci
1057db96d56Sopenharmony_ci            # peel off the escaped newline at the end of string
1067db96d56Sopenharmony_ci            if creationDate.endswith('\\n'):
1077db96d56Sopenharmony_ci                creationDate = creationDate[:-len('\\n')]
1087db96d56Sopenharmony_ci
1097db96d56Sopenharmony_ci            # This will raise if the date format does not exactly match.
1107db96d56Sopenharmony_ci            datetime.strptime(creationDate, '%Y-%m-%d %H:%M%z')
1117db96d56Sopenharmony_ci
1127db96d56Sopenharmony_ci    def test_funcdocstring(self):
1137db96d56Sopenharmony_ci        for doc in ('"""doc"""', "r'''doc'''", "R'doc'", 'u"doc"'):
1147db96d56Sopenharmony_ci            with self.subTest(doc):
1157db96d56Sopenharmony_ci                msgids = self.extract_docstrings_from_str(dedent('''\
1167db96d56Sopenharmony_ci                def foo(bar):
1177db96d56Sopenharmony_ci                    %s
1187db96d56Sopenharmony_ci                ''' % doc))
1197db96d56Sopenharmony_ci                self.assertIn('doc', msgids)
1207db96d56Sopenharmony_ci
1217db96d56Sopenharmony_ci    def test_funcdocstring_bytes(self):
1227db96d56Sopenharmony_ci        msgids = self.extract_docstrings_from_str(dedent('''\
1237db96d56Sopenharmony_ci        def foo(bar):
1247db96d56Sopenharmony_ci            b"""doc"""
1257db96d56Sopenharmony_ci        '''))
1267db96d56Sopenharmony_ci        self.assertFalse([msgid for msgid in msgids if 'doc' in msgid])
1277db96d56Sopenharmony_ci
1287db96d56Sopenharmony_ci    def test_funcdocstring_fstring(self):
1297db96d56Sopenharmony_ci        msgids = self.extract_docstrings_from_str(dedent('''\
1307db96d56Sopenharmony_ci        def foo(bar):
1317db96d56Sopenharmony_ci            f"""doc"""
1327db96d56Sopenharmony_ci        '''))
1337db96d56Sopenharmony_ci        self.assertFalse([msgid for msgid in msgids if 'doc' in msgid])
1347db96d56Sopenharmony_ci
1357db96d56Sopenharmony_ci    def test_classdocstring(self):
1367db96d56Sopenharmony_ci        for doc in ('"""doc"""', "r'''doc'''", "R'doc'", 'u"doc"'):
1377db96d56Sopenharmony_ci            with self.subTest(doc):
1387db96d56Sopenharmony_ci                msgids = self.extract_docstrings_from_str(dedent('''\
1397db96d56Sopenharmony_ci                class C:
1407db96d56Sopenharmony_ci                    %s
1417db96d56Sopenharmony_ci                ''' % doc))
1427db96d56Sopenharmony_ci                self.assertIn('doc', msgids)
1437db96d56Sopenharmony_ci
1447db96d56Sopenharmony_ci    def test_classdocstring_bytes(self):
1457db96d56Sopenharmony_ci        msgids = self.extract_docstrings_from_str(dedent('''\
1467db96d56Sopenharmony_ci        class C:
1477db96d56Sopenharmony_ci            b"""doc"""
1487db96d56Sopenharmony_ci        '''))
1497db96d56Sopenharmony_ci        self.assertFalse([msgid for msgid in msgids if 'doc' in msgid])
1507db96d56Sopenharmony_ci
1517db96d56Sopenharmony_ci    def test_classdocstring_fstring(self):
1527db96d56Sopenharmony_ci        msgids = self.extract_docstrings_from_str(dedent('''\
1537db96d56Sopenharmony_ci        class C:
1547db96d56Sopenharmony_ci            f"""doc"""
1557db96d56Sopenharmony_ci        '''))
1567db96d56Sopenharmony_ci        self.assertFalse([msgid for msgid in msgids if 'doc' in msgid])
1577db96d56Sopenharmony_ci
1587db96d56Sopenharmony_ci    def test_moduledocstring(self):
1597db96d56Sopenharmony_ci        for doc in ('"""doc"""', "r'''doc'''", "R'doc'", 'u"doc"'):
1607db96d56Sopenharmony_ci            with self.subTest(doc):
1617db96d56Sopenharmony_ci                msgids = self.extract_docstrings_from_str(dedent('''\
1627db96d56Sopenharmony_ci                %s
1637db96d56Sopenharmony_ci                ''' % doc))
1647db96d56Sopenharmony_ci                self.assertIn('doc', msgids)
1657db96d56Sopenharmony_ci
1667db96d56Sopenharmony_ci    def test_moduledocstring_bytes(self):
1677db96d56Sopenharmony_ci        msgids = self.extract_docstrings_from_str(dedent('''\
1687db96d56Sopenharmony_ci        b"""doc"""
1697db96d56Sopenharmony_ci        '''))
1707db96d56Sopenharmony_ci        self.assertFalse([msgid for msgid in msgids if 'doc' in msgid])
1717db96d56Sopenharmony_ci
1727db96d56Sopenharmony_ci    def test_moduledocstring_fstring(self):
1737db96d56Sopenharmony_ci        msgids = self.extract_docstrings_from_str(dedent('''\
1747db96d56Sopenharmony_ci        f"""doc"""
1757db96d56Sopenharmony_ci        '''))
1767db96d56Sopenharmony_ci        self.assertFalse([msgid for msgid in msgids if 'doc' in msgid])
1777db96d56Sopenharmony_ci
1787db96d56Sopenharmony_ci    def test_msgid(self):
1797db96d56Sopenharmony_ci        msgids = self.extract_docstrings_from_str(
1807db96d56Sopenharmony_ci                '''_("""doc""" r'str' u"ing")''')
1817db96d56Sopenharmony_ci        self.assertIn('docstring', msgids)
1827db96d56Sopenharmony_ci
1837db96d56Sopenharmony_ci    def test_msgid_bytes(self):
1847db96d56Sopenharmony_ci        msgids = self.extract_docstrings_from_str('_(b"""doc""")')
1857db96d56Sopenharmony_ci        self.assertFalse([msgid for msgid in msgids if 'doc' in msgid])
1867db96d56Sopenharmony_ci
1877db96d56Sopenharmony_ci    def test_msgid_fstring(self):
1887db96d56Sopenharmony_ci        msgids = self.extract_docstrings_from_str('_(f"""doc""")')
1897db96d56Sopenharmony_ci        self.assertFalse([msgid for msgid in msgids if 'doc' in msgid])
1907db96d56Sopenharmony_ci
1917db96d56Sopenharmony_ci    def test_funcdocstring_annotated_args(self):
1927db96d56Sopenharmony_ci        """ Test docstrings for functions with annotated args """
1937db96d56Sopenharmony_ci        msgids = self.extract_docstrings_from_str(dedent('''\
1947db96d56Sopenharmony_ci        def foo(bar: str):
1957db96d56Sopenharmony_ci            """doc"""
1967db96d56Sopenharmony_ci        '''))
1977db96d56Sopenharmony_ci        self.assertIn('doc', msgids)
1987db96d56Sopenharmony_ci
1997db96d56Sopenharmony_ci    def test_funcdocstring_annotated_return(self):
2007db96d56Sopenharmony_ci        """ Test docstrings for functions with annotated return type """
2017db96d56Sopenharmony_ci        msgids = self.extract_docstrings_from_str(dedent('''\
2027db96d56Sopenharmony_ci        def foo(bar) -> str:
2037db96d56Sopenharmony_ci            """doc"""
2047db96d56Sopenharmony_ci        '''))
2057db96d56Sopenharmony_ci        self.assertIn('doc', msgids)
2067db96d56Sopenharmony_ci
2077db96d56Sopenharmony_ci    def test_funcdocstring_defvalue_args(self):
2087db96d56Sopenharmony_ci        """ Test docstring for functions with default arg values """
2097db96d56Sopenharmony_ci        msgids = self.extract_docstrings_from_str(dedent('''\
2107db96d56Sopenharmony_ci        def foo(bar=()):
2117db96d56Sopenharmony_ci            """doc"""
2127db96d56Sopenharmony_ci        '''))
2137db96d56Sopenharmony_ci        self.assertIn('doc', msgids)
2147db96d56Sopenharmony_ci
2157db96d56Sopenharmony_ci    def test_funcdocstring_multiple_funcs(self):
2167db96d56Sopenharmony_ci        """ Test docstring extraction for multiple functions combining
2177db96d56Sopenharmony_ci        annotated args, annotated return types and default arg values
2187db96d56Sopenharmony_ci        """
2197db96d56Sopenharmony_ci        msgids = self.extract_docstrings_from_str(dedent('''\
2207db96d56Sopenharmony_ci        def foo1(bar: tuple=()) -> str:
2217db96d56Sopenharmony_ci            """doc1"""
2227db96d56Sopenharmony_ci
2237db96d56Sopenharmony_ci        def foo2(bar: List[1:2]) -> (lambda x: x):
2247db96d56Sopenharmony_ci            """doc2"""
2257db96d56Sopenharmony_ci
2267db96d56Sopenharmony_ci        def foo3(bar: 'func'=lambda x: x) -> {1: 2}:
2277db96d56Sopenharmony_ci            """doc3"""
2287db96d56Sopenharmony_ci        '''))
2297db96d56Sopenharmony_ci        self.assertIn('doc1', msgids)
2307db96d56Sopenharmony_ci        self.assertIn('doc2', msgids)
2317db96d56Sopenharmony_ci        self.assertIn('doc3', msgids)
2327db96d56Sopenharmony_ci
2337db96d56Sopenharmony_ci    def test_classdocstring_early_colon(self):
2347db96d56Sopenharmony_ci        """ Test docstring extraction for a class with colons occurring within
2357db96d56Sopenharmony_ci        the parentheses.
2367db96d56Sopenharmony_ci        """
2377db96d56Sopenharmony_ci        msgids = self.extract_docstrings_from_str(dedent('''\
2387db96d56Sopenharmony_ci        class D(L[1:2], F({1: 2}), metaclass=M(lambda x: x)):
2397db96d56Sopenharmony_ci            """doc"""
2407db96d56Sopenharmony_ci        '''))
2417db96d56Sopenharmony_ci        self.assertIn('doc', msgids)
2427db96d56Sopenharmony_ci
2437db96d56Sopenharmony_ci    def test_calls_in_fstrings(self):
2447db96d56Sopenharmony_ci        msgids = self.extract_docstrings_from_str(dedent('''\
2457db96d56Sopenharmony_ci        f"{_('foo bar')}"
2467db96d56Sopenharmony_ci        '''))
2477db96d56Sopenharmony_ci        self.assertIn('foo bar', msgids)
2487db96d56Sopenharmony_ci
2497db96d56Sopenharmony_ci    def test_calls_in_fstrings_raw(self):
2507db96d56Sopenharmony_ci        msgids = self.extract_docstrings_from_str(dedent('''\
2517db96d56Sopenharmony_ci        rf"{_('foo bar')}"
2527db96d56Sopenharmony_ci        '''))
2537db96d56Sopenharmony_ci        self.assertIn('foo bar', msgids)
2547db96d56Sopenharmony_ci
2557db96d56Sopenharmony_ci    def test_calls_in_fstrings_nested(self):
2567db96d56Sopenharmony_ci        msgids = self.extract_docstrings_from_str(dedent('''\
2577db96d56Sopenharmony_ci        f"""{f'{_("foo bar")}'}"""
2587db96d56Sopenharmony_ci        '''))
2597db96d56Sopenharmony_ci        self.assertIn('foo bar', msgids)
2607db96d56Sopenharmony_ci
2617db96d56Sopenharmony_ci    def test_calls_in_fstrings_attribute(self):
2627db96d56Sopenharmony_ci        msgids = self.extract_docstrings_from_str(dedent('''\
2637db96d56Sopenharmony_ci        f"{obj._('foo bar')}"
2647db96d56Sopenharmony_ci        '''))
2657db96d56Sopenharmony_ci        self.assertIn('foo bar', msgids)
2667db96d56Sopenharmony_ci
2677db96d56Sopenharmony_ci    def test_calls_in_fstrings_with_call_on_call(self):
2687db96d56Sopenharmony_ci        msgids = self.extract_docstrings_from_str(dedent('''\
2697db96d56Sopenharmony_ci        f"{type(str)('foo bar')}"
2707db96d56Sopenharmony_ci        '''))
2717db96d56Sopenharmony_ci        self.assertNotIn('foo bar', msgids)
2727db96d56Sopenharmony_ci
2737db96d56Sopenharmony_ci    def test_calls_in_fstrings_with_format(self):
2747db96d56Sopenharmony_ci        msgids = self.extract_docstrings_from_str(dedent('''\
2757db96d56Sopenharmony_ci        f"{_('foo {bar}').format(bar='baz')}"
2767db96d56Sopenharmony_ci        '''))
2777db96d56Sopenharmony_ci        self.assertIn('foo {bar}', msgids)
2787db96d56Sopenharmony_ci
2797db96d56Sopenharmony_ci    def test_calls_in_fstrings_with_wrong_input_1(self):
2807db96d56Sopenharmony_ci        msgids = self.extract_docstrings_from_str(dedent('''\
2817db96d56Sopenharmony_ci        f"{_(f'foo {bar}')}"
2827db96d56Sopenharmony_ci        '''))
2837db96d56Sopenharmony_ci        self.assertFalse([msgid for msgid in msgids if 'foo {bar}' in msgid])
2847db96d56Sopenharmony_ci
2857db96d56Sopenharmony_ci    def test_calls_in_fstrings_with_wrong_input_2(self):
2867db96d56Sopenharmony_ci        msgids = self.extract_docstrings_from_str(dedent('''\
2877db96d56Sopenharmony_ci        f"{_(1)}"
2887db96d56Sopenharmony_ci        '''))
2897db96d56Sopenharmony_ci        self.assertNotIn(1, msgids)
2907db96d56Sopenharmony_ci
2917db96d56Sopenharmony_ci    def test_calls_in_fstring_with_multiple_args(self):
2927db96d56Sopenharmony_ci        msgids = self.extract_docstrings_from_str(dedent('''\
2937db96d56Sopenharmony_ci        f"{_('foo', 'bar')}"
2947db96d56Sopenharmony_ci        '''))
2957db96d56Sopenharmony_ci        self.assertNotIn('foo', msgids)
2967db96d56Sopenharmony_ci        self.assertNotIn('bar', msgids)
2977db96d56Sopenharmony_ci
2987db96d56Sopenharmony_ci    def test_calls_in_fstring_with_keyword_args(self):
2997db96d56Sopenharmony_ci        msgids = self.extract_docstrings_from_str(dedent('''\
3007db96d56Sopenharmony_ci        f"{_('foo', bar='baz')}"
3017db96d56Sopenharmony_ci        '''))
3027db96d56Sopenharmony_ci        self.assertNotIn('foo', msgids)
3037db96d56Sopenharmony_ci        self.assertNotIn('bar', msgids)
3047db96d56Sopenharmony_ci        self.assertNotIn('baz', msgids)
3057db96d56Sopenharmony_ci
3067db96d56Sopenharmony_ci    def test_calls_in_fstring_with_partially_wrong_expression(self):
3077db96d56Sopenharmony_ci        msgids = self.extract_docstrings_from_str(dedent('''\
3087db96d56Sopenharmony_ci        f"{_(f'foo') + _('bar')}"
3097db96d56Sopenharmony_ci        '''))
3107db96d56Sopenharmony_ci        self.assertNotIn('foo', msgids)
3117db96d56Sopenharmony_ci        self.assertIn('bar', msgids)
3127db96d56Sopenharmony_ci
3137db96d56Sopenharmony_ci    def test_files_list(self):
3147db96d56Sopenharmony_ci        """Make sure the directories are inspected for source files
3157db96d56Sopenharmony_ci           bpo-31920
3167db96d56Sopenharmony_ci        """
3177db96d56Sopenharmony_ci        text1 = 'Text to translate1'
3187db96d56Sopenharmony_ci        text2 = 'Text to translate2'
3197db96d56Sopenharmony_ci        text3 = 'Text to ignore'
3207db96d56Sopenharmony_ci        with temp_cwd(None), temp_dir(None) as sdir:
3217db96d56Sopenharmony_ci            os.mkdir(os.path.join(sdir, 'pypkg'))
3227db96d56Sopenharmony_ci            with open(os.path.join(sdir, 'pypkg', 'pymod.py'), 'w',
3237db96d56Sopenharmony_ci                      encoding='utf-8') as sfile:
3247db96d56Sopenharmony_ci                sfile.write(f'_({text1!r})')
3257db96d56Sopenharmony_ci            os.mkdir(os.path.join(sdir, 'pkg.py'))
3267db96d56Sopenharmony_ci            with open(os.path.join(sdir, 'pkg.py', 'pymod2.py'), 'w',
3277db96d56Sopenharmony_ci                      encoding='utf-8') as sfile:
3287db96d56Sopenharmony_ci                sfile.write(f'_({text2!r})')
3297db96d56Sopenharmony_ci            os.mkdir(os.path.join(sdir, 'CVS'))
3307db96d56Sopenharmony_ci            with open(os.path.join(sdir, 'CVS', 'pymod3.py'), 'w',
3317db96d56Sopenharmony_ci                      encoding='utf-8') as sfile:
3327db96d56Sopenharmony_ci                sfile.write(f'_({text3!r})')
3337db96d56Sopenharmony_ci            assert_python_ok(self.script, sdir)
3347db96d56Sopenharmony_ci            with open('messages.pot', encoding='utf-8') as fp:
3357db96d56Sopenharmony_ci                data = fp.read()
3367db96d56Sopenharmony_ci            self.assertIn(f'msgid "{text1}"', data)
3377db96d56Sopenharmony_ci            self.assertIn(f'msgid "{text2}"', data)
3387db96d56Sopenharmony_ci            self.assertNotIn(text3, data)
339