17db96d56Sopenharmony_cifrom collections import namedtuple
27db96d56Sopenharmony_ciimport contextlib
37db96d56Sopenharmony_ciimport itertools
47db96d56Sopenharmony_ciimport os
57db96d56Sopenharmony_ciimport pickle
67db96d56Sopenharmony_ciimport sys
77db96d56Sopenharmony_cifrom textwrap import dedent
87db96d56Sopenharmony_ciimport threading
97db96d56Sopenharmony_ciimport time
107db96d56Sopenharmony_ciimport unittest
117db96d56Sopenharmony_ci
127db96d56Sopenharmony_cifrom test import support
137db96d56Sopenharmony_cifrom test.support import import_helper
147db96d56Sopenharmony_cifrom test.support import script_helper
157db96d56Sopenharmony_ci
167db96d56Sopenharmony_ci
177db96d56Sopenharmony_ciinterpreters = import_helper.import_module('_xxsubinterpreters')
187db96d56Sopenharmony_ci
197db96d56Sopenharmony_ci
207db96d56Sopenharmony_ci##################################
217db96d56Sopenharmony_ci# helpers
227db96d56Sopenharmony_ci
237db96d56Sopenharmony_cidef _captured_script(script):
247db96d56Sopenharmony_ci    r, w = os.pipe()
257db96d56Sopenharmony_ci    indented = script.replace('\n', '\n                ')
267db96d56Sopenharmony_ci    wrapped = dedent(f"""
277db96d56Sopenharmony_ci        import contextlib
287db96d56Sopenharmony_ci        with open({w}, 'w', encoding="utf-8") as spipe:
297db96d56Sopenharmony_ci            with contextlib.redirect_stdout(spipe):
307db96d56Sopenharmony_ci                {indented}
317db96d56Sopenharmony_ci        """)
327db96d56Sopenharmony_ci    return wrapped, open(r, encoding="utf-8")
337db96d56Sopenharmony_ci
347db96d56Sopenharmony_ci
357db96d56Sopenharmony_cidef _run_output(interp, request, shared=None):
367db96d56Sopenharmony_ci    script, rpipe = _captured_script(request)
377db96d56Sopenharmony_ci    with rpipe:
387db96d56Sopenharmony_ci        interpreters.run_string(interp, script, shared)
397db96d56Sopenharmony_ci        return rpipe.read()
407db96d56Sopenharmony_ci
417db96d56Sopenharmony_ci
427db96d56Sopenharmony_cidef _wait_for_interp_to_run(interp, timeout=None):
437db96d56Sopenharmony_ci    # bpo-37224: Running this test file in multiprocesses will fail randomly.
447db96d56Sopenharmony_ci    # The failure reason is that the thread can't acquire the cpu to
457db96d56Sopenharmony_ci    # run subinterpreter eariler than the main thread in multiprocess.
467db96d56Sopenharmony_ci    if timeout is None:
477db96d56Sopenharmony_ci        timeout = support.SHORT_TIMEOUT
487db96d56Sopenharmony_ci    start_time = time.monotonic()
497db96d56Sopenharmony_ci    deadline = start_time + timeout
507db96d56Sopenharmony_ci    while not interpreters.is_running(interp):
517db96d56Sopenharmony_ci        if time.monotonic() > deadline:
527db96d56Sopenharmony_ci            raise RuntimeError('interp is not running')
537db96d56Sopenharmony_ci        time.sleep(0.010)
547db96d56Sopenharmony_ci
557db96d56Sopenharmony_ci
567db96d56Sopenharmony_ci@contextlib.contextmanager
577db96d56Sopenharmony_cidef _running(interp):
587db96d56Sopenharmony_ci    r, w = os.pipe()
597db96d56Sopenharmony_ci    def run():
607db96d56Sopenharmony_ci        interpreters.run_string(interp, dedent(f"""
617db96d56Sopenharmony_ci            # wait for "signal"
627db96d56Sopenharmony_ci            with open({r}, encoding="utf-8") as rpipe:
637db96d56Sopenharmony_ci                rpipe.read()
647db96d56Sopenharmony_ci            """))
657db96d56Sopenharmony_ci
667db96d56Sopenharmony_ci    t = threading.Thread(target=run)
677db96d56Sopenharmony_ci    t.start()
687db96d56Sopenharmony_ci    _wait_for_interp_to_run(interp)
697db96d56Sopenharmony_ci
707db96d56Sopenharmony_ci    yield
717db96d56Sopenharmony_ci
727db96d56Sopenharmony_ci    with open(w, 'w', encoding="utf-8") as spipe:
737db96d56Sopenharmony_ci        spipe.write('done')
747db96d56Sopenharmony_ci    t.join()
757db96d56Sopenharmony_ci
767db96d56Sopenharmony_ci
777db96d56Sopenharmony_ci#@contextmanager
787db96d56Sopenharmony_ci#def run_threaded(id, source, **shared):
797db96d56Sopenharmony_ci#    def run():
807db96d56Sopenharmony_ci#        run_interp(id, source, **shared)
817db96d56Sopenharmony_ci#    t = threading.Thread(target=run)
827db96d56Sopenharmony_ci#    t.start()
837db96d56Sopenharmony_ci#    yield
847db96d56Sopenharmony_ci#    t.join()
857db96d56Sopenharmony_ci
867db96d56Sopenharmony_ci
877db96d56Sopenharmony_cidef run_interp(id, source, **shared):
887db96d56Sopenharmony_ci    _run_interp(id, source, shared)
897db96d56Sopenharmony_ci
907db96d56Sopenharmony_ci
917db96d56Sopenharmony_cidef _run_interp(id, source, shared, _mainns={}):
927db96d56Sopenharmony_ci    source = dedent(source)
937db96d56Sopenharmony_ci    main = interpreters.get_main()
947db96d56Sopenharmony_ci    if main == id:
957db96d56Sopenharmony_ci        if interpreters.get_current() != main:
967db96d56Sopenharmony_ci            raise RuntimeError
977db96d56Sopenharmony_ci        # XXX Run a func?
987db96d56Sopenharmony_ci        exec(source, _mainns)
997db96d56Sopenharmony_ci    else:
1007db96d56Sopenharmony_ci        interpreters.run_string(id, source, shared)
1017db96d56Sopenharmony_ci
1027db96d56Sopenharmony_ci
1037db96d56Sopenharmony_ciclass Interpreter(namedtuple('Interpreter', 'name id')):
1047db96d56Sopenharmony_ci
1057db96d56Sopenharmony_ci    @classmethod
1067db96d56Sopenharmony_ci    def from_raw(cls, raw):
1077db96d56Sopenharmony_ci        if isinstance(raw, cls):
1087db96d56Sopenharmony_ci            return raw
1097db96d56Sopenharmony_ci        elif isinstance(raw, str):
1107db96d56Sopenharmony_ci            return cls(raw)
1117db96d56Sopenharmony_ci        else:
1127db96d56Sopenharmony_ci            raise NotImplementedError
1137db96d56Sopenharmony_ci
1147db96d56Sopenharmony_ci    def __new__(cls, name=None, id=None):
1157db96d56Sopenharmony_ci        main = interpreters.get_main()
1167db96d56Sopenharmony_ci        if id == main:
1177db96d56Sopenharmony_ci            if not name:
1187db96d56Sopenharmony_ci                name = 'main'
1197db96d56Sopenharmony_ci            elif name != 'main':
1207db96d56Sopenharmony_ci                raise ValueError(
1217db96d56Sopenharmony_ci                    'name mismatch (expected "main", got "{}")'.format(name))
1227db96d56Sopenharmony_ci            id = main
1237db96d56Sopenharmony_ci        elif id is not None:
1247db96d56Sopenharmony_ci            if not name:
1257db96d56Sopenharmony_ci                name = 'interp'
1267db96d56Sopenharmony_ci            elif name == 'main':
1277db96d56Sopenharmony_ci                raise ValueError('name mismatch (unexpected "main")')
1287db96d56Sopenharmony_ci            if not isinstance(id, interpreters.InterpreterID):
1297db96d56Sopenharmony_ci                id = interpreters.InterpreterID(id)
1307db96d56Sopenharmony_ci        elif not name or name == 'main':
1317db96d56Sopenharmony_ci            name = 'main'
1327db96d56Sopenharmony_ci            id = main
1337db96d56Sopenharmony_ci        else:
1347db96d56Sopenharmony_ci            id = interpreters.create()
1357db96d56Sopenharmony_ci        self = super().__new__(cls, name, id)
1367db96d56Sopenharmony_ci        return self
1377db96d56Sopenharmony_ci
1387db96d56Sopenharmony_ci
1397db96d56Sopenharmony_ci# XXX expect_channel_closed() is unnecessary once we improve exc propagation.
1407db96d56Sopenharmony_ci
1417db96d56Sopenharmony_ci@contextlib.contextmanager
1427db96d56Sopenharmony_cidef expect_channel_closed():
1437db96d56Sopenharmony_ci    try:
1447db96d56Sopenharmony_ci        yield
1457db96d56Sopenharmony_ci    except interpreters.ChannelClosedError:
1467db96d56Sopenharmony_ci        pass
1477db96d56Sopenharmony_ci    else:
1487db96d56Sopenharmony_ci        assert False, 'channel not closed'
1497db96d56Sopenharmony_ci
1507db96d56Sopenharmony_ci
1517db96d56Sopenharmony_ciclass ChannelAction(namedtuple('ChannelAction', 'action end interp')):
1527db96d56Sopenharmony_ci
1537db96d56Sopenharmony_ci    def __new__(cls, action, end=None, interp=None):
1547db96d56Sopenharmony_ci        if not end:
1557db96d56Sopenharmony_ci            end = 'both'
1567db96d56Sopenharmony_ci        if not interp:
1577db96d56Sopenharmony_ci            interp = 'main'
1587db96d56Sopenharmony_ci        self = super().__new__(cls, action, end, interp)
1597db96d56Sopenharmony_ci        return self
1607db96d56Sopenharmony_ci
1617db96d56Sopenharmony_ci    def __init__(self, *args, **kwargs):
1627db96d56Sopenharmony_ci        if self.action == 'use':
1637db96d56Sopenharmony_ci            if self.end not in ('same', 'opposite', 'send', 'recv'):
1647db96d56Sopenharmony_ci                raise ValueError(self.end)
1657db96d56Sopenharmony_ci        elif self.action in ('close', 'force-close'):
1667db96d56Sopenharmony_ci            if self.end not in ('both', 'same', 'opposite', 'send', 'recv'):
1677db96d56Sopenharmony_ci                raise ValueError(self.end)
1687db96d56Sopenharmony_ci        else:
1697db96d56Sopenharmony_ci            raise ValueError(self.action)
1707db96d56Sopenharmony_ci        if self.interp not in ('main', 'same', 'other', 'extra'):
1717db96d56Sopenharmony_ci            raise ValueError(self.interp)
1727db96d56Sopenharmony_ci
1737db96d56Sopenharmony_ci    def resolve_end(self, end):
1747db96d56Sopenharmony_ci        if self.end == 'same':
1757db96d56Sopenharmony_ci            return end
1767db96d56Sopenharmony_ci        elif self.end == 'opposite':
1777db96d56Sopenharmony_ci            return 'recv' if end == 'send' else 'send'
1787db96d56Sopenharmony_ci        else:
1797db96d56Sopenharmony_ci            return self.end
1807db96d56Sopenharmony_ci
1817db96d56Sopenharmony_ci    def resolve_interp(self, interp, other, extra):
1827db96d56Sopenharmony_ci        if self.interp == 'same':
1837db96d56Sopenharmony_ci            return interp
1847db96d56Sopenharmony_ci        elif self.interp == 'other':
1857db96d56Sopenharmony_ci            if other is None:
1867db96d56Sopenharmony_ci                raise RuntimeError
1877db96d56Sopenharmony_ci            return other
1887db96d56Sopenharmony_ci        elif self.interp == 'extra':
1897db96d56Sopenharmony_ci            if extra is None:
1907db96d56Sopenharmony_ci                raise RuntimeError
1917db96d56Sopenharmony_ci            return extra
1927db96d56Sopenharmony_ci        elif self.interp == 'main':
1937db96d56Sopenharmony_ci            if interp.name == 'main':
1947db96d56Sopenharmony_ci                return interp
1957db96d56Sopenharmony_ci            elif other and other.name == 'main':
1967db96d56Sopenharmony_ci                return other
1977db96d56Sopenharmony_ci            else:
1987db96d56Sopenharmony_ci                raise RuntimeError
1997db96d56Sopenharmony_ci        # Per __init__(), there aren't any others.
2007db96d56Sopenharmony_ci
2017db96d56Sopenharmony_ci
2027db96d56Sopenharmony_ciclass ChannelState(namedtuple('ChannelState', 'pending closed')):
2037db96d56Sopenharmony_ci
2047db96d56Sopenharmony_ci    def __new__(cls, pending=0, *, closed=False):
2057db96d56Sopenharmony_ci        self = super().__new__(cls, pending, closed)
2067db96d56Sopenharmony_ci        return self
2077db96d56Sopenharmony_ci
2087db96d56Sopenharmony_ci    def incr(self):
2097db96d56Sopenharmony_ci        return type(self)(self.pending + 1, closed=self.closed)
2107db96d56Sopenharmony_ci
2117db96d56Sopenharmony_ci    def decr(self):
2127db96d56Sopenharmony_ci        return type(self)(self.pending - 1, closed=self.closed)
2137db96d56Sopenharmony_ci
2147db96d56Sopenharmony_ci    def close(self, *, force=True):
2157db96d56Sopenharmony_ci        if self.closed:
2167db96d56Sopenharmony_ci            if not force or self.pending == 0:
2177db96d56Sopenharmony_ci                return self
2187db96d56Sopenharmony_ci        return type(self)(0 if force else self.pending, closed=True)
2197db96d56Sopenharmony_ci
2207db96d56Sopenharmony_ci
2217db96d56Sopenharmony_cidef run_action(cid, action, end, state, *, hideclosed=True):
2227db96d56Sopenharmony_ci    if state.closed:
2237db96d56Sopenharmony_ci        if action == 'use' and end == 'recv' and state.pending:
2247db96d56Sopenharmony_ci            expectfail = False
2257db96d56Sopenharmony_ci        else:
2267db96d56Sopenharmony_ci            expectfail = True
2277db96d56Sopenharmony_ci    else:
2287db96d56Sopenharmony_ci        expectfail = False
2297db96d56Sopenharmony_ci
2307db96d56Sopenharmony_ci    try:
2317db96d56Sopenharmony_ci        result = _run_action(cid, action, end, state)
2327db96d56Sopenharmony_ci    except interpreters.ChannelClosedError:
2337db96d56Sopenharmony_ci        if not hideclosed and not expectfail:
2347db96d56Sopenharmony_ci            raise
2357db96d56Sopenharmony_ci        result = state.close()
2367db96d56Sopenharmony_ci    else:
2377db96d56Sopenharmony_ci        if expectfail:
2387db96d56Sopenharmony_ci            raise ...  # XXX
2397db96d56Sopenharmony_ci    return result
2407db96d56Sopenharmony_ci
2417db96d56Sopenharmony_ci
2427db96d56Sopenharmony_cidef _run_action(cid, action, end, state):
2437db96d56Sopenharmony_ci    if action == 'use':
2447db96d56Sopenharmony_ci        if end == 'send':
2457db96d56Sopenharmony_ci            interpreters.channel_send(cid, b'spam')
2467db96d56Sopenharmony_ci            return state.incr()
2477db96d56Sopenharmony_ci        elif end == 'recv':
2487db96d56Sopenharmony_ci            if not state.pending:
2497db96d56Sopenharmony_ci                try:
2507db96d56Sopenharmony_ci                    interpreters.channel_recv(cid)
2517db96d56Sopenharmony_ci                except interpreters.ChannelEmptyError:
2527db96d56Sopenharmony_ci                    return state
2537db96d56Sopenharmony_ci                else:
2547db96d56Sopenharmony_ci                    raise Exception('expected ChannelEmptyError')
2557db96d56Sopenharmony_ci            else:
2567db96d56Sopenharmony_ci                interpreters.channel_recv(cid)
2577db96d56Sopenharmony_ci                return state.decr()
2587db96d56Sopenharmony_ci        else:
2597db96d56Sopenharmony_ci            raise ValueError(end)
2607db96d56Sopenharmony_ci    elif action == 'close':
2617db96d56Sopenharmony_ci        kwargs = {}
2627db96d56Sopenharmony_ci        if end in ('recv', 'send'):
2637db96d56Sopenharmony_ci            kwargs[end] = True
2647db96d56Sopenharmony_ci        interpreters.channel_close(cid, **kwargs)
2657db96d56Sopenharmony_ci        return state.close()
2667db96d56Sopenharmony_ci    elif action == 'force-close':
2677db96d56Sopenharmony_ci        kwargs = {
2687db96d56Sopenharmony_ci            'force': True,
2697db96d56Sopenharmony_ci            }
2707db96d56Sopenharmony_ci        if end in ('recv', 'send'):
2717db96d56Sopenharmony_ci            kwargs[end] = True
2727db96d56Sopenharmony_ci        interpreters.channel_close(cid, **kwargs)
2737db96d56Sopenharmony_ci        return state.close(force=True)
2747db96d56Sopenharmony_ci    else:
2757db96d56Sopenharmony_ci        raise ValueError(action)
2767db96d56Sopenharmony_ci
2777db96d56Sopenharmony_ci
2787db96d56Sopenharmony_cidef clean_up_interpreters():
2797db96d56Sopenharmony_ci    for id in interpreters.list_all():
2807db96d56Sopenharmony_ci        if id == 0:  # main
2817db96d56Sopenharmony_ci            continue
2827db96d56Sopenharmony_ci        try:
2837db96d56Sopenharmony_ci            interpreters.destroy(id)
2847db96d56Sopenharmony_ci        except RuntimeError:
2857db96d56Sopenharmony_ci            pass  # already destroyed
2867db96d56Sopenharmony_ci
2877db96d56Sopenharmony_ci
2887db96d56Sopenharmony_cidef clean_up_channels():
2897db96d56Sopenharmony_ci    for cid in interpreters.channel_list_all():
2907db96d56Sopenharmony_ci        try:
2917db96d56Sopenharmony_ci            interpreters.channel_destroy(cid)
2927db96d56Sopenharmony_ci        except interpreters.ChannelNotFoundError:
2937db96d56Sopenharmony_ci            pass  # already destroyed
2947db96d56Sopenharmony_ci
2957db96d56Sopenharmony_ci
2967db96d56Sopenharmony_ciclass TestBase(unittest.TestCase):
2977db96d56Sopenharmony_ci
2987db96d56Sopenharmony_ci    def tearDown(self):
2997db96d56Sopenharmony_ci        clean_up_interpreters()
3007db96d56Sopenharmony_ci        clean_up_channels()
3017db96d56Sopenharmony_ci
3027db96d56Sopenharmony_ci
3037db96d56Sopenharmony_ci##################################
3047db96d56Sopenharmony_ci# misc. tests
3057db96d56Sopenharmony_ci
3067db96d56Sopenharmony_ciclass IsShareableTests(unittest.TestCase):
3077db96d56Sopenharmony_ci
3087db96d56Sopenharmony_ci    def test_default_shareables(self):
3097db96d56Sopenharmony_ci        shareables = [
3107db96d56Sopenharmony_ci                # singletons
3117db96d56Sopenharmony_ci                None,
3127db96d56Sopenharmony_ci                # builtin objects
3137db96d56Sopenharmony_ci                b'spam',
3147db96d56Sopenharmony_ci                'spam',
3157db96d56Sopenharmony_ci                10,
3167db96d56Sopenharmony_ci                -10,
3177db96d56Sopenharmony_ci                ]
3187db96d56Sopenharmony_ci        for obj in shareables:
3197db96d56Sopenharmony_ci            with self.subTest(obj):
3207db96d56Sopenharmony_ci                self.assertTrue(
3217db96d56Sopenharmony_ci                    interpreters.is_shareable(obj))
3227db96d56Sopenharmony_ci
3237db96d56Sopenharmony_ci    def test_not_shareable(self):
3247db96d56Sopenharmony_ci        class Cheese:
3257db96d56Sopenharmony_ci            def __init__(self, name):
3267db96d56Sopenharmony_ci                self.name = name
3277db96d56Sopenharmony_ci            def __str__(self):
3287db96d56Sopenharmony_ci                return self.name
3297db96d56Sopenharmony_ci
3307db96d56Sopenharmony_ci        class SubBytes(bytes):
3317db96d56Sopenharmony_ci            """A subclass of a shareable type."""
3327db96d56Sopenharmony_ci
3337db96d56Sopenharmony_ci        not_shareables = [
3347db96d56Sopenharmony_ci                # singletons
3357db96d56Sopenharmony_ci                True,
3367db96d56Sopenharmony_ci                False,
3377db96d56Sopenharmony_ci                NotImplemented,
3387db96d56Sopenharmony_ci                ...,
3397db96d56Sopenharmony_ci                # builtin types and objects
3407db96d56Sopenharmony_ci                type,
3417db96d56Sopenharmony_ci                object,
3427db96d56Sopenharmony_ci                object(),
3437db96d56Sopenharmony_ci                Exception(),
3447db96d56Sopenharmony_ci                100.0,
3457db96d56Sopenharmony_ci                # user-defined types and objects
3467db96d56Sopenharmony_ci                Cheese,
3477db96d56Sopenharmony_ci                Cheese('Wensleydale'),
3487db96d56Sopenharmony_ci                SubBytes(b'spam'),
3497db96d56Sopenharmony_ci                ]
3507db96d56Sopenharmony_ci        for obj in not_shareables:
3517db96d56Sopenharmony_ci            with self.subTest(repr(obj)):
3527db96d56Sopenharmony_ci                self.assertFalse(
3537db96d56Sopenharmony_ci                    interpreters.is_shareable(obj))
3547db96d56Sopenharmony_ci
3557db96d56Sopenharmony_ci
3567db96d56Sopenharmony_ciclass ShareableTypeTests(unittest.TestCase):
3577db96d56Sopenharmony_ci
3587db96d56Sopenharmony_ci    def setUp(self):
3597db96d56Sopenharmony_ci        super().setUp()
3607db96d56Sopenharmony_ci        self.cid = interpreters.channel_create()
3617db96d56Sopenharmony_ci
3627db96d56Sopenharmony_ci    def tearDown(self):
3637db96d56Sopenharmony_ci        interpreters.channel_destroy(self.cid)
3647db96d56Sopenharmony_ci        super().tearDown()
3657db96d56Sopenharmony_ci
3667db96d56Sopenharmony_ci    def _assert_values(self, values):
3677db96d56Sopenharmony_ci        for obj in values:
3687db96d56Sopenharmony_ci            with self.subTest(obj):
3697db96d56Sopenharmony_ci                interpreters.channel_send(self.cid, obj)
3707db96d56Sopenharmony_ci                got = interpreters.channel_recv(self.cid)
3717db96d56Sopenharmony_ci
3727db96d56Sopenharmony_ci                self.assertEqual(got, obj)
3737db96d56Sopenharmony_ci                self.assertIs(type(got), type(obj))
3747db96d56Sopenharmony_ci                # XXX Check the following in the channel tests?
3757db96d56Sopenharmony_ci                #self.assertIsNot(got, obj)
3767db96d56Sopenharmony_ci
3777db96d56Sopenharmony_ci    def test_singletons(self):
3787db96d56Sopenharmony_ci        for obj in [None]:
3797db96d56Sopenharmony_ci            with self.subTest(obj):
3807db96d56Sopenharmony_ci                interpreters.channel_send(self.cid, obj)
3817db96d56Sopenharmony_ci                got = interpreters.channel_recv(self.cid)
3827db96d56Sopenharmony_ci
3837db96d56Sopenharmony_ci                # XXX What about between interpreters?
3847db96d56Sopenharmony_ci                self.assertIs(got, obj)
3857db96d56Sopenharmony_ci
3867db96d56Sopenharmony_ci    def test_types(self):
3877db96d56Sopenharmony_ci        self._assert_values([
3887db96d56Sopenharmony_ci            b'spam',
3897db96d56Sopenharmony_ci            9999,
3907db96d56Sopenharmony_ci            self.cid,
3917db96d56Sopenharmony_ci            ])
3927db96d56Sopenharmony_ci
3937db96d56Sopenharmony_ci    def test_bytes(self):
3947db96d56Sopenharmony_ci        self._assert_values(i.to_bytes(2, 'little', signed=True)
3957db96d56Sopenharmony_ci                            for i in range(-1, 258))
3967db96d56Sopenharmony_ci
3977db96d56Sopenharmony_ci    def test_strs(self):
3987db96d56Sopenharmony_ci        self._assert_values(['hello world', '你好世界', ''])
3997db96d56Sopenharmony_ci
4007db96d56Sopenharmony_ci    def test_int(self):
4017db96d56Sopenharmony_ci        self._assert_values(itertools.chain(range(-1, 258),
4027db96d56Sopenharmony_ci                                            [sys.maxsize, -sys.maxsize - 1]))
4037db96d56Sopenharmony_ci
4047db96d56Sopenharmony_ci    def test_non_shareable_int(self):
4057db96d56Sopenharmony_ci        ints = [
4067db96d56Sopenharmony_ci            sys.maxsize + 1,
4077db96d56Sopenharmony_ci            -sys.maxsize - 2,
4087db96d56Sopenharmony_ci            2**1000,
4097db96d56Sopenharmony_ci        ]
4107db96d56Sopenharmony_ci        for i in ints:
4117db96d56Sopenharmony_ci            with self.subTest(i):
4127db96d56Sopenharmony_ci                with self.assertRaises(OverflowError):
4137db96d56Sopenharmony_ci                    interpreters.channel_send(self.cid, i)
4147db96d56Sopenharmony_ci
4157db96d56Sopenharmony_ci
4167db96d56Sopenharmony_ci##################################
4177db96d56Sopenharmony_ci# interpreter tests
4187db96d56Sopenharmony_ci
4197db96d56Sopenharmony_ciclass ListAllTests(TestBase):
4207db96d56Sopenharmony_ci
4217db96d56Sopenharmony_ci    def test_initial(self):
4227db96d56Sopenharmony_ci        main = interpreters.get_main()
4237db96d56Sopenharmony_ci        ids = interpreters.list_all()
4247db96d56Sopenharmony_ci        self.assertEqual(ids, [main])
4257db96d56Sopenharmony_ci
4267db96d56Sopenharmony_ci    def test_after_creating(self):
4277db96d56Sopenharmony_ci        main = interpreters.get_main()
4287db96d56Sopenharmony_ci        first = interpreters.create()
4297db96d56Sopenharmony_ci        second = interpreters.create()
4307db96d56Sopenharmony_ci        ids = interpreters.list_all()
4317db96d56Sopenharmony_ci        self.assertEqual(ids, [main, first, second])
4327db96d56Sopenharmony_ci
4337db96d56Sopenharmony_ci    def test_after_destroying(self):
4347db96d56Sopenharmony_ci        main = interpreters.get_main()
4357db96d56Sopenharmony_ci        first = interpreters.create()
4367db96d56Sopenharmony_ci        second = interpreters.create()
4377db96d56Sopenharmony_ci        interpreters.destroy(first)
4387db96d56Sopenharmony_ci        ids = interpreters.list_all()
4397db96d56Sopenharmony_ci        self.assertEqual(ids, [main, second])
4407db96d56Sopenharmony_ci
4417db96d56Sopenharmony_ci
4427db96d56Sopenharmony_ciclass GetCurrentTests(TestBase):
4437db96d56Sopenharmony_ci
4447db96d56Sopenharmony_ci    def test_main(self):
4457db96d56Sopenharmony_ci        main = interpreters.get_main()
4467db96d56Sopenharmony_ci        cur = interpreters.get_current()
4477db96d56Sopenharmony_ci        self.assertEqual(cur, main)
4487db96d56Sopenharmony_ci        self.assertIsInstance(cur, interpreters.InterpreterID)
4497db96d56Sopenharmony_ci
4507db96d56Sopenharmony_ci    def test_subinterpreter(self):
4517db96d56Sopenharmony_ci        main = interpreters.get_main()
4527db96d56Sopenharmony_ci        interp = interpreters.create()
4537db96d56Sopenharmony_ci        out = _run_output(interp, dedent("""
4547db96d56Sopenharmony_ci            import _xxsubinterpreters as _interpreters
4557db96d56Sopenharmony_ci            cur = _interpreters.get_current()
4567db96d56Sopenharmony_ci            print(cur)
4577db96d56Sopenharmony_ci            assert isinstance(cur, _interpreters.InterpreterID)
4587db96d56Sopenharmony_ci            """))
4597db96d56Sopenharmony_ci        cur = int(out.strip())
4607db96d56Sopenharmony_ci        _, expected = interpreters.list_all()
4617db96d56Sopenharmony_ci        self.assertEqual(cur, expected)
4627db96d56Sopenharmony_ci        self.assertNotEqual(cur, main)
4637db96d56Sopenharmony_ci
4647db96d56Sopenharmony_ci
4657db96d56Sopenharmony_ciclass GetMainTests(TestBase):
4667db96d56Sopenharmony_ci
4677db96d56Sopenharmony_ci    def test_from_main(self):
4687db96d56Sopenharmony_ci        [expected] = interpreters.list_all()
4697db96d56Sopenharmony_ci        main = interpreters.get_main()
4707db96d56Sopenharmony_ci        self.assertEqual(main, expected)
4717db96d56Sopenharmony_ci        self.assertIsInstance(main, interpreters.InterpreterID)
4727db96d56Sopenharmony_ci
4737db96d56Sopenharmony_ci    def test_from_subinterpreter(self):
4747db96d56Sopenharmony_ci        [expected] = interpreters.list_all()
4757db96d56Sopenharmony_ci        interp = interpreters.create()
4767db96d56Sopenharmony_ci        out = _run_output(interp, dedent("""
4777db96d56Sopenharmony_ci            import _xxsubinterpreters as _interpreters
4787db96d56Sopenharmony_ci            main = _interpreters.get_main()
4797db96d56Sopenharmony_ci            print(main)
4807db96d56Sopenharmony_ci            assert isinstance(main, _interpreters.InterpreterID)
4817db96d56Sopenharmony_ci            """))
4827db96d56Sopenharmony_ci        main = int(out.strip())
4837db96d56Sopenharmony_ci        self.assertEqual(main, expected)
4847db96d56Sopenharmony_ci
4857db96d56Sopenharmony_ci
4867db96d56Sopenharmony_ciclass IsRunningTests(TestBase):
4877db96d56Sopenharmony_ci
4887db96d56Sopenharmony_ci    def test_main(self):
4897db96d56Sopenharmony_ci        main = interpreters.get_main()
4907db96d56Sopenharmony_ci        self.assertTrue(interpreters.is_running(main))
4917db96d56Sopenharmony_ci
4927db96d56Sopenharmony_ci    @unittest.skip('Fails on FreeBSD')
4937db96d56Sopenharmony_ci    def test_subinterpreter(self):
4947db96d56Sopenharmony_ci        interp = interpreters.create()
4957db96d56Sopenharmony_ci        self.assertFalse(interpreters.is_running(interp))
4967db96d56Sopenharmony_ci
4977db96d56Sopenharmony_ci        with _running(interp):
4987db96d56Sopenharmony_ci            self.assertTrue(interpreters.is_running(interp))
4997db96d56Sopenharmony_ci        self.assertFalse(interpreters.is_running(interp))
5007db96d56Sopenharmony_ci
5017db96d56Sopenharmony_ci    def test_from_subinterpreter(self):
5027db96d56Sopenharmony_ci        interp = interpreters.create()
5037db96d56Sopenharmony_ci        out = _run_output(interp, dedent(f"""
5047db96d56Sopenharmony_ci            import _xxsubinterpreters as _interpreters
5057db96d56Sopenharmony_ci            if _interpreters.is_running({interp}):
5067db96d56Sopenharmony_ci                print(True)
5077db96d56Sopenharmony_ci            else:
5087db96d56Sopenharmony_ci                print(False)
5097db96d56Sopenharmony_ci            """))
5107db96d56Sopenharmony_ci        self.assertEqual(out.strip(), 'True')
5117db96d56Sopenharmony_ci
5127db96d56Sopenharmony_ci    def test_already_destroyed(self):
5137db96d56Sopenharmony_ci        interp = interpreters.create()
5147db96d56Sopenharmony_ci        interpreters.destroy(interp)
5157db96d56Sopenharmony_ci        with self.assertRaises(RuntimeError):
5167db96d56Sopenharmony_ci            interpreters.is_running(interp)
5177db96d56Sopenharmony_ci
5187db96d56Sopenharmony_ci    def test_does_not_exist(self):
5197db96d56Sopenharmony_ci        with self.assertRaises(RuntimeError):
5207db96d56Sopenharmony_ci            interpreters.is_running(1_000_000)
5217db96d56Sopenharmony_ci
5227db96d56Sopenharmony_ci    def test_bad_id(self):
5237db96d56Sopenharmony_ci        with self.assertRaises(ValueError):
5247db96d56Sopenharmony_ci            interpreters.is_running(-1)
5257db96d56Sopenharmony_ci
5267db96d56Sopenharmony_ci
5277db96d56Sopenharmony_ciclass InterpreterIDTests(TestBase):
5287db96d56Sopenharmony_ci
5297db96d56Sopenharmony_ci    def test_with_int(self):
5307db96d56Sopenharmony_ci        id = interpreters.InterpreterID(10, force=True)
5317db96d56Sopenharmony_ci
5327db96d56Sopenharmony_ci        self.assertEqual(int(id), 10)
5337db96d56Sopenharmony_ci
5347db96d56Sopenharmony_ci    def test_coerce_id(self):
5357db96d56Sopenharmony_ci        class Int(str):
5367db96d56Sopenharmony_ci            def __index__(self):
5377db96d56Sopenharmony_ci                return 10
5387db96d56Sopenharmony_ci
5397db96d56Sopenharmony_ci        id = interpreters.InterpreterID(Int(), force=True)
5407db96d56Sopenharmony_ci        self.assertEqual(int(id), 10)
5417db96d56Sopenharmony_ci
5427db96d56Sopenharmony_ci    def test_bad_id(self):
5437db96d56Sopenharmony_ci        self.assertRaises(TypeError, interpreters.InterpreterID, object())
5447db96d56Sopenharmony_ci        self.assertRaises(TypeError, interpreters.InterpreterID, 10.0)
5457db96d56Sopenharmony_ci        self.assertRaises(TypeError, interpreters.InterpreterID, '10')
5467db96d56Sopenharmony_ci        self.assertRaises(TypeError, interpreters.InterpreterID, b'10')
5477db96d56Sopenharmony_ci        self.assertRaises(ValueError, interpreters.InterpreterID, -1)
5487db96d56Sopenharmony_ci        self.assertRaises(OverflowError, interpreters.InterpreterID, 2**64)
5497db96d56Sopenharmony_ci
5507db96d56Sopenharmony_ci    def test_does_not_exist(self):
5517db96d56Sopenharmony_ci        id = interpreters.channel_create()
5527db96d56Sopenharmony_ci        with self.assertRaises(RuntimeError):
5537db96d56Sopenharmony_ci            interpreters.InterpreterID(int(id) + 1)  # unforced
5547db96d56Sopenharmony_ci
5557db96d56Sopenharmony_ci    def test_str(self):
5567db96d56Sopenharmony_ci        id = interpreters.InterpreterID(10, force=True)
5577db96d56Sopenharmony_ci        self.assertEqual(str(id), '10')
5587db96d56Sopenharmony_ci
5597db96d56Sopenharmony_ci    def test_repr(self):
5607db96d56Sopenharmony_ci        id = interpreters.InterpreterID(10, force=True)
5617db96d56Sopenharmony_ci        self.assertEqual(repr(id), 'InterpreterID(10)')
5627db96d56Sopenharmony_ci
5637db96d56Sopenharmony_ci    def test_equality(self):
5647db96d56Sopenharmony_ci        id1 = interpreters.create()
5657db96d56Sopenharmony_ci        id2 = interpreters.InterpreterID(int(id1))
5667db96d56Sopenharmony_ci        id3 = interpreters.create()
5677db96d56Sopenharmony_ci
5687db96d56Sopenharmony_ci        self.assertTrue(id1 == id1)
5697db96d56Sopenharmony_ci        self.assertTrue(id1 == id2)
5707db96d56Sopenharmony_ci        self.assertTrue(id1 == int(id1))
5717db96d56Sopenharmony_ci        self.assertTrue(int(id1) == id1)
5727db96d56Sopenharmony_ci        self.assertTrue(id1 == float(int(id1)))
5737db96d56Sopenharmony_ci        self.assertTrue(float(int(id1)) == id1)
5747db96d56Sopenharmony_ci        self.assertFalse(id1 == float(int(id1)) + 0.1)
5757db96d56Sopenharmony_ci        self.assertFalse(id1 == str(int(id1)))
5767db96d56Sopenharmony_ci        self.assertFalse(id1 == 2**1000)
5777db96d56Sopenharmony_ci        self.assertFalse(id1 == float('inf'))
5787db96d56Sopenharmony_ci        self.assertFalse(id1 == 'spam')
5797db96d56Sopenharmony_ci        self.assertFalse(id1 == id3)
5807db96d56Sopenharmony_ci
5817db96d56Sopenharmony_ci        self.assertFalse(id1 != id1)
5827db96d56Sopenharmony_ci        self.assertFalse(id1 != id2)
5837db96d56Sopenharmony_ci        self.assertTrue(id1 != id3)
5847db96d56Sopenharmony_ci
5857db96d56Sopenharmony_ci
5867db96d56Sopenharmony_ciclass CreateTests(TestBase):
5877db96d56Sopenharmony_ci
5887db96d56Sopenharmony_ci    def test_in_main(self):
5897db96d56Sopenharmony_ci        id = interpreters.create()
5907db96d56Sopenharmony_ci        self.assertIsInstance(id, interpreters.InterpreterID)
5917db96d56Sopenharmony_ci
5927db96d56Sopenharmony_ci        self.assertIn(id, interpreters.list_all())
5937db96d56Sopenharmony_ci
5947db96d56Sopenharmony_ci    @unittest.skip('enable this test when working on pystate.c')
5957db96d56Sopenharmony_ci    def test_unique_id(self):
5967db96d56Sopenharmony_ci        seen = set()
5977db96d56Sopenharmony_ci        for _ in range(100):
5987db96d56Sopenharmony_ci            id = interpreters.create()
5997db96d56Sopenharmony_ci            interpreters.destroy(id)
6007db96d56Sopenharmony_ci            seen.add(id)
6017db96d56Sopenharmony_ci
6027db96d56Sopenharmony_ci        self.assertEqual(len(seen), 100)
6037db96d56Sopenharmony_ci
6047db96d56Sopenharmony_ci    def test_in_thread(self):
6057db96d56Sopenharmony_ci        lock = threading.Lock()
6067db96d56Sopenharmony_ci        id = None
6077db96d56Sopenharmony_ci        def f():
6087db96d56Sopenharmony_ci            nonlocal id
6097db96d56Sopenharmony_ci            id = interpreters.create()
6107db96d56Sopenharmony_ci            lock.acquire()
6117db96d56Sopenharmony_ci            lock.release()
6127db96d56Sopenharmony_ci
6137db96d56Sopenharmony_ci        t = threading.Thread(target=f)
6147db96d56Sopenharmony_ci        with lock:
6157db96d56Sopenharmony_ci            t.start()
6167db96d56Sopenharmony_ci        t.join()
6177db96d56Sopenharmony_ci        self.assertIn(id, interpreters.list_all())
6187db96d56Sopenharmony_ci
6197db96d56Sopenharmony_ci    def test_in_subinterpreter(self):
6207db96d56Sopenharmony_ci        main, = interpreters.list_all()
6217db96d56Sopenharmony_ci        id1 = interpreters.create()
6227db96d56Sopenharmony_ci        out = _run_output(id1, dedent("""
6237db96d56Sopenharmony_ci            import _xxsubinterpreters as _interpreters
6247db96d56Sopenharmony_ci            id = _interpreters.create()
6257db96d56Sopenharmony_ci            print(id)
6267db96d56Sopenharmony_ci            assert isinstance(id, _interpreters.InterpreterID)
6277db96d56Sopenharmony_ci            """))
6287db96d56Sopenharmony_ci        id2 = int(out.strip())
6297db96d56Sopenharmony_ci
6307db96d56Sopenharmony_ci        self.assertEqual(set(interpreters.list_all()), {main, id1, id2})
6317db96d56Sopenharmony_ci
6327db96d56Sopenharmony_ci    def test_in_threaded_subinterpreter(self):
6337db96d56Sopenharmony_ci        main, = interpreters.list_all()
6347db96d56Sopenharmony_ci        id1 = interpreters.create()
6357db96d56Sopenharmony_ci        id2 = None
6367db96d56Sopenharmony_ci        def f():
6377db96d56Sopenharmony_ci            nonlocal id2
6387db96d56Sopenharmony_ci            out = _run_output(id1, dedent("""
6397db96d56Sopenharmony_ci                import _xxsubinterpreters as _interpreters
6407db96d56Sopenharmony_ci                id = _interpreters.create()
6417db96d56Sopenharmony_ci                print(id)
6427db96d56Sopenharmony_ci                """))
6437db96d56Sopenharmony_ci            id2 = int(out.strip())
6447db96d56Sopenharmony_ci
6457db96d56Sopenharmony_ci        t = threading.Thread(target=f)
6467db96d56Sopenharmony_ci        t.start()
6477db96d56Sopenharmony_ci        t.join()
6487db96d56Sopenharmony_ci
6497db96d56Sopenharmony_ci        self.assertEqual(set(interpreters.list_all()), {main, id1, id2})
6507db96d56Sopenharmony_ci
6517db96d56Sopenharmony_ci    def test_after_destroy_all(self):
6527db96d56Sopenharmony_ci        before = set(interpreters.list_all())
6537db96d56Sopenharmony_ci        # Create 3 subinterpreters.
6547db96d56Sopenharmony_ci        ids = []
6557db96d56Sopenharmony_ci        for _ in range(3):
6567db96d56Sopenharmony_ci            id = interpreters.create()
6577db96d56Sopenharmony_ci            ids.append(id)
6587db96d56Sopenharmony_ci        # Now destroy them.
6597db96d56Sopenharmony_ci        for id in ids:
6607db96d56Sopenharmony_ci            interpreters.destroy(id)
6617db96d56Sopenharmony_ci        # Finally, create another.
6627db96d56Sopenharmony_ci        id = interpreters.create()
6637db96d56Sopenharmony_ci        self.assertEqual(set(interpreters.list_all()), before | {id})
6647db96d56Sopenharmony_ci
6657db96d56Sopenharmony_ci    def test_after_destroy_some(self):
6667db96d56Sopenharmony_ci        before = set(interpreters.list_all())
6677db96d56Sopenharmony_ci        # Create 3 subinterpreters.
6687db96d56Sopenharmony_ci        id1 = interpreters.create()
6697db96d56Sopenharmony_ci        id2 = interpreters.create()
6707db96d56Sopenharmony_ci        id3 = interpreters.create()
6717db96d56Sopenharmony_ci        # Now destroy 2 of them.
6727db96d56Sopenharmony_ci        interpreters.destroy(id1)
6737db96d56Sopenharmony_ci        interpreters.destroy(id3)
6747db96d56Sopenharmony_ci        # Finally, create another.
6757db96d56Sopenharmony_ci        id = interpreters.create()
6767db96d56Sopenharmony_ci        self.assertEqual(set(interpreters.list_all()), before | {id, id2})
6777db96d56Sopenharmony_ci
6787db96d56Sopenharmony_ci
6797db96d56Sopenharmony_ciclass DestroyTests(TestBase):
6807db96d56Sopenharmony_ci
6817db96d56Sopenharmony_ci    def test_one(self):
6827db96d56Sopenharmony_ci        id1 = interpreters.create()
6837db96d56Sopenharmony_ci        id2 = interpreters.create()
6847db96d56Sopenharmony_ci        id3 = interpreters.create()
6857db96d56Sopenharmony_ci        self.assertIn(id2, interpreters.list_all())
6867db96d56Sopenharmony_ci        interpreters.destroy(id2)
6877db96d56Sopenharmony_ci        self.assertNotIn(id2, interpreters.list_all())
6887db96d56Sopenharmony_ci        self.assertIn(id1, interpreters.list_all())
6897db96d56Sopenharmony_ci        self.assertIn(id3, interpreters.list_all())
6907db96d56Sopenharmony_ci
6917db96d56Sopenharmony_ci    def test_all(self):
6927db96d56Sopenharmony_ci        before = set(interpreters.list_all())
6937db96d56Sopenharmony_ci        ids = set()
6947db96d56Sopenharmony_ci        for _ in range(3):
6957db96d56Sopenharmony_ci            id = interpreters.create()
6967db96d56Sopenharmony_ci            ids.add(id)
6977db96d56Sopenharmony_ci        self.assertEqual(set(interpreters.list_all()), before | ids)
6987db96d56Sopenharmony_ci        for id in ids:
6997db96d56Sopenharmony_ci            interpreters.destroy(id)
7007db96d56Sopenharmony_ci        self.assertEqual(set(interpreters.list_all()), before)
7017db96d56Sopenharmony_ci
7027db96d56Sopenharmony_ci    def test_main(self):
7037db96d56Sopenharmony_ci        main, = interpreters.list_all()
7047db96d56Sopenharmony_ci        with self.assertRaises(RuntimeError):
7057db96d56Sopenharmony_ci            interpreters.destroy(main)
7067db96d56Sopenharmony_ci
7077db96d56Sopenharmony_ci        def f():
7087db96d56Sopenharmony_ci            with self.assertRaises(RuntimeError):
7097db96d56Sopenharmony_ci                interpreters.destroy(main)
7107db96d56Sopenharmony_ci
7117db96d56Sopenharmony_ci        t = threading.Thread(target=f)
7127db96d56Sopenharmony_ci        t.start()
7137db96d56Sopenharmony_ci        t.join()
7147db96d56Sopenharmony_ci
7157db96d56Sopenharmony_ci    def test_already_destroyed(self):
7167db96d56Sopenharmony_ci        id = interpreters.create()
7177db96d56Sopenharmony_ci        interpreters.destroy(id)
7187db96d56Sopenharmony_ci        with self.assertRaises(RuntimeError):
7197db96d56Sopenharmony_ci            interpreters.destroy(id)
7207db96d56Sopenharmony_ci
7217db96d56Sopenharmony_ci    def test_does_not_exist(self):
7227db96d56Sopenharmony_ci        with self.assertRaises(RuntimeError):
7237db96d56Sopenharmony_ci            interpreters.destroy(1_000_000)
7247db96d56Sopenharmony_ci
7257db96d56Sopenharmony_ci    def test_bad_id(self):
7267db96d56Sopenharmony_ci        with self.assertRaises(ValueError):
7277db96d56Sopenharmony_ci            interpreters.destroy(-1)
7287db96d56Sopenharmony_ci
7297db96d56Sopenharmony_ci    def test_from_current(self):
7307db96d56Sopenharmony_ci        main, = interpreters.list_all()
7317db96d56Sopenharmony_ci        id = interpreters.create()
7327db96d56Sopenharmony_ci        script = dedent(f"""
7337db96d56Sopenharmony_ci            import _xxsubinterpreters as _interpreters
7347db96d56Sopenharmony_ci            try:
7357db96d56Sopenharmony_ci                _interpreters.destroy({id})
7367db96d56Sopenharmony_ci            except RuntimeError:
7377db96d56Sopenharmony_ci                pass
7387db96d56Sopenharmony_ci            """)
7397db96d56Sopenharmony_ci
7407db96d56Sopenharmony_ci        interpreters.run_string(id, script)
7417db96d56Sopenharmony_ci        self.assertEqual(set(interpreters.list_all()), {main, id})
7427db96d56Sopenharmony_ci
7437db96d56Sopenharmony_ci    def test_from_sibling(self):
7447db96d56Sopenharmony_ci        main, = interpreters.list_all()
7457db96d56Sopenharmony_ci        id1 = interpreters.create()
7467db96d56Sopenharmony_ci        id2 = interpreters.create()
7477db96d56Sopenharmony_ci        script = dedent(f"""
7487db96d56Sopenharmony_ci            import _xxsubinterpreters as _interpreters
7497db96d56Sopenharmony_ci            _interpreters.destroy({id2})
7507db96d56Sopenharmony_ci            """)
7517db96d56Sopenharmony_ci        interpreters.run_string(id1, script)
7527db96d56Sopenharmony_ci
7537db96d56Sopenharmony_ci        self.assertEqual(set(interpreters.list_all()), {main, id1})
7547db96d56Sopenharmony_ci
7557db96d56Sopenharmony_ci    def test_from_other_thread(self):
7567db96d56Sopenharmony_ci        id = interpreters.create()
7577db96d56Sopenharmony_ci        def f():
7587db96d56Sopenharmony_ci            interpreters.destroy(id)
7597db96d56Sopenharmony_ci
7607db96d56Sopenharmony_ci        t = threading.Thread(target=f)
7617db96d56Sopenharmony_ci        t.start()
7627db96d56Sopenharmony_ci        t.join()
7637db96d56Sopenharmony_ci
7647db96d56Sopenharmony_ci    def test_still_running(self):
7657db96d56Sopenharmony_ci        main, = interpreters.list_all()
7667db96d56Sopenharmony_ci        interp = interpreters.create()
7677db96d56Sopenharmony_ci        with _running(interp):
7687db96d56Sopenharmony_ci            self.assertTrue(interpreters.is_running(interp),
7697db96d56Sopenharmony_ci                            msg=f"Interp {interp} should be running before destruction.")
7707db96d56Sopenharmony_ci
7717db96d56Sopenharmony_ci            with self.assertRaises(RuntimeError,
7727db96d56Sopenharmony_ci                                   msg=f"Should not be able to destroy interp {interp} while it's still running."):
7737db96d56Sopenharmony_ci                interpreters.destroy(interp)
7747db96d56Sopenharmony_ci            self.assertTrue(interpreters.is_running(interp))
7757db96d56Sopenharmony_ci
7767db96d56Sopenharmony_ci
7777db96d56Sopenharmony_ciclass RunStringTests(TestBase):
7787db96d56Sopenharmony_ci
7797db96d56Sopenharmony_ci    def setUp(self):
7807db96d56Sopenharmony_ci        super().setUp()
7817db96d56Sopenharmony_ci        self.id = interpreters.create()
7827db96d56Sopenharmony_ci
7837db96d56Sopenharmony_ci    def test_success(self):
7847db96d56Sopenharmony_ci        script, file = _captured_script('print("it worked!", end="")')
7857db96d56Sopenharmony_ci        with file:
7867db96d56Sopenharmony_ci            interpreters.run_string(self.id, script)
7877db96d56Sopenharmony_ci            out = file.read()
7887db96d56Sopenharmony_ci
7897db96d56Sopenharmony_ci        self.assertEqual(out, 'it worked!')
7907db96d56Sopenharmony_ci
7917db96d56Sopenharmony_ci    def test_in_thread(self):
7927db96d56Sopenharmony_ci        script, file = _captured_script('print("it worked!", end="")')
7937db96d56Sopenharmony_ci        with file:
7947db96d56Sopenharmony_ci            def f():
7957db96d56Sopenharmony_ci                interpreters.run_string(self.id, script)
7967db96d56Sopenharmony_ci
7977db96d56Sopenharmony_ci            t = threading.Thread(target=f)
7987db96d56Sopenharmony_ci            t.start()
7997db96d56Sopenharmony_ci            t.join()
8007db96d56Sopenharmony_ci            out = file.read()
8017db96d56Sopenharmony_ci
8027db96d56Sopenharmony_ci        self.assertEqual(out, 'it worked!')
8037db96d56Sopenharmony_ci
8047db96d56Sopenharmony_ci    def test_create_thread(self):
8057db96d56Sopenharmony_ci        subinterp = interpreters.create(isolated=False)
8067db96d56Sopenharmony_ci        script, file = _captured_script("""
8077db96d56Sopenharmony_ci            import threading
8087db96d56Sopenharmony_ci            def f():
8097db96d56Sopenharmony_ci                print('it worked!', end='')
8107db96d56Sopenharmony_ci
8117db96d56Sopenharmony_ci            t = threading.Thread(target=f)
8127db96d56Sopenharmony_ci            t.start()
8137db96d56Sopenharmony_ci            t.join()
8147db96d56Sopenharmony_ci            """)
8157db96d56Sopenharmony_ci        with file:
8167db96d56Sopenharmony_ci            interpreters.run_string(subinterp, script)
8177db96d56Sopenharmony_ci            out = file.read()
8187db96d56Sopenharmony_ci
8197db96d56Sopenharmony_ci        self.assertEqual(out, 'it worked!')
8207db96d56Sopenharmony_ci
8217db96d56Sopenharmony_ci    @support.requires_fork()
8227db96d56Sopenharmony_ci    def test_fork(self):
8237db96d56Sopenharmony_ci        import tempfile
8247db96d56Sopenharmony_ci        with tempfile.NamedTemporaryFile('w+', encoding="utf-8") as file:
8257db96d56Sopenharmony_ci            file.write('')
8267db96d56Sopenharmony_ci            file.flush()
8277db96d56Sopenharmony_ci
8287db96d56Sopenharmony_ci            expected = 'spam spam spam spam spam'
8297db96d56Sopenharmony_ci            script = dedent(f"""
8307db96d56Sopenharmony_ci                import os
8317db96d56Sopenharmony_ci                try:
8327db96d56Sopenharmony_ci                    os.fork()
8337db96d56Sopenharmony_ci                except RuntimeError:
8347db96d56Sopenharmony_ci                    with open('{file.name}', 'w', encoding='utf-8') as out:
8357db96d56Sopenharmony_ci                        out.write('{expected}')
8367db96d56Sopenharmony_ci                """)
8377db96d56Sopenharmony_ci            interpreters.run_string(self.id, script)
8387db96d56Sopenharmony_ci
8397db96d56Sopenharmony_ci            file.seek(0)
8407db96d56Sopenharmony_ci            content = file.read()
8417db96d56Sopenharmony_ci            self.assertEqual(content, expected)
8427db96d56Sopenharmony_ci
8437db96d56Sopenharmony_ci    def test_already_running(self):
8447db96d56Sopenharmony_ci        with _running(self.id):
8457db96d56Sopenharmony_ci            with self.assertRaises(RuntimeError):
8467db96d56Sopenharmony_ci                interpreters.run_string(self.id, 'print("spam")')
8477db96d56Sopenharmony_ci
8487db96d56Sopenharmony_ci    def test_does_not_exist(self):
8497db96d56Sopenharmony_ci        id = 0
8507db96d56Sopenharmony_ci        while id in interpreters.list_all():
8517db96d56Sopenharmony_ci            id += 1
8527db96d56Sopenharmony_ci        with self.assertRaises(RuntimeError):
8537db96d56Sopenharmony_ci            interpreters.run_string(id, 'print("spam")')
8547db96d56Sopenharmony_ci
8557db96d56Sopenharmony_ci    def test_error_id(self):
8567db96d56Sopenharmony_ci        with self.assertRaises(ValueError):
8577db96d56Sopenharmony_ci            interpreters.run_string(-1, 'print("spam")')
8587db96d56Sopenharmony_ci
8597db96d56Sopenharmony_ci    def test_bad_id(self):
8607db96d56Sopenharmony_ci        with self.assertRaises(TypeError):
8617db96d56Sopenharmony_ci            interpreters.run_string('spam', 'print("spam")')
8627db96d56Sopenharmony_ci
8637db96d56Sopenharmony_ci    def test_bad_script(self):
8647db96d56Sopenharmony_ci        with self.assertRaises(TypeError):
8657db96d56Sopenharmony_ci            interpreters.run_string(self.id, 10)
8667db96d56Sopenharmony_ci
8677db96d56Sopenharmony_ci    def test_bytes_for_script(self):
8687db96d56Sopenharmony_ci        with self.assertRaises(TypeError):
8697db96d56Sopenharmony_ci            interpreters.run_string(self.id, b'print("spam")')
8707db96d56Sopenharmony_ci
8717db96d56Sopenharmony_ci    @contextlib.contextmanager
8727db96d56Sopenharmony_ci    def assert_run_failed(self, exctype, msg=None):
8737db96d56Sopenharmony_ci        with self.assertRaises(interpreters.RunFailedError) as caught:
8747db96d56Sopenharmony_ci            yield
8757db96d56Sopenharmony_ci        if msg is None:
8767db96d56Sopenharmony_ci            self.assertEqual(str(caught.exception).split(':')[0],
8777db96d56Sopenharmony_ci                             str(exctype))
8787db96d56Sopenharmony_ci        else:
8797db96d56Sopenharmony_ci            self.assertEqual(str(caught.exception),
8807db96d56Sopenharmony_ci                             "{}: {}".format(exctype, msg))
8817db96d56Sopenharmony_ci
8827db96d56Sopenharmony_ci    def test_invalid_syntax(self):
8837db96d56Sopenharmony_ci        with self.assert_run_failed(SyntaxError):
8847db96d56Sopenharmony_ci            # missing close paren
8857db96d56Sopenharmony_ci            interpreters.run_string(self.id, 'print("spam"')
8867db96d56Sopenharmony_ci
8877db96d56Sopenharmony_ci    def test_failure(self):
8887db96d56Sopenharmony_ci        with self.assert_run_failed(Exception, 'spam'):
8897db96d56Sopenharmony_ci            interpreters.run_string(self.id, 'raise Exception("spam")')
8907db96d56Sopenharmony_ci
8917db96d56Sopenharmony_ci    def test_SystemExit(self):
8927db96d56Sopenharmony_ci        with self.assert_run_failed(SystemExit, '42'):
8937db96d56Sopenharmony_ci            interpreters.run_string(self.id, 'raise SystemExit(42)')
8947db96d56Sopenharmony_ci
8957db96d56Sopenharmony_ci    def test_sys_exit(self):
8967db96d56Sopenharmony_ci        with self.assert_run_failed(SystemExit):
8977db96d56Sopenharmony_ci            interpreters.run_string(self.id, dedent("""
8987db96d56Sopenharmony_ci                import sys
8997db96d56Sopenharmony_ci                sys.exit()
9007db96d56Sopenharmony_ci                """))
9017db96d56Sopenharmony_ci
9027db96d56Sopenharmony_ci        with self.assert_run_failed(SystemExit, '42'):
9037db96d56Sopenharmony_ci            interpreters.run_string(self.id, dedent("""
9047db96d56Sopenharmony_ci                import sys
9057db96d56Sopenharmony_ci                sys.exit(42)
9067db96d56Sopenharmony_ci                """))
9077db96d56Sopenharmony_ci
9087db96d56Sopenharmony_ci    def test_with_shared(self):
9097db96d56Sopenharmony_ci        r, w = os.pipe()
9107db96d56Sopenharmony_ci
9117db96d56Sopenharmony_ci        shared = {
9127db96d56Sopenharmony_ci                'spam': b'ham',
9137db96d56Sopenharmony_ci                'eggs': b'-1',
9147db96d56Sopenharmony_ci                'cheddar': None,
9157db96d56Sopenharmony_ci                }
9167db96d56Sopenharmony_ci        script = dedent(f"""
9177db96d56Sopenharmony_ci            eggs = int(eggs)
9187db96d56Sopenharmony_ci            spam = 42
9197db96d56Sopenharmony_ci            result = spam + eggs
9207db96d56Sopenharmony_ci
9217db96d56Sopenharmony_ci            ns = dict(vars())
9227db96d56Sopenharmony_ci            del ns['__builtins__']
9237db96d56Sopenharmony_ci            import pickle
9247db96d56Sopenharmony_ci            with open({w}, 'wb') as chan:
9257db96d56Sopenharmony_ci                pickle.dump(ns, chan)
9267db96d56Sopenharmony_ci            """)
9277db96d56Sopenharmony_ci        interpreters.run_string(self.id, script, shared)
9287db96d56Sopenharmony_ci        with open(r, 'rb') as chan:
9297db96d56Sopenharmony_ci            ns = pickle.load(chan)
9307db96d56Sopenharmony_ci
9317db96d56Sopenharmony_ci        self.assertEqual(ns['spam'], 42)
9327db96d56Sopenharmony_ci        self.assertEqual(ns['eggs'], -1)
9337db96d56Sopenharmony_ci        self.assertEqual(ns['result'], 41)
9347db96d56Sopenharmony_ci        self.assertIsNone(ns['cheddar'])
9357db96d56Sopenharmony_ci
9367db96d56Sopenharmony_ci    def test_shared_overwrites(self):
9377db96d56Sopenharmony_ci        interpreters.run_string(self.id, dedent("""
9387db96d56Sopenharmony_ci            spam = 'eggs'
9397db96d56Sopenharmony_ci            ns1 = dict(vars())
9407db96d56Sopenharmony_ci            del ns1['__builtins__']
9417db96d56Sopenharmony_ci            """))
9427db96d56Sopenharmony_ci
9437db96d56Sopenharmony_ci        shared = {'spam': b'ham'}
9447db96d56Sopenharmony_ci        script = dedent(f"""
9457db96d56Sopenharmony_ci            ns2 = dict(vars())
9467db96d56Sopenharmony_ci            del ns2['__builtins__']
9477db96d56Sopenharmony_ci        """)
9487db96d56Sopenharmony_ci        interpreters.run_string(self.id, script, shared)
9497db96d56Sopenharmony_ci
9507db96d56Sopenharmony_ci        r, w = os.pipe()
9517db96d56Sopenharmony_ci        script = dedent(f"""
9527db96d56Sopenharmony_ci            ns = dict(vars())
9537db96d56Sopenharmony_ci            del ns['__builtins__']
9547db96d56Sopenharmony_ci            import pickle
9557db96d56Sopenharmony_ci            with open({w}, 'wb') as chan:
9567db96d56Sopenharmony_ci                pickle.dump(ns, chan)
9577db96d56Sopenharmony_ci            """)
9587db96d56Sopenharmony_ci        interpreters.run_string(self.id, script)
9597db96d56Sopenharmony_ci        with open(r, 'rb') as chan:
9607db96d56Sopenharmony_ci            ns = pickle.load(chan)
9617db96d56Sopenharmony_ci
9627db96d56Sopenharmony_ci        self.assertEqual(ns['ns1']['spam'], 'eggs')
9637db96d56Sopenharmony_ci        self.assertEqual(ns['ns2']['spam'], b'ham')
9647db96d56Sopenharmony_ci        self.assertEqual(ns['spam'], b'ham')
9657db96d56Sopenharmony_ci
9667db96d56Sopenharmony_ci    def test_shared_overwrites_default_vars(self):
9677db96d56Sopenharmony_ci        r, w = os.pipe()
9687db96d56Sopenharmony_ci
9697db96d56Sopenharmony_ci        shared = {'__name__': b'not __main__'}
9707db96d56Sopenharmony_ci        script = dedent(f"""
9717db96d56Sopenharmony_ci            spam = 42
9727db96d56Sopenharmony_ci
9737db96d56Sopenharmony_ci            ns = dict(vars())
9747db96d56Sopenharmony_ci            del ns['__builtins__']
9757db96d56Sopenharmony_ci            import pickle
9767db96d56Sopenharmony_ci            with open({w}, 'wb') as chan:
9777db96d56Sopenharmony_ci                pickle.dump(ns, chan)
9787db96d56Sopenharmony_ci            """)
9797db96d56Sopenharmony_ci        interpreters.run_string(self.id, script, shared)
9807db96d56Sopenharmony_ci        with open(r, 'rb') as chan:
9817db96d56Sopenharmony_ci            ns = pickle.load(chan)
9827db96d56Sopenharmony_ci
9837db96d56Sopenharmony_ci        self.assertEqual(ns['__name__'], b'not __main__')
9847db96d56Sopenharmony_ci
9857db96d56Sopenharmony_ci    def test_main_reused(self):
9867db96d56Sopenharmony_ci        r, w = os.pipe()
9877db96d56Sopenharmony_ci        interpreters.run_string(self.id, dedent(f"""
9887db96d56Sopenharmony_ci            spam = True
9897db96d56Sopenharmony_ci
9907db96d56Sopenharmony_ci            ns = dict(vars())
9917db96d56Sopenharmony_ci            del ns['__builtins__']
9927db96d56Sopenharmony_ci            import pickle
9937db96d56Sopenharmony_ci            with open({w}, 'wb') as chan:
9947db96d56Sopenharmony_ci                pickle.dump(ns, chan)
9957db96d56Sopenharmony_ci            del ns, pickle, chan
9967db96d56Sopenharmony_ci            """))
9977db96d56Sopenharmony_ci        with open(r, 'rb') as chan:
9987db96d56Sopenharmony_ci            ns1 = pickle.load(chan)
9997db96d56Sopenharmony_ci
10007db96d56Sopenharmony_ci        r, w = os.pipe()
10017db96d56Sopenharmony_ci        interpreters.run_string(self.id, dedent(f"""
10027db96d56Sopenharmony_ci            eggs = False
10037db96d56Sopenharmony_ci
10047db96d56Sopenharmony_ci            ns = dict(vars())
10057db96d56Sopenharmony_ci            del ns['__builtins__']
10067db96d56Sopenharmony_ci            import pickle
10077db96d56Sopenharmony_ci            with open({w}, 'wb') as chan:
10087db96d56Sopenharmony_ci                pickle.dump(ns, chan)
10097db96d56Sopenharmony_ci            """))
10107db96d56Sopenharmony_ci        with open(r, 'rb') as chan:
10117db96d56Sopenharmony_ci            ns2 = pickle.load(chan)
10127db96d56Sopenharmony_ci
10137db96d56Sopenharmony_ci        self.assertIn('spam', ns1)
10147db96d56Sopenharmony_ci        self.assertNotIn('eggs', ns1)
10157db96d56Sopenharmony_ci        self.assertIn('eggs', ns2)
10167db96d56Sopenharmony_ci        self.assertIn('spam', ns2)
10177db96d56Sopenharmony_ci
10187db96d56Sopenharmony_ci    def test_execution_namespace_is_main(self):
10197db96d56Sopenharmony_ci        r, w = os.pipe()
10207db96d56Sopenharmony_ci
10217db96d56Sopenharmony_ci        script = dedent(f"""
10227db96d56Sopenharmony_ci            spam = 42
10237db96d56Sopenharmony_ci
10247db96d56Sopenharmony_ci            ns = dict(vars())
10257db96d56Sopenharmony_ci            ns['__builtins__'] = str(ns['__builtins__'])
10267db96d56Sopenharmony_ci            import pickle
10277db96d56Sopenharmony_ci            with open({w}, 'wb') as chan:
10287db96d56Sopenharmony_ci                pickle.dump(ns, chan)
10297db96d56Sopenharmony_ci            """)
10307db96d56Sopenharmony_ci        interpreters.run_string(self.id, script)
10317db96d56Sopenharmony_ci        with open(r, 'rb') as chan:
10327db96d56Sopenharmony_ci            ns = pickle.load(chan)
10337db96d56Sopenharmony_ci
10347db96d56Sopenharmony_ci        ns.pop('__builtins__')
10357db96d56Sopenharmony_ci        ns.pop('__loader__')
10367db96d56Sopenharmony_ci        self.assertEqual(ns, {
10377db96d56Sopenharmony_ci            '__name__': '__main__',
10387db96d56Sopenharmony_ci            '__annotations__': {},
10397db96d56Sopenharmony_ci            '__doc__': None,
10407db96d56Sopenharmony_ci            '__package__': None,
10417db96d56Sopenharmony_ci            '__spec__': None,
10427db96d56Sopenharmony_ci            'spam': 42,
10437db96d56Sopenharmony_ci            })
10447db96d56Sopenharmony_ci
10457db96d56Sopenharmony_ci    # XXX Fix this test!
10467db96d56Sopenharmony_ci    @unittest.skip('blocking forever')
10477db96d56Sopenharmony_ci    def test_still_running_at_exit(self):
10487db96d56Sopenharmony_ci        script = dedent(f"""
10497db96d56Sopenharmony_ci        from textwrap import dedent
10507db96d56Sopenharmony_ci        import threading
10517db96d56Sopenharmony_ci        import _xxsubinterpreters as _interpreters
10527db96d56Sopenharmony_ci        id = _interpreters.create()
10537db96d56Sopenharmony_ci        def f():
10547db96d56Sopenharmony_ci            _interpreters.run_string(id, dedent('''
10557db96d56Sopenharmony_ci                import time
10567db96d56Sopenharmony_ci                # Give plenty of time for the main interpreter to finish.
10577db96d56Sopenharmony_ci                time.sleep(1_000_000)
10587db96d56Sopenharmony_ci                '''))
10597db96d56Sopenharmony_ci
10607db96d56Sopenharmony_ci        t = threading.Thread(target=f)
10617db96d56Sopenharmony_ci        t.start()
10627db96d56Sopenharmony_ci        """)
10637db96d56Sopenharmony_ci        with support.temp_dir() as dirname:
10647db96d56Sopenharmony_ci            filename = script_helper.make_script(dirname, 'interp', script)
10657db96d56Sopenharmony_ci            with script_helper.spawn_python(filename) as proc:
10667db96d56Sopenharmony_ci                retcode = proc.wait()
10677db96d56Sopenharmony_ci
10687db96d56Sopenharmony_ci        self.assertEqual(retcode, 0)
10697db96d56Sopenharmony_ci
10707db96d56Sopenharmony_ci
10717db96d56Sopenharmony_ci##################################
10727db96d56Sopenharmony_ci# channel tests
10737db96d56Sopenharmony_ci
10747db96d56Sopenharmony_ciclass ChannelIDTests(TestBase):
10757db96d56Sopenharmony_ci
10767db96d56Sopenharmony_ci    def test_default_kwargs(self):
10777db96d56Sopenharmony_ci        cid = interpreters._channel_id(10, force=True)
10787db96d56Sopenharmony_ci
10797db96d56Sopenharmony_ci        self.assertEqual(int(cid), 10)
10807db96d56Sopenharmony_ci        self.assertEqual(cid.end, 'both')
10817db96d56Sopenharmony_ci
10827db96d56Sopenharmony_ci    def test_with_kwargs(self):
10837db96d56Sopenharmony_ci        cid = interpreters._channel_id(10, send=True, force=True)
10847db96d56Sopenharmony_ci        self.assertEqual(cid.end, 'send')
10857db96d56Sopenharmony_ci
10867db96d56Sopenharmony_ci        cid = interpreters._channel_id(10, send=True, recv=False, force=True)
10877db96d56Sopenharmony_ci        self.assertEqual(cid.end, 'send')
10887db96d56Sopenharmony_ci
10897db96d56Sopenharmony_ci        cid = interpreters._channel_id(10, recv=True, force=True)
10907db96d56Sopenharmony_ci        self.assertEqual(cid.end, 'recv')
10917db96d56Sopenharmony_ci
10927db96d56Sopenharmony_ci        cid = interpreters._channel_id(10, recv=True, send=False, force=True)
10937db96d56Sopenharmony_ci        self.assertEqual(cid.end, 'recv')
10947db96d56Sopenharmony_ci
10957db96d56Sopenharmony_ci        cid = interpreters._channel_id(10, send=True, recv=True, force=True)
10967db96d56Sopenharmony_ci        self.assertEqual(cid.end, 'both')
10977db96d56Sopenharmony_ci
10987db96d56Sopenharmony_ci    def test_coerce_id(self):
10997db96d56Sopenharmony_ci        class Int(str):
11007db96d56Sopenharmony_ci            def __index__(self):
11017db96d56Sopenharmony_ci                return 10
11027db96d56Sopenharmony_ci
11037db96d56Sopenharmony_ci        cid = interpreters._channel_id(Int(), force=True)
11047db96d56Sopenharmony_ci        self.assertEqual(int(cid), 10)
11057db96d56Sopenharmony_ci
11067db96d56Sopenharmony_ci    def test_bad_id(self):
11077db96d56Sopenharmony_ci        self.assertRaises(TypeError, interpreters._channel_id, object())
11087db96d56Sopenharmony_ci        self.assertRaises(TypeError, interpreters._channel_id, 10.0)
11097db96d56Sopenharmony_ci        self.assertRaises(TypeError, interpreters._channel_id, '10')
11107db96d56Sopenharmony_ci        self.assertRaises(TypeError, interpreters._channel_id, b'10')
11117db96d56Sopenharmony_ci        self.assertRaises(ValueError, interpreters._channel_id, -1)
11127db96d56Sopenharmony_ci        self.assertRaises(OverflowError, interpreters._channel_id, 2**64)
11137db96d56Sopenharmony_ci
11147db96d56Sopenharmony_ci    def test_bad_kwargs(self):
11157db96d56Sopenharmony_ci        with self.assertRaises(ValueError):
11167db96d56Sopenharmony_ci            interpreters._channel_id(10, send=False, recv=False)
11177db96d56Sopenharmony_ci
11187db96d56Sopenharmony_ci    def test_does_not_exist(self):
11197db96d56Sopenharmony_ci        cid = interpreters.channel_create()
11207db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelNotFoundError):
11217db96d56Sopenharmony_ci            interpreters._channel_id(int(cid) + 1)  # unforced
11227db96d56Sopenharmony_ci
11237db96d56Sopenharmony_ci    def test_str(self):
11247db96d56Sopenharmony_ci        cid = interpreters._channel_id(10, force=True)
11257db96d56Sopenharmony_ci        self.assertEqual(str(cid), '10')
11267db96d56Sopenharmony_ci
11277db96d56Sopenharmony_ci    def test_repr(self):
11287db96d56Sopenharmony_ci        cid = interpreters._channel_id(10, force=True)
11297db96d56Sopenharmony_ci        self.assertEqual(repr(cid), 'ChannelID(10)')
11307db96d56Sopenharmony_ci
11317db96d56Sopenharmony_ci        cid = interpreters._channel_id(10, send=True, force=True)
11327db96d56Sopenharmony_ci        self.assertEqual(repr(cid), 'ChannelID(10, send=True)')
11337db96d56Sopenharmony_ci
11347db96d56Sopenharmony_ci        cid = interpreters._channel_id(10, recv=True, force=True)
11357db96d56Sopenharmony_ci        self.assertEqual(repr(cid), 'ChannelID(10, recv=True)')
11367db96d56Sopenharmony_ci
11377db96d56Sopenharmony_ci        cid = interpreters._channel_id(10, send=True, recv=True, force=True)
11387db96d56Sopenharmony_ci        self.assertEqual(repr(cid), 'ChannelID(10)')
11397db96d56Sopenharmony_ci
11407db96d56Sopenharmony_ci    def test_equality(self):
11417db96d56Sopenharmony_ci        cid1 = interpreters.channel_create()
11427db96d56Sopenharmony_ci        cid2 = interpreters._channel_id(int(cid1))
11437db96d56Sopenharmony_ci        cid3 = interpreters.channel_create()
11447db96d56Sopenharmony_ci
11457db96d56Sopenharmony_ci        self.assertTrue(cid1 == cid1)
11467db96d56Sopenharmony_ci        self.assertTrue(cid1 == cid2)
11477db96d56Sopenharmony_ci        self.assertTrue(cid1 == int(cid1))
11487db96d56Sopenharmony_ci        self.assertTrue(int(cid1) == cid1)
11497db96d56Sopenharmony_ci        self.assertTrue(cid1 == float(int(cid1)))
11507db96d56Sopenharmony_ci        self.assertTrue(float(int(cid1)) == cid1)
11517db96d56Sopenharmony_ci        self.assertFalse(cid1 == float(int(cid1)) + 0.1)
11527db96d56Sopenharmony_ci        self.assertFalse(cid1 == str(int(cid1)))
11537db96d56Sopenharmony_ci        self.assertFalse(cid1 == 2**1000)
11547db96d56Sopenharmony_ci        self.assertFalse(cid1 == float('inf'))
11557db96d56Sopenharmony_ci        self.assertFalse(cid1 == 'spam')
11567db96d56Sopenharmony_ci        self.assertFalse(cid1 == cid3)
11577db96d56Sopenharmony_ci
11587db96d56Sopenharmony_ci        self.assertFalse(cid1 != cid1)
11597db96d56Sopenharmony_ci        self.assertFalse(cid1 != cid2)
11607db96d56Sopenharmony_ci        self.assertTrue(cid1 != cid3)
11617db96d56Sopenharmony_ci
11627db96d56Sopenharmony_ci
11637db96d56Sopenharmony_ciclass ChannelTests(TestBase):
11647db96d56Sopenharmony_ci
11657db96d56Sopenharmony_ci    def test_create_cid(self):
11667db96d56Sopenharmony_ci        cid = interpreters.channel_create()
11677db96d56Sopenharmony_ci        self.assertIsInstance(cid, interpreters.ChannelID)
11687db96d56Sopenharmony_ci
11697db96d56Sopenharmony_ci    def test_sequential_ids(self):
11707db96d56Sopenharmony_ci        before = interpreters.channel_list_all()
11717db96d56Sopenharmony_ci        id1 = interpreters.channel_create()
11727db96d56Sopenharmony_ci        id2 = interpreters.channel_create()
11737db96d56Sopenharmony_ci        id3 = interpreters.channel_create()
11747db96d56Sopenharmony_ci        after = interpreters.channel_list_all()
11757db96d56Sopenharmony_ci
11767db96d56Sopenharmony_ci        self.assertEqual(id2, int(id1) + 1)
11777db96d56Sopenharmony_ci        self.assertEqual(id3, int(id2) + 1)
11787db96d56Sopenharmony_ci        self.assertEqual(set(after) - set(before), {id1, id2, id3})
11797db96d56Sopenharmony_ci
11807db96d56Sopenharmony_ci    def test_ids_global(self):
11817db96d56Sopenharmony_ci        id1 = interpreters.create()
11827db96d56Sopenharmony_ci        out = _run_output(id1, dedent("""
11837db96d56Sopenharmony_ci            import _xxsubinterpreters as _interpreters
11847db96d56Sopenharmony_ci            cid = _interpreters.channel_create()
11857db96d56Sopenharmony_ci            print(cid)
11867db96d56Sopenharmony_ci            """))
11877db96d56Sopenharmony_ci        cid1 = int(out.strip())
11887db96d56Sopenharmony_ci
11897db96d56Sopenharmony_ci        id2 = interpreters.create()
11907db96d56Sopenharmony_ci        out = _run_output(id2, dedent("""
11917db96d56Sopenharmony_ci            import _xxsubinterpreters as _interpreters
11927db96d56Sopenharmony_ci            cid = _interpreters.channel_create()
11937db96d56Sopenharmony_ci            print(cid)
11947db96d56Sopenharmony_ci            """))
11957db96d56Sopenharmony_ci        cid2 = int(out.strip())
11967db96d56Sopenharmony_ci
11977db96d56Sopenharmony_ci        self.assertEqual(cid2, int(cid1) + 1)
11987db96d56Sopenharmony_ci
11997db96d56Sopenharmony_ci    def test_channel_list_interpreters_none(self):
12007db96d56Sopenharmony_ci        """Test listing interpreters for a channel with no associations."""
12017db96d56Sopenharmony_ci        # Test for channel with no associated interpreters.
12027db96d56Sopenharmony_ci        cid = interpreters.channel_create()
12037db96d56Sopenharmony_ci        send_interps = interpreters.channel_list_interpreters(cid, send=True)
12047db96d56Sopenharmony_ci        recv_interps = interpreters.channel_list_interpreters(cid, send=False)
12057db96d56Sopenharmony_ci        self.assertEqual(send_interps, [])
12067db96d56Sopenharmony_ci        self.assertEqual(recv_interps, [])
12077db96d56Sopenharmony_ci
12087db96d56Sopenharmony_ci    def test_channel_list_interpreters_basic(self):
12097db96d56Sopenharmony_ci        """Test basic listing channel interpreters."""
12107db96d56Sopenharmony_ci        interp0 = interpreters.get_main()
12117db96d56Sopenharmony_ci        cid = interpreters.channel_create()
12127db96d56Sopenharmony_ci        interpreters.channel_send(cid, "send")
12137db96d56Sopenharmony_ci        # Test for a channel that has one end associated to an interpreter.
12147db96d56Sopenharmony_ci        send_interps = interpreters.channel_list_interpreters(cid, send=True)
12157db96d56Sopenharmony_ci        recv_interps = interpreters.channel_list_interpreters(cid, send=False)
12167db96d56Sopenharmony_ci        self.assertEqual(send_interps, [interp0])
12177db96d56Sopenharmony_ci        self.assertEqual(recv_interps, [])
12187db96d56Sopenharmony_ci
12197db96d56Sopenharmony_ci        interp1 = interpreters.create()
12207db96d56Sopenharmony_ci        _run_output(interp1, dedent(f"""
12217db96d56Sopenharmony_ci            import _xxsubinterpreters as _interpreters
12227db96d56Sopenharmony_ci            obj = _interpreters.channel_recv({cid})
12237db96d56Sopenharmony_ci            """))
12247db96d56Sopenharmony_ci        # Test for channel that has both ends associated to an interpreter.
12257db96d56Sopenharmony_ci        send_interps = interpreters.channel_list_interpreters(cid, send=True)
12267db96d56Sopenharmony_ci        recv_interps = interpreters.channel_list_interpreters(cid, send=False)
12277db96d56Sopenharmony_ci        self.assertEqual(send_interps, [interp0])
12287db96d56Sopenharmony_ci        self.assertEqual(recv_interps, [interp1])
12297db96d56Sopenharmony_ci
12307db96d56Sopenharmony_ci    def test_channel_list_interpreters_multiple(self):
12317db96d56Sopenharmony_ci        """Test listing interpreters for a channel with many associations."""
12327db96d56Sopenharmony_ci        interp0 = interpreters.get_main()
12337db96d56Sopenharmony_ci        interp1 = interpreters.create()
12347db96d56Sopenharmony_ci        interp2 = interpreters.create()
12357db96d56Sopenharmony_ci        interp3 = interpreters.create()
12367db96d56Sopenharmony_ci        cid = interpreters.channel_create()
12377db96d56Sopenharmony_ci
12387db96d56Sopenharmony_ci        interpreters.channel_send(cid, "send")
12397db96d56Sopenharmony_ci        _run_output(interp1, dedent(f"""
12407db96d56Sopenharmony_ci            import _xxsubinterpreters as _interpreters
12417db96d56Sopenharmony_ci            _interpreters.channel_send({cid}, "send")
12427db96d56Sopenharmony_ci            """))
12437db96d56Sopenharmony_ci        _run_output(interp2, dedent(f"""
12447db96d56Sopenharmony_ci            import _xxsubinterpreters as _interpreters
12457db96d56Sopenharmony_ci            obj = _interpreters.channel_recv({cid})
12467db96d56Sopenharmony_ci            """))
12477db96d56Sopenharmony_ci        _run_output(interp3, dedent(f"""
12487db96d56Sopenharmony_ci            import _xxsubinterpreters as _interpreters
12497db96d56Sopenharmony_ci            obj = _interpreters.channel_recv({cid})
12507db96d56Sopenharmony_ci            """))
12517db96d56Sopenharmony_ci        send_interps = interpreters.channel_list_interpreters(cid, send=True)
12527db96d56Sopenharmony_ci        recv_interps = interpreters.channel_list_interpreters(cid, send=False)
12537db96d56Sopenharmony_ci        self.assertEqual(set(send_interps), {interp0, interp1})
12547db96d56Sopenharmony_ci        self.assertEqual(set(recv_interps), {interp2, interp3})
12557db96d56Sopenharmony_ci
12567db96d56Sopenharmony_ci    def test_channel_list_interpreters_destroyed(self):
12577db96d56Sopenharmony_ci        """Test listing channel interpreters with a destroyed interpreter."""
12587db96d56Sopenharmony_ci        interp0 = interpreters.get_main()
12597db96d56Sopenharmony_ci        interp1 = interpreters.create()
12607db96d56Sopenharmony_ci        cid = interpreters.channel_create()
12617db96d56Sopenharmony_ci        interpreters.channel_send(cid, "send")
12627db96d56Sopenharmony_ci        _run_output(interp1, dedent(f"""
12637db96d56Sopenharmony_ci            import _xxsubinterpreters as _interpreters
12647db96d56Sopenharmony_ci            obj = _interpreters.channel_recv({cid})
12657db96d56Sopenharmony_ci            """))
12667db96d56Sopenharmony_ci        # Should be one interpreter associated with each end.
12677db96d56Sopenharmony_ci        send_interps = interpreters.channel_list_interpreters(cid, send=True)
12687db96d56Sopenharmony_ci        recv_interps = interpreters.channel_list_interpreters(cid, send=False)
12697db96d56Sopenharmony_ci        self.assertEqual(send_interps, [interp0])
12707db96d56Sopenharmony_ci        self.assertEqual(recv_interps, [interp1])
12717db96d56Sopenharmony_ci
12727db96d56Sopenharmony_ci        interpreters.destroy(interp1)
12737db96d56Sopenharmony_ci        # Destroyed interpreter should not be listed.
12747db96d56Sopenharmony_ci        send_interps = interpreters.channel_list_interpreters(cid, send=True)
12757db96d56Sopenharmony_ci        recv_interps = interpreters.channel_list_interpreters(cid, send=False)
12767db96d56Sopenharmony_ci        self.assertEqual(send_interps, [interp0])
12777db96d56Sopenharmony_ci        self.assertEqual(recv_interps, [])
12787db96d56Sopenharmony_ci
12797db96d56Sopenharmony_ci    def test_channel_list_interpreters_released(self):
12807db96d56Sopenharmony_ci        """Test listing channel interpreters with a released channel."""
12817db96d56Sopenharmony_ci        # Set up one channel with main interpreter on the send end and two
12827db96d56Sopenharmony_ci        # subinterpreters on the receive end.
12837db96d56Sopenharmony_ci        interp0 = interpreters.get_main()
12847db96d56Sopenharmony_ci        interp1 = interpreters.create()
12857db96d56Sopenharmony_ci        interp2 = interpreters.create()
12867db96d56Sopenharmony_ci        cid = interpreters.channel_create()
12877db96d56Sopenharmony_ci        interpreters.channel_send(cid, "data")
12887db96d56Sopenharmony_ci        _run_output(interp1, dedent(f"""
12897db96d56Sopenharmony_ci            import _xxsubinterpreters as _interpreters
12907db96d56Sopenharmony_ci            obj = _interpreters.channel_recv({cid})
12917db96d56Sopenharmony_ci            """))
12927db96d56Sopenharmony_ci        interpreters.channel_send(cid, "data")
12937db96d56Sopenharmony_ci        _run_output(interp2, dedent(f"""
12947db96d56Sopenharmony_ci            import _xxsubinterpreters as _interpreters
12957db96d56Sopenharmony_ci            obj = _interpreters.channel_recv({cid})
12967db96d56Sopenharmony_ci            """))
12977db96d56Sopenharmony_ci        # Check the setup.
12987db96d56Sopenharmony_ci        send_interps = interpreters.channel_list_interpreters(cid, send=True)
12997db96d56Sopenharmony_ci        recv_interps = interpreters.channel_list_interpreters(cid, send=False)
13007db96d56Sopenharmony_ci        self.assertEqual(len(send_interps), 1)
13017db96d56Sopenharmony_ci        self.assertEqual(len(recv_interps), 2)
13027db96d56Sopenharmony_ci
13037db96d56Sopenharmony_ci        # Release the main interpreter from the send end.
13047db96d56Sopenharmony_ci        interpreters.channel_release(cid, send=True)
13057db96d56Sopenharmony_ci        # Send end should have no associated interpreters.
13067db96d56Sopenharmony_ci        send_interps = interpreters.channel_list_interpreters(cid, send=True)
13077db96d56Sopenharmony_ci        recv_interps = interpreters.channel_list_interpreters(cid, send=False)
13087db96d56Sopenharmony_ci        self.assertEqual(len(send_interps), 0)
13097db96d56Sopenharmony_ci        self.assertEqual(len(recv_interps), 2)
13107db96d56Sopenharmony_ci
13117db96d56Sopenharmony_ci        # Release one of the subinterpreters from the receive end.
13127db96d56Sopenharmony_ci        _run_output(interp2, dedent(f"""
13137db96d56Sopenharmony_ci            import _xxsubinterpreters as _interpreters
13147db96d56Sopenharmony_ci            _interpreters.channel_release({cid})
13157db96d56Sopenharmony_ci            """))
13167db96d56Sopenharmony_ci        # Receive end should have the released interpreter removed.
13177db96d56Sopenharmony_ci        send_interps = interpreters.channel_list_interpreters(cid, send=True)
13187db96d56Sopenharmony_ci        recv_interps = interpreters.channel_list_interpreters(cid, send=False)
13197db96d56Sopenharmony_ci        self.assertEqual(len(send_interps), 0)
13207db96d56Sopenharmony_ci        self.assertEqual(recv_interps, [interp1])
13217db96d56Sopenharmony_ci
13227db96d56Sopenharmony_ci    def test_channel_list_interpreters_closed(self):
13237db96d56Sopenharmony_ci        """Test listing channel interpreters with a closed channel."""
13247db96d56Sopenharmony_ci        interp0 = interpreters.get_main()
13257db96d56Sopenharmony_ci        interp1 = interpreters.create()
13267db96d56Sopenharmony_ci        cid = interpreters.channel_create()
13277db96d56Sopenharmony_ci        # Put something in the channel so that it's not empty.
13287db96d56Sopenharmony_ci        interpreters.channel_send(cid, "send")
13297db96d56Sopenharmony_ci
13307db96d56Sopenharmony_ci        # Check initial state.
13317db96d56Sopenharmony_ci        send_interps = interpreters.channel_list_interpreters(cid, send=True)
13327db96d56Sopenharmony_ci        recv_interps = interpreters.channel_list_interpreters(cid, send=False)
13337db96d56Sopenharmony_ci        self.assertEqual(len(send_interps), 1)
13347db96d56Sopenharmony_ci        self.assertEqual(len(recv_interps), 0)
13357db96d56Sopenharmony_ci
13367db96d56Sopenharmony_ci        # Force close the channel.
13377db96d56Sopenharmony_ci        interpreters.channel_close(cid, force=True)
13387db96d56Sopenharmony_ci        # Both ends should raise an error.
13397db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelClosedError):
13407db96d56Sopenharmony_ci            interpreters.channel_list_interpreters(cid, send=True)
13417db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelClosedError):
13427db96d56Sopenharmony_ci            interpreters.channel_list_interpreters(cid, send=False)
13437db96d56Sopenharmony_ci
13447db96d56Sopenharmony_ci    def test_channel_list_interpreters_closed_send_end(self):
13457db96d56Sopenharmony_ci        """Test listing channel interpreters with a channel's send end closed."""
13467db96d56Sopenharmony_ci        interp0 = interpreters.get_main()
13477db96d56Sopenharmony_ci        interp1 = interpreters.create()
13487db96d56Sopenharmony_ci        cid = interpreters.channel_create()
13497db96d56Sopenharmony_ci        # Put something in the channel so that it's not empty.
13507db96d56Sopenharmony_ci        interpreters.channel_send(cid, "send")
13517db96d56Sopenharmony_ci
13527db96d56Sopenharmony_ci        # Check initial state.
13537db96d56Sopenharmony_ci        send_interps = interpreters.channel_list_interpreters(cid, send=True)
13547db96d56Sopenharmony_ci        recv_interps = interpreters.channel_list_interpreters(cid, send=False)
13557db96d56Sopenharmony_ci        self.assertEqual(len(send_interps), 1)
13567db96d56Sopenharmony_ci        self.assertEqual(len(recv_interps), 0)
13577db96d56Sopenharmony_ci
13587db96d56Sopenharmony_ci        # Close the send end of the channel.
13597db96d56Sopenharmony_ci        interpreters.channel_close(cid, send=True)
13607db96d56Sopenharmony_ci        # Send end should raise an error.
13617db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelClosedError):
13627db96d56Sopenharmony_ci            interpreters.channel_list_interpreters(cid, send=True)
13637db96d56Sopenharmony_ci        # Receive end should not be closed (since channel is not empty).
13647db96d56Sopenharmony_ci        recv_interps = interpreters.channel_list_interpreters(cid, send=False)
13657db96d56Sopenharmony_ci        self.assertEqual(len(recv_interps), 0)
13667db96d56Sopenharmony_ci
13677db96d56Sopenharmony_ci        # Close the receive end of the channel from a subinterpreter.
13687db96d56Sopenharmony_ci        _run_output(interp1, dedent(f"""
13697db96d56Sopenharmony_ci            import _xxsubinterpreters as _interpreters
13707db96d56Sopenharmony_ci            _interpreters.channel_close({cid}, force=True)
13717db96d56Sopenharmony_ci            """))
13727db96d56Sopenharmony_ci        # Both ends should raise an error.
13737db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelClosedError):
13747db96d56Sopenharmony_ci            interpreters.channel_list_interpreters(cid, send=True)
13757db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelClosedError):
13767db96d56Sopenharmony_ci            interpreters.channel_list_interpreters(cid, send=False)
13777db96d56Sopenharmony_ci
13787db96d56Sopenharmony_ci    ####################
13797db96d56Sopenharmony_ci
13807db96d56Sopenharmony_ci    def test_send_recv_main(self):
13817db96d56Sopenharmony_ci        cid = interpreters.channel_create()
13827db96d56Sopenharmony_ci        orig = b'spam'
13837db96d56Sopenharmony_ci        interpreters.channel_send(cid, orig)
13847db96d56Sopenharmony_ci        obj = interpreters.channel_recv(cid)
13857db96d56Sopenharmony_ci
13867db96d56Sopenharmony_ci        self.assertEqual(obj, orig)
13877db96d56Sopenharmony_ci        self.assertIsNot(obj, orig)
13887db96d56Sopenharmony_ci
13897db96d56Sopenharmony_ci    def test_send_recv_same_interpreter(self):
13907db96d56Sopenharmony_ci        id1 = interpreters.create()
13917db96d56Sopenharmony_ci        out = _run_output(id1, dedent("""
13927db96d56Sopenharmony_ci            import _xxsubinterpreters as _interpreters
13937db96d56Sopenharmony_ci            cid = _interpreters.channel_create()
13947db96d56Sopenharmony_ci            orig = b'spam'
13957db96d56Sopenharmony_ci            _interpreters.channel_send(cid, orig)
13967db96d56Sopenharmony_ci            obj = _interpreters.channel_recv(cid)
13977db96d56Sopenharmony_ci            assert obj is not orig
13987db96d56Sopenharmony_ci            assert obj == orig
13997db96d56Sopenharmony_ci            """))
14007db96d56Sopenharmony_ci
14017db96d56Sopenharmony_ci    def test_send_recv_different_interpreters(self):
14027db96d56Sopenharmony_ci        cid = interpreters.channel_create()
14037db96d56Sopenharmony_ci        id1 = interpreters.create()
14047db96d56Sopenharmony_ci        out = _run_output(id1, dedent(f"""
14057db96d56Sopenharmony_ci            import _xxsubinterpreters as _interpreters
14067db96d56Sopenharmony_ci            _interpreters.channel_send({cid}, b'spam')
14077db96d56Sopenharmony_ci            """))
14087db96d56Sopenharmony_ci        obj = interpreters.channel_recv(cid)
14097db96d56Sopenharmony_ci
14107db96d56Sopenharmony_ci        self.assertEqual(obj, b'spam')
14117db96d56Sopenharmony_ci
14127db96d56Sopenharmony_ci    def test_send_recv_different_threads(self):
14137db96d56Sopenharmony_ci        cid = interpreters.channel_create()
14147db96d56Sopenharmony_ci
14157db96d56Sopenharmony_ci        def f():
14167db96d56Sopenharmony_ci            while True:
14177db96d56Sopenharmony_ci                try:
14187db96d56Sopenharmony_ci                    obj = interpreters.channel_recv(cid)
14197db96d56Sopenharmony_ci                    break
14207db96d56Sopenharmony_ci                except interpreters.ChannelEmptyError:
14217db96d56Sopenharmony_ci                    time.sleep(0.1)
14227db96d56Sopenharmony_ci            interpreters.channel_send(cid, obj)
14237db96d56Sopenharmony_ci        t = threading.Thread(target=f)
14247db96d56Sopenharmony_ci        t.start()
14257db96d56Sopenharmony_ci
14267db96d56Sopenharmony_ci        interpreters.channel_send(cid, b'spam')
14277db96d56Sopenharmony_ci        t.join()
14287db96d56Sopenharmony_ci        obj = interpreters.channel_recv(cid)
14297db96d56Sopenharmony_ci
14307db96d56Sopenharmony_ci        self.assertEqual(obj, b'spam')
14317db96d56Sopenharmony_ci
14327db96d56Sopenharmony_ci    def test_send_recv_different_interpreters_and_threads(self):
14337db96d56Sopenharmony_ci        cid = interpreters.channel_create()
14347db96d56Sopenharmony_ci        id1 = interpreters.create()
14357db96d56Sopenharmony_ci        out = None
14367db96d56Sopenharmony_ci
14377db96d56Sopenharmony_ci        def f():
14387db96d56Sopenharmony_ci            nonlocal out
14397db96d56Sopenharmony_ci            out = _run_output(id1, dedent(f"""
14407db96d56Sopenharmony_ci                import time
14417db96d56Sopenharmony_ci                import _xxsubinterpreters as _interpreters
14427db96d56Sopenharmony_ci                while True:
14437db96d56Sopenharmony_ci                    try:
14447db96d56Sopenharmony_ci                        obj = _interpreters.channel_recv({cid})
14457db96d56Sopenharmony_ci                        break
14467db96d56Sopenharmony_ci                    except _interpreters.ChannelEmptyError:
14477db96d56Sopenharmony_ci                        time.sleep(0.1)
14487db96d56Sopenharmony_ci                assert(obj == b'spam')
14497db96d56Sopenharmony_ci                _interpreters.channel_send({cid}, b'eggs')
14507db96d56Sopenharmony_ci                """))
14517db96d56Sopenharmony_ci        t = threading.Thread(target=f)
14527db96d56Sopenharmony_ci        t.start()
14537db96d56Sopenharmony_ci
14547db96d56Sopenharmony_ci        interpreters.channel_send(cid, b'spam')
14557db96d56Sopenharmony_ci        t.join()
14567db96d56Sopenharmony_ci        obj = interpreters.channel_recv(cid)
14577db96d56Sopenharmony_ci
14587db96d56Sopenharmony_ci        self.assertEqual(obj, b'eggs')
14597db96d56Sopenharmony_ci
14607db96d56Sopenharmony_ci    def test_send_not_found(self):
14617db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelNotFoundError):
14627db96d56Sopenharmony_ci            interpreters.channel_send(10, b'spam')
14637db96d56Sopenharmony_ci
14647db96d56Sopenharmony_ci    def test_recv_not_found(self):
14657db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelNotFoundError):
14667db96d56Sopenharmony_ci            interpreters.channel_recv(10)
14677db96d56Sopenharmony_ci
14687db96d56Sopenharmony_ci    def test_recv_empty(self):
14697db96d56Sopenharmony_ci        cid = interpreters.channel_create()
14707db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelEmptyError):
14717db96d56Sopenharmony_ci            interpreters.channel_recv(cid)
14727db96d56Sopenharmony_ci
14737db96d56Sopenharmony_ci    def test_recv_default(self):
14747db96d56Sopenharmony_ci        default = object()
14757db96d56Sopenharmony_ci        cid = interpreters.channel_create()
14767db96d56Sopenharmony_ci        obj1 = interpreters.channel_recv(cid, default)
14777db96d56Sopenharmony_ci        interpreters.channel_send(cid, None)
14787db96d56Sopenharmony_ci        interpreters.channel_send(cid, 1)
14797db96d56Sopenharmony_ci        interpreters.channel_send(cid, b'spam')
14807db96d56Sopenharmony_ci        interpreters.channel_send(cid, b'eggs')
14817db96d56Sopenharmony_ci        obj2 = interpreters.channel_recv(cid, default)
14827db96d56Sopenharmony_ci        obj3 = interpreters.channel_recv(cid, default)
14837db96d56Sopenharmony_ci        obj4 = interpreters.channel_recv(cid)
14847db96d56Sopenharmony_ci        obj5 = interpreters.channel_recv(cid, default)
14857db96d56Sopenharmony_ci        obj6 = interpreters.channel_recv(cid, default)
14867db96d56Sopenharmony_ci
14877db96d56Sopenharmony_ci        self.assertIs(obj1, default)
14887db96d56Sopenharmony_ci        self.assertIs(obj2, None)
14897db96d56Sopenharmony_ci        self.assertEqual(obj3, 1)
14907db96d56Sopenharmony_ci        self.assertEqual(obj4, b'spam')
14917db96d56Sopenharmony_ci        self.assertEqual(obj5, b'eggs')
14927db96d56Sopenharmony_ci        self.assertIs(obj6, default)
14937db96d56Sopenharmony_ci
14947db96d56Sopenharmony_ci    def test_run_string_arg_unresolved(self):
14957db96d56Sopenharmony_ci        cid = interpreters.channel_create()
14967db96d56Sopenharmony_ci        interp = interpreters.create()
14977db96d56Sopenharmony_ci
14987db96d56Sopenharmony_ci        out = _run_output(interp, dedent("""
14997db96d56Sopenharmony_ci            import _xxsubinterpreters as _interpreters
15007db96d56Sopenharmony_ci            print(cid.end)
15017db96d56Sopenharmony_ci            _interpreters.channel_send(cid, b'spam')
15027db96d56Sopenharmony_ci            """),
15037db96d56Sopenharmony_ci            dict(cid=cid.send))
15047db96d56Sopenharmony_ci        obj = interpreters.channel_recv(cid)
15057db96d56Sopenharmony_ci
15067db96d56Sopenharmony_ci        self.assertEqual(obj, b'spam')
15077db96d56Sopenharmony_ci        self.assertEqual(out.strip(), 'send')
15087db96d56Sopenharmony_ci
15097db96d56Sopenharmony_ci    # XXX For now there is no high-level channel into which the
15107db96d56Sopenharmony_ci    # sent channel ID can be converted...
15117db96d56Sopenharmony_ci    # Note: this test caused crashes on some buildbots (bpo-33615).
15127db96d56Sopenharmony_ci    @unittest.skip('disabled until high-level channels exist')
15137db96d56Sopenharmony_ci    def test_run_string_arg_resolved(self):
15147db96d56Sopenharmony_ci        cid = interpreters.channel_create()
15157db96d56Sopenharmony_ci        cid = interpreters._channel_id(cid, _resolve=True)
15167db96d56Sopenharmony_ci        interp = interpreters.create()
15177db96d56Sopenharmony_ci
15187db96d56Sopenharmony_ci        out = _run_output(interp, dedent("""
15197db96d56Sopenharmony_ci            import _xxsubinterpreters as _interpreters
15207db96d56Sopenharmony_ci            print(chan.id.end)
15217db96d56Sopenharmony_ci            _interpreters.channel_send(chan.id, b'spam')
15227db96d56Sopenharmony_ci            """),
15237db96d56Sopenharmony_ci            dict(chan=cid.send))
15247db96d56Sopenharmony_ci        obj = interpreters.channel_recv(cid)
15257db96d56Sopenharmony_ci
15267db96d56Sopenharmony_ci        self.assertEqual(obj, b'spam')
15277db96d56Sopenharmony_ci        self.assertEqual(out.strip(), 'send')
15287db96d56Sopenharmony_ci
15297db96d56Sopenharmony_ci    # close
15307db96d56Sopenharmony_ci
15317db96d56Sopenharmony_ci    def test_close_single_user(self):
15327db96d56Sopenharmony_ci        cid = interpreters.channel_create()
15337db96d56Sopenharmony_ci        interpreters.channel_send(cid, b'spam')
15347db96d56Sopenharmony_ci        interpreters.channel_recv(cid)
15357db96d56Sopenharmony_ci        interpreters.channel_close(cid)
15367db96d56Sopenharmony_ci
15377db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelClosedError):
15387db96d56Sopenharmony_ci            interpreters.channel_send(cid, b'eggs')
15397db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelClosedError):
15407db96d56Sopenharmony_ci            interpreters.channel_recv(cid)
15417db96d56Sopenharmony_ci
15427db96d56Sopenharmony_ci    def test_close_multiple_users(self):
15437db96d56Sopenharmony_ci        cid = interpreters.channel_create()
15447db96d56Sopenharmony_ci        id1 = interpreters.create()
15457db96d56Sopenharmony_ci        id2 = interpreters.create()
15467db96d56Sopenharmony_ci        interpreters.run_string(id1, dedent(f"""
15477db96d56Sopenharmony_ci            import _xxsubinterpreters as _interpreters
15487db96d56Sopenharmony_ci            _interpreters.channel_send({cid}, b'spam')
15497db96d56Sopenharmony_ci            """))
15507db96d56Sopenharmony_ci        interpreters.run_string(id2, dedent(f"""
15517db96d56Sopenharmony_ci            import _xxsubinterpreters as _interpreters
15527db96d56Sopenharmony_ci            _interpreters.channel_recv({cid})
15537db96d56Sopenharmony_ci            """))
15547db96d56Sopenharmony_ci        interpreters.channel_close(cid)
15557db96d56Sopenharmony_ci        with self.assertRaises(interpreters.RunFailedError) as cm:
15567db96d56Sopenharmony_ci            interpreters.run_string(id1, dedent(f"""
15577db96d56Sopenharmony_ci                _interpreters.channel_send({cid}, b'spam')
15587db96d56Sopenharmony_ci                """))
15597db96d56Sopenharmony_ci        self.assertIn('ChannelClosedError', str(cm.exception))
15607db96d56Sopenharmony_ci        with self.assertRaises(interpreters.RunFailedError) as cm:
15617db96d56Sopenharmony_ci            interpreters.run_string(id2, dedent(f"""
15627db96d56Sopenharmony_ci                _interpreters.channel_send({cid}, b'spam')
15637db96d56Sopenharmony_ci                """))
15647db96d56Sopenharmony_ci        self.assertIn('ChannelClosedError', str(cm.exception))
15657db96d56Sopenharmony_ci
15667db96d56Sopenharmony_ci    def test_close_multiple_times(self):
15677db96d56Sopenharmony_ci        cid = interpreters.channel_create()
15687db96d56Sopenharmony_ci        interpreters.channel_send(cid, b'spam')
15697db96d56Sopenharmony_ci        interpreters.channel_recv(cid)
15707db96d56Sopenharmony_ci        interpreters.channel_close(cid)
15717db96d56Sopenharmony_ci
15727db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelClosedError):
15737db96d56Sopenharmony_ci            interpreters.channel_close(cid)
15747db96d56Sopenharmony_ci
15757db96d56Sopenharmony_ci    def test_close_empty(self):
15767db96d56Sopenharmony_ci        tests = [
15777db96d56Sopenharmony_ci            (False, False),
15787db96d56Sopenharmony_ci            (True, False),
15797db96d56Sopenharmony_ci            (False, True),
15807db96d56Sopenharmony_ci            (True, True),
15817db96d56Sopenharmony_ci            ]
15827db96d56Sopenharmony_ci        for send, recv in tests:
15837db96d56Sopenharmony_ci            with self.subTest((send, recv)):
15847db96d56Sopenharmony_ci                cid = interpreters.channel_create()
15857db96d56Sopenharmony_ci                interpreters.channel_send(cid, b'spam')
15867db96d56Sopenharmony_ci                interpreters.channel_recv(cid)
15877db96d56Sopenharmony_ci                interpreters.channel_close(cid, send=send, recv=recv)
15887db96d56Sopenharmony_ci
15897db96d56Sopenharmony_ci                with self.assertRaises(interpreters.ChannelClosedError):
15907db96d56Sopenharmony_ci                    interpreters.channel_send(cid, b'eggs')
15917db96d56Sopenharmony_ci                with self.assertRaises(interpreters.ChannelClosedError):
15927db96d56Sopenharmony_ci                    interpreters.channel_recv(cid)
15937db96d56Sopenharmony_ci
15947db96d56Sopenharmony_ci    def test_close_defaults_with_unused_items(self):
15957db96d56Sopenharmony_ci        cid = interpreters.channel_create()
15967db96d56Sopenharmony_ci        interpreters.channel_send(cid, b'spam')
15977db96d56Sopenharmony_ci        interpreters.channel_send(cid, b'ham')
15987db96d56Sopenharmony_ci
15997db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelNotEmptyError):
16007db96d56Sopenharmony_ci            interpreters.channel_close(cid)
16017db96d56Sopenharmony_ci        interpreters.channel_recv(cid)
16027db96d56Sopenharmony_ci        interpreters.channel_send(cid, b'eggs')
16037db96d56Sopenharmony_ci
16047db96d56Sopenharmony_ci    def test_close_recv_with_unused_items_unforced(self):
16057db96d56Sopenharmony_ci        cid = interpreters.channel_create()
16067db96d56Sopenharmony_ci        interpreters.channel_send(cid, b'spam')
16077db96d56Sopenharmony_ci        interpreters.channel_send(cid, b'ham')
16087db96d56Sopenharmony_ci
16097db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelNotEmptyError):
16107db96d56Sopenharmony_ci            interpreters.channel_close(cid, recv=True)
16117db96d56Sopenharmony_ci        interpreters.channel_recv(cid)
16127db96d56Sopenharmony_ci        interpreters.channel_send(cid, b'eggs')
16137db96d56Sopenharmony_ci        interpreters.channel_recv(cid)
16147db96d56Sopenharmony_ci        interpreters.channel_recv(cid)
16157db96d56Sopenharmony_ci        interpreters.channel_close(cid, recv=True)
16167db96d56Sopenharmony_ci
16177db96d56Sopenharmony_ci    def test_close_send_with_unused_items_unforced(self):
16187db96d56Sopenharmony_ci        cid = interpreters.channel_create()
16197db96d56Sopenharmony_ci        interpreters.channel_send(cid, b'spam')
16207db96d56Sopenharmony_ci        interpreters.channel_send(cid, b'ham')
16217db96d56Sopenharmony_ci        interpreters.channel_close(cid, send=True)
16227db96d56Sopenharmony_ci
16237db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelClosedError):
16247db96d56Sopenharmony_ci            interpreters.channel_send(cid, b'eggs')
16257db96d56Sopenharmony_ci        interpreters.channel_recv(cid)
16267db96d56Sopenharmony_ci        interpreters.channel_recv(cid)
16277db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelClosedError):
16287db96d56Sopenharmony_ci            interpreters.channel_recv(cid)
16297db96d56Sopenharmony_ci
16307db96d56Sopenharmony_ci    def test_close_both_with_unused_items_unforced(self):
16317db96d56Sopenharmony_ci        cid = interpreters.channel_create()
16327db96d56Sopenharmony_ci        interpreters.channel_send(cid, b'spam')
16337db96d56Sopenharmony_ci        interpreters.channel_send(cid, b'ham')
16347db96d56Sopenharmony_ci
16357db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelNotEmptyError):
16367db96d56Sopenharmony_ci            interpreters.channel_close(cid, recv=True, send=True)
16377db96d56Sopenharmony_ci        interpreters.channel_recv(cid)
16387db96d56Sopenharmony_ci        interpreters.channel_send(cid, b'eggs')
16397db96d56Sopenharmony_ci        interpreters.channel_recv(cid)
16407db96d56Sopenharmony_ci        interpreters.channel_recv(cid)
16417db96d56Sopenharmony_ci        interpreters.channel_close(cid, recv=True)
16427db96d56Sopenharmony_ci
16437db96d56Sopenharmony_ci    def test_close_recv_with_unused_items_forced(self):
16447db96d56Sopenharmony_ci        cid = interpreters.channel_create()
16457db96d56Sopenharmony_ci        interpreters.channel_send(cid, b'spam')
16467db96d56Sopenharmony_ci        interpreters.channel_send(cid, b'ham')
16477db96d56Sopenharmony_ci        interpreters.channel_close(cid, recv=True, force=True)
16487db96d56Sopenharmony_ci
16497db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelClosedError):
16507db96d56Sopenharmony_ci            interpreters.channel_send(cid, b'eggs')
16517db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelClosedError):
16527db96d56Sopenharmony_ci            interpreters.channel_recv(cid)
16537db96d56Sopenharmony_ci
16547db96d56Sopenharmony_ci    def test_close_send_with_unused_items_forced(self):
16557db96d56Sopenharmony_ci        cid = interpreters.channel_create()
16567db96d56Sopenharmony_ci        interpreters.channel_send(cid, b'spam')
16577db96d56Sopenharmony_ci        interpreters.channel_send(cid, b'ham')
16587db96d56Sopenharmony_ci        interpreters.channel_close(cid, send=True, force=True)
16597db96d56Sopenharmony_ci
16607db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelClosedError):
16617db96d56Sopenharmony_ci            interpreters.channel_send(cid, b'eggs')
16627db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelClosedError):
16637db96d56Sopenharmony_ci            interpreters.channel_recv(cid)
16647db96d56Sopenharmony_ci
16657db96d56Sopenharmony_ci    def test_close_both_with_unused_items_forced(self):
16667db96d56Sopenharmony_ci        cid = interpreters.channel_create()
16677db96d56Sopenharmony_ci        interpreters.channel_send(cid, b'spam')
16687db96d56Sopenharmony_ci        interpreters.channel_send(cid, b'ham')
16697db96d56Sopenharmony_ci        interpreters.channel_close(cid, send=True, recv=True, force=True)
16707db96d56Sopenharmony_ci
16717db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelClosedError):
16727db96d56Sopenharmony_ci            interpreters.channel_send(cid, b'eggs')
16737db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelClosedError):
16747db96d56Sopenharmony_ci            interpreters.channel_recv(cid)
16757db96d56Sopenharmony_ci
16767db96d56Sopenharmony_ci    def test_close_never_used(self):
16777db96d56Sopenharmony_ci        cid = interpreters.channel_create()
16787db96d56Sopenharmony_ci        interpreters.channel_close(cid)
16797db96d56Sopenharmony_ci
16807db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelClosedError):
16817db96d56Sopenharmony_ci            interpreters.channel_send(cid, b'spam')
16827db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelClosedError):
16837db96d56Sopenharmony_ci            interpreters.channel_recv(cid)
16847db96d56Sopenharmony_ci
16857db96d56Sopenharmony_ci    def test_close_by_unassociated_interp(self):
16867db96d56Sopenharmony_ci        cid = interpreters.channel_create()
16877db96d56Sopenharmony_ci        interpreters.channel_send(cid, b'spam')
16887db96d56Sopenharmony_ci        interp = interpreters.create()
16897db96d56Sopenharmony_ci        interpreters.run_string(interp, dedent(f"""
16907db96d56Sopenharmony_ci            import _xxsubinterpreters as _interpreters
16917db96d56Sopenharmony_ci            _interpreters.channel_close({cid}, force=True)
16927db96d56Sopenharmony_ci            """))
16937db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelClosedError):
16947db96d56Sopenharmony_ci            interpreters.channel_recv(cid)
16957db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelClosedError):
16967db96d56Sopenharmony_ci            interpreters.channel_close(cid)
16977db96d56Sopenharmony_ci
16987db96d56Sopenharmony_ci    def test_close_used_multiple_times_by_single_user(self):
16997db96d56Sopenharmony_ci        cid = interpreters.channel_create()
17007db96d56Sopenharmony_ci        interpreters.channel_send(cid, b'spam')
17017db96d56Sopenharmony_ci        interpreters.channel_send(cid, b'spam')
17027db96d56Sopenharmony_ci        interpreters.channel_send(cid, b'spam')
17037db96d56Sopenharmony_ci        interpreters.channel_recv(cid)
17047db96d56Sopenharmony_ci        interpreters.channel_close(cid, force=True)
17057db96d56Sopenharmony_ci
17067db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelClosedError):
17077db96d56Sopenharmony_ci            interpreters.channel_send(cid, b'eggs')
17087db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelClosedError):
17097db96d56Sopenharmony_ci            interpreters.channel_recv(cid)
17107db96d56Sopenharmony_ci
17117db96d56Sopenharmony_ci    def test_channel_list_interpreters_invalid_channel(self):
17127db96d56Sopenharmony_ci        cid = interpreters.channel_create()
17137db96d56Sopenharmony_ci        # Test for invalid channel ID.
17147db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelNotFoundError):
17157db96d56Sopenharmony_ci            interpreters.channel_list_interpreters(1000, send=True)
17167db96d56Sopenharmony_ci
17177db96d56Sopenharmony_ci        interpreters.channel_close(cid)
17187db96d56Sopenharmony_ci        # Test for a channel that has been closed.
17197db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelClosedError):
17207db96d56Sopenharmony_ci            interpreters.channel_list_interpreters(cid, send=True)
17217db96d56Sopenharmony_ci
17227db96d56Sopenharmony_ci    def test_channel_list_interpreters_invalid_args(self):
17237db96d56Sopenharmony_ci        # Tests for invalid arguments passed to the API.
17247db96d56Sopenharmony_ci        cid = interpreters.channel_create()
17257db96d56Sopenharmony_ci        with self.assertRaises(TypeError):
17267db96d56Sopenharmony_ci            interpreters.channel_list_interpreters(cid)
17277db96d56Sopenharmony_ci
17287db96d56Sopenharmony_ci
17297db96d56Sopenharmony_ciclass ChannelReleaseTests(TestBase):
17307db96d56Sopenharmony_ci
17317db96d56Sopenharmony_ci    # XXX Add more test coverage a la the tests for close().
17327db96d56Sopenharmony_ci
17337db96d56Sopenharmony_ci    """
17347db96d56Sopenharmony_ci    - main / interp / other
17357db96d56Sopenharmony_ci    - run in: current thread / new thread / other thread / different threads
17367db96d56Sopenharmony_ci    - end / opposite
17377db96d56Sopenharmony_ci    - force / no force
17387db96d56Sopenharmony_ci    - used / not used  (associated / not associated)
17397db96d56Sopenharmony_ci    - empty / emptied / never emptied / partly emptied
17407db96d56Sopenharmony_ci    - closed / not closed
17417db96d56Sopenharmony_ci    - released / not released
17427db96d56Sopenharmony_ci    - creator (interp) / other
17437db96d56Sopenharmony_ci    - associated interpreter not running
17447db96d56Sopenharmony_ci    - associated interpreter destroyed
17457db96d56Sopenharmony_ci    """
17467db96d56Sopenharmony_ci
17477db96d56Sopenharmony_ci    """
17487db96d56Sopenharmony_ci    use
17497db96d56Sopenharmony_ci    pre-release
17507db96d56Sopenharmony_ci    release
17517db96d56Sopenharmony_ci    after
17527db96d56Sopenharmony_ci    check
17537db96d56Sopenharmony_ci    """
17547db96d56Sopenharmony_ci
17557db96d56Sopenharmony_ci    """
17567db96d56Sopenharmony_ci    release in:         main, interp1
17577db96d56Sopenharmony_ci    creator:            same, other (incl. interp2)
17587db96d56Sopenharmony_ci
17597db96d56Sopenharmony_ci    use:                None,send,recv,send/recv in None,same,other(incl. interp2),same+other(incl. interp2),all
17607db96d56Sopenharmony_ci    pre-release:        None,send,recv,both in None,same,other(incl. interp2),same+other(incl. interp2),all
17617db96d56Sopenharmony_ci    pre-release forced: None,send,recv,both in None,same,other(incl. interp2),same+other(incl. interp2),all
17627db96d56Sopenharmony_ci
17637db96d56Sopenharmony_ci    release:            same
17647db96d56Sopenharmony_ci    release forced:     same
17657db96d56Sopenharmony_ci
17667db96d56Sopenharmony_ci    use after:          None,send,recv,send/recv in None,same,other(incl. interp2),same+other(incl. interp2),all
17677db96d56Sopenharmony_ci    release after:      None,send,recv,send/recv in None,same,other(incl. interp2),same+other(incl. interp2),all
17687db96d56Sopenharmony_ci    check released:     send/recv for same/other(incl. interp2)
17697db96d56Sopenharmony_ci    check closed:       send/recv for same/other(incl. interp2)
17707db96d56Sopenharmony_ci    """
17717db96d56Sopenharmony_ci
17727db96d56Sopenharmony_ci    def test_single_user(self):
17737db96d56Sopenharmony_ci        cid = interpreters.channel_create()
17747db96d56Sopenharmony_ci        interpreters.channel_send(cid, b'spam')
17757db96d56Sopenharmony_ci        interpreters.channel_recv(cid)
17767db96d56Sopenharmony_ci        interpreters.channel_release(cid, send=True, recv=True)
17777db96d56Sopenharmony_ci
17787db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelClosedError):
17797db96d56Sopenharmony_ci            interpreters.channel_send(cid, b'eggs')
17807db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelClosedError):
17817db96d56Sopenharmony_ci            interpreters.channel_recv(cid)
17827db96d56Sopenharmony_ci
17837db96d56Sopenharmony_ci    def test_multiple_users(self):
17847db96d56Sopenharmony_ci        cid = interpreters.channel_create()
17857db96d56Sopenharmony_ci        id1 = interpreters.create()
17867db96d56Sopenharmony_ci        id2 = interpreters.create()
17877db96d56Sopenharmony_ci        interpreters.run_string(id1, dedent(f"""
17887db96d56Sopenharmony_ci            import _xxsubinterpreters as _interpreters
17897db96d56Sopenharmony_ci            _interpreters.channel_send({cid}, b'spam')
17907db96d56Sopenharmony_ci            """))
17917db96d56Sopenharmony_ci        out = _run_output(id2, dedent(f"""
17927db96d56Sopenharmony_ci            import _xxsubinterpreters as _interpreters
17937db96d56Sopenharmony_ci            obj = _interpreters.channel_recv({cid})
17947db96d56Sopenharmony_ci            _interpreters.channel_release({cid})
17957db96d56Sopenharmony_ci            print(repr(obj))
17967db96d56Sopenharmony_ci            """))
17977db96d56Sopenharmony_ci        interpreters.run_string(id1, dedent(f"""
17987db96d56Sopenharmony_ci            _interpreters.channel_release({cid})
17997db96d56Sopenharmony_ci            """))
18007db96d56Sopenharmony_ci
18017db96d56Sopenharmony_ci        self.assertEqual(out.strip(), "b'spam'")
18027db96d56Sopenharmony_ci
18037db96d56Sopenharmony_ci    def test_no_kwargs(self):
18047db96d56Sopenharmony_ci        cid = interpreters.channel_create()
18057db96d56Sopenharmony_ci        interpreters.channel_send(cid, b'spam')
18067db96d56Sopenharmony_ci        interpreters.channel_recv(cid)
18077db96d56Sopenharmony_ci        interpreters.channel_release(cid)
18087db96d56Sopenharmony_ci
18097db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelClosedError):
18107db96d56Sopenharmony_ci            interpreters.channel_send(cid, b'eggs')
18117db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelClosedError):
18127db96d56Sopenharmony_ci            interpreters.channel_recv(cid)
18137db96d56Sopenharmony_ci
18147db96d56Sopenharmony_ci    def test_multiple_times(self):
18157db96d56Sopenharmony_ci        cid = interpreters.channel_create()
18167db96d56Sopenharmony_ci        interpreters.channel_send(cid, b'spam')
18177db96d56Sopenharmony_ci        interpreters.channel_recv(cid)
18187db96d56Sopenharmony_ci        interpreters.channel_release(cid, send=True, recv=True)
18197db96d56Sopenharmony_ci
18207db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelClosedError):
18217db96d56Sopenharmony_ci            interpreters.channel_release(cid, send=True, recv=True)
18227db96d56Sopenharmony_ci
18237db96d56Sopenharmony_ci    def test_with_unused_items(self):
18247db96d56Sopenharmony_ci        cid = interpreters.channel_create()
18257db96d56Sopenharmony_ci        interpreters.channel_send(cid, b'spam')
18267db96d56Sopenharmony_ci        interpreters.channel_send(cid, b'ham')
18277db96d56Sopenharmony_ci        interpreters.channel_release(cid, send=True, recv=True)
18287db96d56Sopenharmony_ci
18297db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelClosedError):
18307db96d56Sopenharmony_ci            interpreters.channel_recv(cid)
18317db96d56Sopenharmony_ci
18327db96d56Sopenharmony_ci    def test_never_used(self):
18337db96d56Sopenharmony_ci        cid = interpreters.channel_create()
18347db96d56Sopenharmony_ci        interpreters.channel_release(cid)
18357db96d56Sopenharmony_ci
18367db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelClosedError):
18377db96d56Sopenharmony_ci            interpreters.channel_send(cid, b'spam')
18387db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelClosedError):
18397db96d56Sopenharmony_ci            interpreters.channel_recv(cid)
18407db96d56Sopenharmony_ci
18417db96d56Sopenharmony_ci    def test_by_unassociated_interp(self):
18427db96d56Sopenharmony_ci        cid = interpreters.channel_create()
18437db96d56Sopenharmony_ci        interpreters.channel_send(cid, b'spam')
18447db96d56Sopenharmony_ci        interp = interpreters.create()
18457db96d56Sopenharmony_ci        interpreters.run_string(interp, dedent(f"""
18467db96d56Sopenharmony_ci            import _xxsubinterpreters as _interpreters
18477db96d56Sopenharmony_ci            _interpreters.channel_release({cid})
18487db96d56Sopenharmony_ci            """))
18497db96d56Sopenharmony_ci        obj = interpreters.channel_recv(cid)
18507db96d56Sopenharmony_ci        interpreters.channel_release(cid)
18517db96d56Sopenharmony_ci
18527db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelClosedError):
18537db96d56Sopenharmony_ci            interpreters.channel_send(cid, b'eggs')
18547db96d56Sopenharmony_ci        self.assertEqual(obj, b'spam')
18557db96d56Sopenharmony_ci
18567db96d56Sopenharmony_ci    def test_close_if_unassociated(self):
18577db96d56Sopenharmony_ci        # XXX Something's not right with this test...
18587db96d56Sopenharmony_ci        cid = interpreters.channel_create()
18597db96d56Sopenharmony_ci        interp = interpreters.create()
18607db96d56Sopenharmony_ci        interpreters.run_string(interp, dedent(f"""
18617db96d56Sopenharmony_ci            import _xxsubinterpreters as _interpreters
18627db96d56Sopenharmony_ci            obj = _interpreters.channel_send({cid}, b'spam')
18637db96d56Sopenharmony_ci            _interpreters.channel_release({cid})
18647db96d56Sopenharmony_ci            """))
18657db96d56Sopenharmony_ci
18667db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelClosedError):
18677db96d56Sopenharmony_ci            interpreters.channel_recv(cid)
18687db96d56Sopenharmony_ci
18697db96d56Sopenharmony_ci    def test_partially(self):
18707db96d56Sopenharmony_ci        # XXX Is partial close too weird/confusing?
18717db96d56Sopenharmony_ci        cid = interpreters.channel_create()
18727db96d56Sopenharmony_ci        interpreters.channel_send(cid, None)
18737db96d56Sopenharmony_ci        interpreters.channel_recv(cid)
18747db96d56Sopenharmony_ci        interpreters.channel_send(cid, b'spam')
18757db96d56Sopenharmony_ci        interpreters.channel_release(cid, send=True)
18767db96d56Sopenharmony_ci        obj = interpreters.channel_recv(cid)
18777db96d56Sopenharmony_ci
18787db96d56Sopenharmony_ci        self.assertEqual(obj, b'spam')
18797db96d56Sopenharmony_ci
18807db96d56Sopenharmony_ci    def test_used_multiple_times_by_single_user(self):
18817db96d56Sopenharmony_ci        cid = interpreters.channel_create()
18827db96d56Sopenharmony_ci        interpreters.channel_send(cid, b'spam')
18837db96d56Sopenharmony_ci        interpreters.channel_send(cid, b'spam')
18847db96d56Sopenharmony_ci        interpreters.channel_send(cid, b'spam')
18857db96d56Sopenharmony_ci        interpreters.channel_recv(cid)
18867db96d56Sopenharmony_ci        interpreters.channel_release(cid, send=True, recv=True)
18877db96d56Sopenharmony_ci
18887db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelClosedError):
18897db96d56Sopenharmony_ci            interpreters.channel_send(cid, b'eggs')
18907db96d56Sopenharmony_ci        with self.assertRaises(interpreters.ChannelClosedError):
18917db96d56Sopenharmony_ci            interpreters.channel_recv(cid)
18927db96d56Sopenharmony_ci
18937db96d56Sopenharmony_ci
18947db96d56Sopenharmony_ciclass ChannelCloseFixture(namedtuple('ChannelCloseFixture',
18957db96d56Sopenharmony_ci                                     'end interp other extra creator')):
18967db96d56Sopenharmony_ci
18977db96d56Sopenharmony_ci    # Set this to True to avoid creating interpreters, e.g. when
18987db96d56Sopenharmony_ci    # scanning through test permutations without running them.
18997db96d56Sopenharmony_ci    QUICK = False
19007db96d56Sopenharmony_ci
19017db96d56Sopenharmony_ci    def __new__(cls, end, interp, other, extra, creator):
19027db96d56Sopenharmony_ci        assert end in ('send', 'recv')
19037db96d56Sopenharmony_ci        if cls.QUICK:
19047db96d56Sopenharmony_ci            known = {}
19057db96d56Sopenharmony_ci        else:
19067db96d56Sopenharmony_ci            interp = Interpreter.from_raw(interp)
19077db96d56Sopenharmony_ci            other = Interpreter.from_raw(other)
19087db96d56Sopenharmony_ci            extra = Interpreter.from_raw(extra)
19097db96d56Sopenharmony_ci            known = {
19107db96d56Sopenharmony_ci                interp.name: interp,
19117db96d56Sopenharmony_ci                other.name: other,
19127db96d56Sopenharmony_ci                extra.name: extra,
19137db96d56Sopenharmony_ci                }
19147db96d56Sopenharmony_ci        if not creator:
19157db96d56Sopenharmony_ci            creator = 'same'
19167db96d56Sopenharmony_ci        self = super().__new__(cls, end, interp, other, extra, creator)
19177db96d56Sopenharmony_ci        self._prepped = set()
19187db96d56Sopenharmony_ci        self._state = ChannelState()
19197db96d56Sopenharmony_ci        self._known = known
19207db96d56Sopenharmony_ci        return self
19217db96d56Sopenharmony_ci
19227db96d56Sopenharmony_ci    @property
19237db96d56Sopenharmony_ci    def state(self):
19247db96d56Sopenharmony_ci        return self._state
19257db96d56Sopenharmony_ci
19267db96d56Sopenharmony_ci    @property
19277db96d56Sopenharmony_ci    def cid(self):
19287db96d56Sopenharmony_ci        try:
19297db96d56Sopenharmony_ci            return self._cid
19307db96d56Sopenharmony_ci        except AttributeError:
19317db96d56Sopenharmony_ci            creator = self._get_interpreter(self.creator)
19327db96d56Sopenharmony_ci            self._cid = self._new_channel(creator)
19337db96d56Sopenharmony_ci            return self._cid
19347db96d56Sopenharmony_ci
19357db96d56Sopenharmony_ci    def get_interpreter(self, interp):
19367db96d56Sopenharmony_ci        interp = self._get_interpreter(interp)
19377db96d56Sopenharmony_ci        self._prep_interpreter(interp)
19387db96d56Sopenharmony_ci        return interp
19397db96d56Sopenharmony_ci
19407db96d56Sopenharmony_ci    def expect_closed_error(self, end=None):
19417db96d56Sopenharmony_ci        if end is None:
19427db96d56Sopenharmony_ci            end = self.end
19437db96d56Sopenharmony_ci        if end == 'recv' and self.state.closed == 'send':
19447db96d56Sopenharmony_ci            return False
19457db96d56Sopenharmony_ci        return bool(self.state.closed)
19467db96d56Sopenharmony_ci
19477db96d56Sopenharmony_ci    def prep_interpreter(self, interp):
19487db96d56Sopenharmony_ci        self._prep_interpreter(interp)
19497db96d56Sopenharmony_ci
19507db96d56Sopenharmony_ci    def record_action(self, action, result):
19517db96d56Sopenharmony_ci        self._state = result
19527db96d56Sopenharmony_ci
19537db96d56Sopenharmony_ci    def clean_up(self):
19547db96d56Sopenharmony_ci        clean_up_interpreters()
19557db96d56Sopenharmony_ci        clean_up_channels()
19567db96d56Sopenharmony_ci
19577db96d56Sopenharmony_ci    # internal methods
19587db96d56Sopenharmony_ci
19597db96d56Sopenharmony_ci    def _new_channel(self, creator):
19607db96d56Sopenharmony_ci        if creator.name == 'main':
19617db96d56Sopenharmony_ci            return interpreters.channel_create()
19627db96d56Sopenharmony_ci        else:
19637db96d56Sopenharmony_ci            ch = interpreters.channel_create()
19647db96d56Sopenharmony_ci            run_interp(creator.id, f"""
19657db96d56Sopenharmony_ci                import _xxsubinterpreters
19667db96d56Sopenharmony_ci                cid = _xxsubinterpreters.channel_create()
19677db96d56Sopenharmony_ci                # We purposefully send back an int to avoid tying the
19687db96d56Sopenharmony_ci                # channel to the other interpreter.
19697db96d56Sopenharmony_ci                _xxsubinterpreters.channel_send({ch}, int(cid))
19707db96d56Sopenharmony_ci                del _xxsubinterpreters
19717db96d56Sopenharmony_ci                """)
19727db96d56Sopenharmony_ci            self._cid = interpreters.channel_recv(ch)
19737db96d56Sopenharmony_ci        return self._cid
19747db96d56Sopenharmony_ci
19757db96d56Sopenharmony_ci    def _get_interpreter(self, interp):
19767db96d56Sopenharmony_ci        if interp in ('same', 'interp'):
19777db96d56Sopenharmony_ci            return self.interp
19787db96d56Sopenharmony_ci        elif interp == 'other':
19797db96d56Sopenharmony_ci            return self.other
19807db96d56Sopenharmony_ci        elif interp == 'extra':
19817db96d56Sopenharmony_ci            return self.extra
19827db96d56Sopenharmony_ci        else:
19837db96d56Sopenharmony_ci            name = interp
19847db96d56Sopenharmony_ci            try:
19857db96d56Sopenharmony_ci                interp = self._known[name]
19867db96d56Sopenharmony_ci            except KeyError:
19877db96d56Sopenharmony_ci                interp = self._known[name] = Interpreter(name)
19887db96d56Sopenharmony_ci            return interp
19897db96d56Sopenharmony_ci
19907db96d56Sopenharmony_ci    def _prep_interpreter(self, interp):
19917db96d56Sopenharmony_ci        if interp.id in self._prepped:
19927db96d56Sopenharmony_ci            return
19937db96d56Sopenharmony_ci        self._prepped.add(interp.id)
19947db96d56Sopenharmony_ci        if interp.name == 'main':
19957db96d56Sopenharmony_ci            return
19967db96d56Sopenharmony_ci        run_interp(interp.id, f"""
19977db96d56Sopenharmony_ci            import _xxsubinterpreters as interpreters
19987db96d56Sopenharmony_ci            import test.test__xxsubinterpreters as helpers
19997db96d56Sopenharmony_ci            ChannelState = helpers.ChannelState
20007db96d56Sopenharmony_ci            try:
20017db96d56Sopenharmony_ci                cid
20027db96d56Sopenharmony_ci            except NameError:
20037db96d56Sopenharmony_ci                cid = interpreters._channel_id({self.cid})
20047db96d56Sopenharmony_ci            """)
20057db96d56Sopenharmony_ci
20067db96d56Sopenharmony_ci
20077db96d56Sopenharmony_ci@unittest.skip('these tests take several hours to run')
20087db96d56Sopenharmony_ciclass ExhaustiveChannelTests(TestBase):
20097db96d56Sopenharmony_ci
20107db96d56Sopenharmony_ci    """
20117db96d56Sopenharmony_ci    - main / interp / other
20127db96d56Sopenharmony_ci    - run in: current thread / new thread / other thread / different threads
20137db96d56Sopenharmony_ci    - end / opposite
20147db96d56Sopenharmony_ci    - force / no force
20157db96d56Sopenharmony_ci    - used / not used  (associated / not associated)
20167db96d56Sopenharmony_ci    - empty / emptied / never emptied / partly emptied
20177db96d56Sopenharmony_ci    - closed / not closed
20187db96d56Sopenharmony_ci    - released / not released
20197db96d56Sopenharmony_ci    - creator (interp) / other
20207db96d56Sopenharmony_ci    - associated interpreter not running
20217db96d56Sopenharmony_ci    - associated interpreter destroyed
20227db96d56Sopenharmony_ci
20237db96d56Sopenharmony_ci    - close after unbound
20247db96d56Sopenharmony_ci    """
20257db96d56Sopenharmony_ci
20267db96d56Sopenharmony_ci    """
20277db96d56Sopenharmony_ci    use
20287db96d56Sopenharmony_ci    pre-close
20297db96d56Sopenharmony_ci    close
20307db96d56Sopenharmony_ci    after
20317db96d56Sopenharmony_ci    check
20327db96d56Sopenharmony_ci    """
20337db96d56Sopenharmony_ci
20347db96d56Sopenharmony_ci    """
20357db96d56Sopenharmony_ci    close in:         main, interp1
20367db96d56Sopenharmony_ci    creator:          same, other, extra
20377db96d56Sopenharmony_ci
20387db96d56Sopenharmony_ci    use:              None,send,recv,send/recv in None,same,other,same+other,all
20397db96d56Sopenharmony_ci    pre-close:        None,send,recv in None,same,other,same+other,all
20407db96d56Sopenharmony_ci    pre-close forced: None,send,recv in None,same,other,same+other,all
20417db96d56Sopenharmony_ci
20427db96d56Sopenharmony_ci    close:            same
20437db96d56Sopenharmony_ci    close forced:     same
20447db96d56Sopenharmony_ci
20457db96d56Sopenharmony_ci    use after:        None,send,recv,send/recv in None,same,other,extra,same+other,all
20467db96d56Sopenharmony_ci    close after:      None,send,recv,send/recv in None,same,other,extra,same+other,all
20477db96d56Sopenharmony_ci    check closed:     send/recv for same/other(incl. interp2)
20487db96d56Sopenharmony_ci    """
20497db96d56Sopenharmony_ci
20507db96d56Sopenharmony_ci    def iter_action_sets(self):
20517db96d56Sopenharmony_ci        # - used / not used  (associated / not associated)
20527db96d56Sopenharmony_ci        # - empty / emptied / never emptied / partly emptied
20537db96d56Sopenharmony_ci        # - closed / not closed
20547db96d56Sopenharmony_ci        # - released / not released
20557db96d56Sopenharmony_ci
20567db96d56Sopenharmony_ci        # never used
20577db96d56Sopenharmony_ci        yield []
20587db96d56Sopenharmony_ci
20597db96d56Sopenharmony_ci        # only pre-closed (and possible used after)
20607db96d56Sopenharmony_ci        for closeactions in self._iter_close_action_sets('same', 'other'):
20617db96d56Sopenharmony_ci            yield closeactions
20627db96d56Sopenharmony_ci            for postactions in self._iter_post_close_action_sets():
20637db96d56Sopenharmony_ci                yield closeactions + postactions
20647db96d56Sopenharmony_ci        for closeactions in self._iter_close_action_sets('other', 'extra'):
20657db96d56Sopenharmony_ci            yield closeactions
20667db96d56Sopenharmony_ci            for postactions in self._iter_post_close_action_sets():
20677db96d56Sopenharmony_ci                yield closeactions + postactions
20687db96d56Sopenharmony_ci
20697db96d56Sopenharmony_ci        # used
20707db96d56Sopenharmony_ci        for useactions in self._iter_use_action_sets('same', 'other'):
20717db96d56Sopenharmony_ci            yield useactions
20727db96d56Sopenharmony_ci            for closeactions in self._iter_close_action_sets('same', 'other'):
20737db96d56Sopenharmony_ci                actions = useactions + closeactions
20747db96d56Sopenharmony_ci                yield actions
20757db96d56Sopenharmony_ci                for postactions in self._iter_post_close_action_sets():
20767db96d56Sopenharmony_ci                    yield actions + postactions
20777db96d56Sopenharmony_ci            for closeactions in self._iter_close_action_sets('other', 'extra'):
20787db96d56Sopenharmony_ci                actions = useactions + closeactions
20797db96d56Sopenharmony_ci                yield actions
20807db96d56Sopenharmony_ci                for postactions in self._iter_post_close_action_sets():
20817db96d56Sopenharmony_ci                    yield actions + postactions
20827db96d56Sopenharmony_ci        for useactions in self._iter_use_action_sets('other', 'extra'):
20837db96d56Sopenharmony_ci            yield useactions
20847db96d56Sopenharmony_ci            for closeactions in self._iter_close_action_sets('same', 'other'):
20857db96d56Sopenharmony_ci                actions = useactions + closeactions
20867db96d56Sopenharmony_ci                yield actions
20877db96d56Sopenharmony_ci                for postactions in self._iter_post_close_action_sets():
20887db96d56Sopenharmony_ci                    yield actions + postactions
20897db96d56Sopenharmony_ci            for closeactions in self._iter_close_action_sets('other', 'extra'):
20907db96d56Sopenharmony_ci                actions = useactions + closeactions
20917db96d56Sopenharmony_ci                yield actions
20927db96d56Sopenharmony_ci                for postactions in self._iter_post_close_action_sets():
20937db96d56Sopenharmony_ci                    yield actions + postactions
20947db96d56Sopenharmony_ci
20957db96d56Sopenharmony_ci    def _iter_use_action_sets(self, interp1, interp2):
20967db96d56Sopenharmony_ci        interps = (interp1, interp2)
20977db96d56Sopenharmony_ci
20987db96d56Sopenharmony_ci        # only recv end used
20997db96d56Sopenharmony_ci        yield [
21007db96d56Sopenharmony_ci            ChannelAction('use', 'recv', interp1),
21017db96d56Sopenharmony_ci            ]
21027db96d56Sopenharmony_ci        yield [
21037db96d56Sopenharmony_ci            ChannelAction('use', 'recv', interp2),
21047db96d56Sopenharmony_ci            ]
21057db96d56Sopenharmony_ci        yield [
21067db96d56Sopenharmony_ci            ChannelAction('use', 'recv', interp1),
21077db96d56Sopenharmony_ci            ChannelAction('use', 'recv', interp2),
21087db96d56Sopenharmony_ci            ]
21097db96d56Sopenharmony_ci
21107db96d56Sopenharmony_ci        # never emptied
21117db96d56Sopenharmony_ci        yield [
21127db96d56Sopenharmony_ci            ChannelAction('use', 'send', interp1),
21137db96d56Sopenharmony_ci            ]
21147db96d56Sopenharmony_ci        yield [
21157db96d56Sopenharmony_ci            ChannelAction('use', 'send', interp2),
21167db96d56Sopenharmony_ci            ]
21177db96d56Sopenharmony_ci        yield [
21187db96d56Sopenharmony_ci            ChannelAction('use', 'send', interp1),
21197db96d56Sopenharmony_ci            ChannelAction('use', 'send', interp2),
21207db96d56Sopenharmony_ci            ]
21217db96d56Sopenharmony_ci
21227db96d56Sopenharmony_ci        # partially emptied
21237db96d56Sopenharmony_ci        for interp1 in interps:
21247db96d56Sopenharmony_ci            for interp2 in interps:
21257db96d56Sopenharmony_ci                for interp3 in interps:
21267db96d56Sopenharmony_ci                    yield [
21277db96d56Sopenharmony_ci                        ChannelAction('use', 'send', interp1),
21287db96d56Sopenharmony_ci                        ChannelAction('use', 'send', interp2),
21297db96d56Sopenharmony_ci                        ChannelAction('use', 'recv', interp3),
21307db96d56Sopenharmony_ci                        ]
21317db96d56Sopenharmony_ci
21327db96d56Sopenharmony_ci        # fully emptied
21337db96d56Sopenharmony_ci        for interp1 in interps:
21347db96d56Sopenharmony_ci            for interp2 in interps:
21357db96d56Sopenharmony_ci                for interp3 in interps:
21367db96d56Sopenharmony_ci                    for interp4 in interps:
21377db96d56Sopenharmony_ci                        yield [
21387db96d56Sopenharmony_ci                            ChannelAction('use', 'send', interp1),
21397db96d56Sopenharmony_ci                            ChannelAction('use', 'send', interp2),
21407db96d56Sopenharmony_ci                            ChannelAction('use', 'recv', interp3),
21417db96d56Sopenharmony_ci                            ChannelAction('use', 'recv', interp4),
21427db96d56Sopenharmony_ci                            ]
21437db96d56Sopenharmony_ci
21447db96d56Sopenharmony_ci    def _iter_close_action_sets(self, interp1, interp2):
21457db96d56Sopenharmony_ci        ends = ('recv', 'send')
21467db96d56Sopenharmony_ci        interps = (interp1, interp2)
21477db96d56Sopenharmony_ci        for force in (True, False):
21487db96d56Sopenharmony_ci            op = 'force-close' if force else 'close'
21497db96d56Sopenharmony_ci            for interp in interps:
21507db96d56Sopenharmony_ci                for end in ends:
21517db96d56Sopenharmony_ci                    yield [
21527db96d56Sopenharmony_ci                        ChannelAction(op, end, interp),
21537db96d56Sopenharmony_ci                        ]
21547db96d56Sopenharmony_ci        for recvop in ('close', 'force-close'):
21557db96d56Sopenharmony_ci            for sendop in ('close', 'force-close'):
21567db96d56Sopenharmony_ci                for recv in interps:
21577db96d56Sopenharmony_ci                    for send in interps:
21587db96d56Sopenharmony_ci                        yield [
21597db96d56Sopenharmony_ci                            ChannelAction(recvop, 'recv', recv),
21607db96d56Sopenharmony_ci                            ChannelAction(sendop, 'send', send),
21617db96d56Sopenharmony_ci                            ]
21627db96d56Sopenharmony_ci
21637db96d56Sopenharmony_ci    def _iter_post_close_action_sets(self):
21647db96d56Sopenharmony_ci        for interp in ('same', 'extra', 'other'):
21657db96d56Sopenharmony_ci            yield [
21667db96d56Sopenharmony_ci                ChannelAction('use', 'recv', interp),
21677db96d56Sopenharmony_ci                ]
21687db96d56Sopenharmony_ci            yield [
21697db96d56Sopenharmony_ci                ChannelAction('use', 'send', interp),
21707db96d56Sopenharmony_ci                ]
21717db96d56Sopenharmony_ci
21727db96d56Sopenharmony_ci    def run_actions(self, fix, actions):
21737db96d56Sopenharmony_ci        for action in actions:
21747db96d56Sopenharmony_ci            self.run_action(fix, action)
21757db96d56Sopenharmony_ci
21767db96d56Sopenharmony_ci    def run_action(self, fix, action, *, hideclosed=True):
21777db96d56Sopenharmony_ci        end = action.resolve_end(fix.end)
21787db96d56Sopenharmony_ci        interp = action.resolve_interp(fix.interp, fix.other, fix.extra)
21797db96d56Sopenharmony_ci        fix.prep_interpreter(interp)
21807db96d56Sopenharmony_ci        if interp.name == 'main':
21817db96d56Sopenharmony_ci            result = run_action(
21827db96d56Sopenharmony_ci                fix.cid,
21837db96d56Sopenharmony_ci                action.action,
21847db96d56Sopenharmony_ci                end,
21857db96d56Sopenharmony_ci                fix.state,
21867db96d56Sopenharmony_ci                hideclosed=hideclosed,
21877db96d56Sopenharmony_ci                )
21887db96d56Sopenharmony_ci            fix.record_action(action, result)
21897db96d56Sopenharmony_ci        else:
21907db96d56Sopenharmony_ci            _cid = interpreters.channel_create()
21917db96d56Sopenharmony_ci            run_interp(interp.id, f"""
21927db96d56Sopenharmony_ci                result = helpers.run_action(
21937db96d56Sopenharmony_ci                    {fix.cid},
21947db96d56Sopenharmony_ci                    {repr(action.action)},
21957db96d56Sopenharmony_ci                    {repr(end)},
21967db96d56Sopenharmony_ci                    {repr(fix.state)},
21977db96d56Sopenharmony_ci                    hideclosed={hideclosed},
21987db96d56Sopenharmony_ci                    )
21997db96d56Sopenharmony_ci                interpreters.channel_send({_cid}, result.pending.to_bytes(1, 'little'))
22007db96d56Sopenharmony_ci                interpreters.channel_send({_cid}, b'X' if result.closed else b'')
22017db96d56Sopenharmony_ci                """)
22027db96d56Sopenharmony_ci            result = ChannelState(
22037db96d56Sopenharmony_ci                pending=int.from_bytes(interpreters.channel_recv(_cid), 'little'),
22047db96d56Sopenharmony_ci                closed=bool(interpreters.channel_recv(_cid)),
22057db96d56Sopenharmony_ci                )
22067db96d56Sopenharmony_ci            fix.record_action(action, result)
22077db96d56Sopenharmony_ci
22087db96d56Sopenharmony_ci    def iter_fixtures(self):
22097db96d56Sopenharmony_ci        # XXX threads?
22107db96d56Sopenharmony_ci        interpreters = [
22117db96d56Sopenharmony_ci            ('main', 'interp', 'extra'),
22127db96d56Sopenharmony_ci            ('interp', 'main', 'extra'),
22137db96d56Sopenharmony_ci            ('interp1', 'interp2', 'extra'),
22147db96d56Sopenharmony_ci            ('interp1', 'interp2', 'main'),
22157db96d56Sopenharmony_ci        ]
22167db96d56Sopenharmony_ci        for interp, other, extra in interpreters:
22177db96d56Sopenharmony_ci            for creator in ('same', 'other', 'creator'):
22187db96d56Sopenharmony_ci                for end in ('send', 'recv'):
22197db96d56Sopenharmony_ci                    yield ChannelCloseFixture(end, interp, other, extra, creator)
22207db96d56Sopenharmony_ci
22217db96d56Sopenharmony_ci    def _close(self, fix, *, force):
22227db96d56Sopenharmony_ci        op = 'force-close' if force else 'close'
22237db96d56Sopenharmony_ci        close = ChannelAction(op, fix.end, 'same')
22247db96d56Sopenharmony_ci        if not fix.expect_closed_error():
22257db96d56Sopenharmony_ci            self.run_action(fix, close, hideclosed=False)
22267db96d56Sopenharmony_ci        else:
22277db96d56Sopenharmony_ci            with self.assertRaises(interpreters.ChannelClosedError):
22287db96d56Sopenharmony_ci                self.run_action(fix, close, hideclosed=False)
22297db96d56Sopenharmony_ci
22307db96d56Sopenharmony_ci    def _assert_closed_in_interp(self, fix, interp=None):
22317db96d56Sopenharmony_ci        if interp is None or interp.name == 'main':
22327db96d56Sopenharmony_ci            with self.assertRaises(interpreters.ChannelClosedError):
22337db96d56Sopenharmony_ci                interpreters.channel_recv(fix.cid)
22347db96d56Sopenharmony_ci            with self.assertRaises(interpreters.ChannelClosedError):
22357db96d56Sopenharmony_ci                interpreters.channel_send(fix.cid, b'spam')
22367db96d56Sopenharmony_ci            with self.assertRaises(interpreters.ChannelClosedError):
22377db96d56Sopenharmony_ci                interpreters.channel_close(fix.cid)
22387db96d56Sopenharmony_ci            with self.assertRaises(interpreters.ChannelClosedError):
22397db96d56Sopenharmony_ci                interpreters.channel_close(fix.cid, force=True)
22407db96d56Sopenharmony_ci        else:
22417db96d56Sopenharmony_ci            run_interp(interp.id, f"""
22427db96d56Sopenharmony_ci                with helpers.expect_channel_closed():
22437db96d56Sopenharmony_ci                    interpreters.channel_recv(cid)
22447db96d56Sopenharmony_ci                """)
22457db96d56Sopenharmony_ci            run_interp(interp.id, f"""
22467db96d56Sopenharmony_ci                with helpers.expect_channel_closed():
22477db96d56Sopenharmony_ci                    interpreters.channel_send(cid, b'spam')
22487db96d56Sopenharmony_ci                """)
22497db96d56Sopenharmony_ci            run_interp(interp.id, f"""
22507db96d56Sopenharmony_ci                with helpers.expect_channel_closed():
22517db96d56Sopenharmony_ci                    interpreters.channel_close(cid)
22527db96d56Sopenharmony_ci                """)
22537db96d56Sopenharmony_ci            run_interp(interp.id, f"""
22547db96d56Sopenharmony_ci                with helpers.expect_channel_closed():
22557db96d56Sopenharmony_ci                    interpreters.channel_close(cid, force=True)
22567db96d56Sopenharmony_ci                """)
22577db96d56Sopenharmony_ci
22587db96d56Sopenharmony_ci    def _assert_closed(self, fix):
22597db96d56Sopenharmony_ci        self.assertTrue(fix.state.closed)
22607db96d56Sopenharmony_ci
22617db96d56Sopenharmony_ci        for _ in range(fix.state.pending):
22627db96d56Sopenharmony_ci            interpreters.channel_recv(fix.cid)
22637db96d56Sopenharmony_ci        self._assert_closed_in_interp(fix)
22647db96d56Sopenharmony_ci
22657db96d56Sopenharmony_ci        for interp in ('same', 'other'):
22667db96d56Sopenharmony_ci            interp = fix.get_interpreter(interp)
22677db96d56Sopenharmony_ci            if interp.name == 'main':
22687db96d56Sopenharmony_ci                continue
22697db96d56Sopenharmony_ci            self._assert_closed_in_interp(fix, interp)
22707db96d56Sopenharmony_ci
22717db96d56Sopenharmony_ci        interp = fix.get_interpreter('fresh')
22727db96d56Sopenharmony_ci        self._assert_closed_in_interp(fix, interp)
22737db96d56Sopenharmony_ci
22747db96d56Sopenharmony_ci    def _iter_close_tests(self, verbose=False):
22757db96d56Sopenharmony_ci        i = 0
22767db96d56Sopenharmony_ci        for actions in self.iter_action_sets():
22777db96d56Sopenharmony_ci            print()
22787db96d56Sopenharmony_ci            for fix in self.iter_fixtures():
22797db96d56Sopenharmony_ci                i += 1
22807db96d56Sopenharmony_ci                if i > 1000:
22817db96d56Sopenharmony_ci                    return
22827db96d56Sopenharmony_ci                if verbose:
22837db96d56Sopenharmony_ci                    if (i - 1) % 6 == 0:
22847db96d56Sopenharmony_ci                        print()
22857db96d56Sopenharmony_ci                    print(i, fix, '({} actions)'.format(len(actions)))
22867db96d56Sopenharmony_ci                else:
22877db96d56Sopenharmony_ci                    if (i - 1) % 6 == 0:
22887db96d56Sopenharmony_ci                        print(' ', end='')
22897db96d56Sopenharmony_ci                    print('.', end=''); sys.stdout.flush()
22907db96d56Sopenharmony_ci                yield i, fix, actions
22917db96d56Sopenharmony_ci            if verbose:
22927db96d56Sopenharmony_ci                print('---')
22937db96d56Sopenharmony_ci        print()
22947db96d56Sopenharmony_ci
22957db96d56Sopenharmony_ci    # This is useful for scanning through the possible tests.
22967db96d56Sopenharmony_ci    def _skim_close_tests(self):
22977db96d56Sopenharmony_ci        ChannelCloseFixture.QUICK = True
22987db96d56Sopenharmony_ci        for i, fix, actions in self._iter_close_tests():
22997db96d56Sopenharmony_ci            pass
23007db96d56Sopenharmony_ci
23017db96d56Sopenharmony_ci    def test_close(self):
23027db96d56Sopenharmony_ci        for i, fix, actions in self._iter_close_tests():
23037db96d56Sopenharmony_ci            with self.subTest('{} {}  {}'.format(i, fix, actions)):
23047db96d56Sopenharmony_ci                fix.prep_interpreter(fix.interp)
23057db96d56Sopenharmony_ci                self.run_actions(fix, actions)
23067db96d56Sopenharmony_ci
23077db96d56Sopenharmony_ci                self._close(fix, force=False)
23087db96d56Sopenharmony_ci
23097db96d56Sopenharmony_ci                self._assert_closed(fix)
23107db96d56Sopenharmony_ci            # XXX Things slow down if we have too many interpreters.
23117db96d56Sopenharmony_ci            fix.clean_up()
23127db96d56Sopenharmony_ci
23137db96d56Sopenharmony_ci    def test_force_close(self):
23147db96d56Sopenharmony_ci        for i, fix, actions in self._iter_close_tests():
23157db96d56Sopenharmony_ci            with self.subTest('{} {}  {}'.format(i, fix, actions)):
23167db96d56Sopenharmony_ci                fix.prep_interpreter(fix.interp)
23177db96d56Sopenharmony_ci                self.run_actions(fix, actions)
23187db96d56Sopenharmony_ci
23197db96d56Sopenharmony_ci                self._close(fix, force=True)
23207db96d56Sopenharmony_ci
23217db96d56Sopenharmony_ci                self._assert_closed(fix)
23227db96d56Sopenharmony_ci            # XXX Things slow down if we have too many interpreters.
23237db96d56Sopenharmony_ci            fix.clean_up()
23247db96d56Sopenharmony_ci
23257db96d56Sopenharmony_ci
23267db96d56Sopenharmony_ciif __name__ == '__main__':
23277db96d56Sopenharmony_ci    unittest.main()
2328