# Copyright 2020 Konstruktor, Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import gc
import platform
import time
from unittest import mock
from unittest.mock import patch, call

from pytest import fixture

from tethys.core.pipes.pipe_zero import ZeroPipe
from tethys.core.sessions.sess_zero import ZeroSession
from tethys.core.stations.station_zero import ZeroStation
from tethys.core.streams.stream_zero import ZeroStream
from tethys.core.transports.transport_zero import ZeroTransport


class MockTransport(ZeroTransport):
    def __init__(self):
        pass

    connect = mock.MagicMock()
    disconnect = mock.MagicMock()


class MockSession(ZeroSession):
    closing_mode = None

    def __init__(self):
        self._closed = False

    @property
    def closed(self):
        return self._closed


class MockStation(ZeroStation):
    def __init__(self):
        pass


class TestZeroStream:
    @staticmethod
    def teardown_method():
        MockTransport.connect.reset_mock()
        MockTransport.disconnect.reset_mock()

    @fixture
    def pipe(self):
        pipe = mock.MagicMock(spec=ZeroPipe)
        return pipe

    @fixture
    def session(self):
        session = MockSession()
        return session

    @fixture
    def transport(self):
        return MockTransport()

    @fixture
    def station(self):
        return MockStation()

    @fixture
    def stream(self, pipe, session, transport):
        return ZeroStream(pipe, session, transport)

    # init

    def test_init_with_transport_cb(self, pipe, session, transport):
        def get_transport(_):
            return transport

        get_transport = mock.MagicMock(side_effect=get_transport)

        stream = ZeroStream(pipe, session, get_transport)

        assert stream.transport == transport

    # conn context

    def test_new_connection_context(self, stream):
        with stream.connection_context():
            MockTransport.connect.assert_called_once_with(stream)
            MockTransport.disconnect.assert_not_called()
        MockTransport.disconnect.assert_called_once_with(stream)

    def test_old_connection_context(self, stream):
        MockTransport._connections[stream.id] = stream

        with stream.connection_context():
            MockTransport.connect.assert_not_called()
        MockTransport.disconnect.assert_not_called()

    # heartbeat

    def test_heartbeat_fail_delay(self, stream):
        assert stream.heartbeat_fail_delay == stream.DEFAULT_HEARTBEAT_FAIL_DELAY

        stream.station = mock.MagicMock(spec=ZeroStation)
        stream.station.heartbeat_fail_delay = 0
        assert stream.heartbeat_fail_delay == stream.DEFAULT_HEARTBEAT_FAIL_DELAY

        stream.station.heartbeat_fail_delay = 12345
        assert stream.heartbeat_fail_delay == 12345

    def test_busy_false(self, stream):
        stream.refresh = mock.MagicMock()
        stream.station = mock.MagicMock(spec=ZeroStation)
        stream.station.heartbeat_fail_delay = 1
        stream.heartbeat_ts = time.time() - 10

        assert stream.is_busy is False
        assert stream.refresh.call_count == 1

    def test_busy_true(self, stream):
        stream.refresh = mock.MagicMock()
        stream.station = mock.MagicMock(spec=ZeroStation)
        stream.station.heartbeat_fail_delay = 1000
        stream.heartbeat_ts = time.time()

        assert stream.is_busy is True
        assert stream.refresh.call_count == 1

    def test_heartbeat(self, stream):
        stream.save = mock.MagicMock()

        with patch("time.time", lambda: 12345):
            stream.heartbeat()

        assert stream.heartbeat_ts == 12345
        stream.save.assert_called_once_with(save_dependency=False)

    # open

    def test_open(self, stream):
        stream.save = mock.MagicMock()
        stream.closed = True

        assert stream.open() is stream
        assert stream.closed is False
        stream.save.assert_called_once_with(save_dependency=False)

    def test_open_no_commit(self, stream):
        stream.save = mock.MagicMock()
        stream.closed = True

        assert stream.open(save=False) is stream
        assert stream.closed is False
        stream.save.assert_not_called()

    # close

    def test_close(self, stream):
        stream.save = mock.MagicMock()

        assert stream.close() is stream
        assert stream.closed is True
        stream.save.assert_called_once_with(save_dependency=False)

    def test_close_no_commit(self, stream):
        stream.save = mock.MagicMock()

        assert stream.close(save=False) is stream
        assert stream.closed is True
        stream.save.assert_not_called()

    # read

    def test_read(self, stream):
        data = ["packet", 0, {}, "", None] + [None, "packet"] * 5
        result_data = list(filter(lambda x: x is not None, data))
        iter_data = iter(data)

        def recv_cb(*_, **__):
            try:
                return next(iter_data)
            except StopIteration:
                return ...

        connection_context = mock.MagicMock()
        stream.connection_context = mock.MagicMock(
            side_effect=lambda: connection_context
        )
        stream.transport.recv = mock.MagicMock(side_effect=recv_cb)

        result = []

        for item in stream.read(test_kw=1):
            if item is ...:
                break
            result.append(item)

        if platform.python_implementation().lower() == "pypy":
            gc.collect()

        assert result == result_data
        assert stream.connection_context.call_count == 1
        assert connection_context.__enter__.call_count == 1
        assert connection_context.__exit__.call_count == 1
        stream.transport.recv.assert_has_calls(
            [call(stream, wait_timeout=None, test_kw=1) for _ in data]
        )

    def test_read_n_packets(self, stream):
        iter_data = iter([None, "packet"] + ["packet"] * 10)

        def recv_cb(*_, **__):
            try:
                return next(iter_data)
            except StopIteration:
                return ...

        connection_context = mock.MagicMock()
        stream.connection_context = mock.MagicMock(
            side_effect=lambda: connection_context
        )
        stream.transport.recv = mock.MagicMock(side_effect=recv_cb)

        result = []

        for item in stream.read(count=5, test_kw=1):
            if item is ...:
                break
            result.append(item)

        assert result == ["packet"] * 5
        assert stream.connection_context.call_count == 1
        assert connection_context.__enter__.call_count == 1
        assert connection_context.__exit__.call_count == 1
        stream.transport.recv.assert_has_calls(
            [call(stream, wait_timeout=None, test_kw=1) for _ in range(6)]
        )

    def test_read_while_stream_open(self, stream):
        iter_data = iter(range(10))

        def recv_cb(*_, **__):
            try:
                return next(iter_data)
            except StopIteration:
                return ...

        connection_context = mock.MagicMock()
        stream.connection_context = mock.MagicMock(
            side_effect=lambda: connection_context
        )
        stream.transport.recv = mock.MagicMock(side_effect=recv_cb)

        result = []

        for item in stream.read(test_kw=1):
            if item == 4:
                stream.closed = True

            if item is ...:
                break

            result.append(item)

        assert result == list(range(5))
        assert stream.connection_context.call_count == 1
        assert connection_context.__enter__.call_count == 1
        assert connection_context.__exit__.call_count == 1
        stream.transport.recv.assert_has_calls(
            [call(stream, wait_timeout=None, test_kw=1) for _ in range(5)]
        )

    def test_read_while_sess_open(self, stream):
        stream.session._closed = True

        iter_data = iter([0, 1, 2, 3, None, 4])

        def recv_cb(*_, **__):
            try:
                return next(iter_data)
            except StopIteration:
                return ...

        connection_context = mock.MagicMock()
        stream.connection_context = mock.MagicMock(
            side_effect=lambda: connection_context
        )
        stream.transport.recv = mock.MagicMock(side_effect=recv_cb)

        result = []

        for item in stream.read(test_kw=1):
            if item is ...:
                break

            result.append(item)

        assert result == list(range(4))
        assert stream.connection_context.call_count == 1
        assert connection_context.__enter__.call_count == 1
        assert connection_context.__exit__.call_count == 1
        stream.transport.recv.assert_has_calls(
            [call(stream, wait_timeout=None, test_kw=1) for _ in range(5)]
        )

    def test_read_when_station_changed(self, stream, station):
        iter_data = iter(range(10))

        def recv_cb(*_, **__):
            try:
                return next(iter_data)
            except StopIteration:
                return ...

        connection_context = mock.MagicMock()
        stream.connection_context = mock.MagicMock(
            side_effect=lambda: connection_context
        )
        stream.transport.recv = mock.MagicMock(side_effect=recv_cb)

        result = []

        for item in stream.read(test_kw=1):
            if item == 4:
                stream.station = station

            if item is ...:
                break

            result.append(item)

        assert result == list(range(5))
        assert stream.connection_context.call_count == 1
        assert connection_context.__enter__.call_count == 1
        assert connection_context.__exit__.call_count == 1
        stream.transport.recv.assert_has_calls(
            [call(stream, wait_timeout=None, test_kw=1) for _ in range(5)]
        )

    def test_read_none(self, stream):
        iter_data = iter([None, "packet"] + ["packet"] * 10)

        def recv_cb(*_, **__):
            try:
                return next(iter_data)
            except StopIteration:
                return ...

        connection_context = mock.MagicMock()
        stream.connection_context = mock.MagicMock(
            side_effect=lambda: connection_context
        )
        stream.transport.recv = mock.MagicMock(side_effect=recv_cb)

        result = []

        for item in stream.read(wait_timeout=1, test_kw=1):
            if item is ...:
                break
            result.append(item)

        assert result == []
        assert stream.connection_context.call_count == 1
        assert connection_context.__enter__.call_count == 1
        assert connection_context.__exit__.call_count == 1
        stream.transport.recv.assert_called_once_with(stream, wait_timeout=1, test_kw=1)

    # write

    def test_write(self, stream):
        connection_context = mock.MagicMock()
        stream.connection_context = mock.MagicMock(
            side_effect=lambda: connection_context
        )
        stream.transport.send = mock.MagicMock()

        stream.write("packet", test_kw=1)

        stream.transport.send.assert_called_once_with(stream, "packet", test_kw=1)
        assert stream.connection_context.call_count == 1
        assert connection_context.__enter__.call_count == 1
        assert connection_context.__exit__.call_count == 1

    def test_write_many(self, stream):
        connection_context = mock.MagicMock()
        stream.connection_context = mock.MagicMock(
            side_effect=lambda: connection_context
        )
        stream.transport.send = mock.MagicMock()

        stream.write("packet", many=True, test_kw=1)

        stream.transport.send.assert_has_calls(
            [call(stream, i, test_kw=1) for i in "packet"]
        )
        assert stream.connection_context.call_count == 1
        assert connection_context.__enter__.call_count == 1
        assert connection_context.__exit__.call_count == 1

    def test_write_when_closed(self, stream):
        connection_context = mock.MagicMock()
        stream.connection_context = mock.MagicMock(
            side_effect=lambda: connection_context
        )
        stream.transport.send = mock.MagicMock()
        stream.closed = True

        stream.write("packet", test_kw=1)

        stream.transport.send.assert_not_called()
        stream.connection_context.assert_not_called()
        connection_context.__enter__.assert_not_called()
        connection_context.__exit__.assert_not_called()

    def test_write_out(self, stream):
        connection_context = mock.MagicMock()
        stream.connection_context = mock.MagicMock(
            side_effect=lambda: connection_context
        )
        stream.transport.send = mock.MagicMock()
        stream.closed = True
        stream.pipe.node_b = "<out>"

        stream.write("packet", test_kw=1)

        stream.transport.send.assert_called_once_with(stream, "packet", test_kw=1)
        assert stream.connection_context.call_count == 1
        assert connection_context.__enter__.call_count == 1
        assert connection_context.__exit__.call_count == 1

    # ack

    def test_ack(self, stream):
        stream.transport.ack = mock.MagicMock()

        stream.ack("message", test_kw=1)

        stream.transport.ack.assert_called_once_with(stream, "message", test_kw=1)

    def test_ack_closed(self, stream):
        stream.closed = True
        stream.transport.ack = mock.MagicMock()

        stream.ack("message", test_kw=1)

        stream.transport.ack.assert_not_called()

    # redirect

    def test_redirect(self, stream, station):
        station.save = mock.MagicMock()
        station.stream_lock_ttl = 0

        stream.save = mock.MagicMock()

        stream.redirect_to(station)

        assert stream.station == station
        station.save.assert_called_once_with(save_dependency=False)
        stream.save.assert_called_once_with(save_dependency=False)

    # open/close context

    def test_context(self, stream):
        stream.open = mock.MagicMock()
        stream.close = mock.MagicMock()

        with stream:
            stream.open.assert_called_once_with(save=False)
            stream.close.assert_not_called()
        stream.close.assert_called_once_with(save=False)

[((1104, 1120), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {}), '()\n', (1118, 1120), False, 'from unittest import mock\n'), ((1138, 1154), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {}), '()\n', (1152, 1154), False, 'from unittest import mock\n'), ((1610, 1639), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {'spec': 'ZeroPipe'}), '(spec=ZeroPipe)\n', (1624, 1639), False, 'from unittest import mock\n'), ((1965, 2001), 'tethys.core.streams.stream_zero.ZeroStream', 'ZeroStream', (['pipe', 'session', 'transport'], {}), '(pipe, session, transport)\n', (1975, 2001), False, 'from tethys.core.streams.stream_zero import ZeroStream\n'), ((2168, 2209), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {'side_effect': 'get_transport'}), '(side_effect=get_transport)\n', (2182, 2209), False, 'from unittest import mock\n'), ((2228, 2268), 'tethys.core.streams.stream_zero.ZeroStream', 'ZeroStream', (['pipe', 'session', 'get_transport'], {}), '(pipe, session, get_transport)\n', (2238, 2268), False, 'from tethys.core.streams.stream_zero import ZeroStream\n'), ((3049, 3081), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {'spec': 'ZeroStation'}), '(spec=ZeroStation)\n', (3063, 3081), False, 'from unittest import mock\n'), ((3382, 3398), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {}), '()\n', (3396, 3398), False, 'from unittest import mock\n'), ((3424, 3456), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {'spec': 'ZeroStation'}), '(spec=ZeroStation)\n', (3438, 3456), False, 'from unittest import mock\n'), ((3702, 3718), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {}), '()\n', (3716, 3718), False, 'from unittest import mock\n'), ((3744, 3776), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {'spec': 'ZeroStation'}), '(spec=ZeroStation)\n', (3758, 3776), False, 'from unittest import mock\n'), ((3858, 3869), 'time.time', 'time.time', ([], {}), '()\n', (3867, 3869), False, 'import time\n'), ((4016, 4032), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {}), '()\n', (4030, 4032), False, 'from unittest import mock\n'), ((4293, 4309), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {}), '()\n', (4307, 4309), False, 'from unittest import mock\n'), ((4550, 4566), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {}), '()\n', (4564, 4566), False, 'from unittest import mock\n'), ((4794, 4810), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {}), '()\n', (4808, 4810), False, 'from unittest import mock\n'), ((5023, 5039), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {}), '()\n', (5037, 5039), False, 'from unittest import mock\n'), ((5556, 5572), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {}), '()\n', (5570, 5572), False, 'from unittest import mock\n'), ((5609, 5664), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {'side_effect': '(lambda : connection_context)'}), '(side_effect=lambda : connection_context)\n', (5623, 5664), False, 'from unittest import mock\n'), ((5718, 5753), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {'side_effect': 'recv_cb'}), '(side_effect=recv_cb)\n', (5732, 5753), False, 'from unittest import mock\n'), ((6618, 6634), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {}), '()\n', (6632, 6634), False, 'from unittest import mock\n'), ((6671, 6726), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {'side_effect': '(lambda : connection_context)'}), '(side_effect=lambda : connection_context)\n', (6685, 6726), False, 'from unittest import mock\n'), ((6780, 6815), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {'side_effect': 'recv_cb'}), '(side_effect=recv_cb)\n', (6794, 6815), False, 'from unittest import mock\n'), ((7590, 7606), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {}), '()\n', (7604, 7606), False, 'from unittest import mock\n'), ((7643, 7698), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {'side_effect': '(lambda : connection_context)'}), '(side_effect=lambda : connection_context)\n', (7657, 7698), False, 'from unittest import mock\n'), ((7752, 7787), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {'side_effect': 'recv_cb'}), '(side_effect=recv_cb)\n', (7766, 7787), False, 'from unittest import mock\n'), ((8667, 8683), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {}), '()\n', (8681, 8683), False, 'from unittest import mock\n'), ((8720, 8775), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {'side_effect': '(lambda : connection_context)'}), '(side_effect=lambda : connection_context)\n', (8734, 8775), False, 'from unittest import mock\n'), ((8829, 8864), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {'side_effect': 'recv_cb'}), '(side_effect=recv_cb)\n', (8843, 8864), False, 'from unittest import mock\n'), ((9643, 9659), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {}), '()\n', (9657, 9659), False, 'from unittest import mock\n'), ((9696, 9751), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {'side_effect': '(lambda : connection_context)'}), '(side_effect=lambda : connection_context)\n', (9710, 9751), False, 'from unittest import mock\n'), ((9805, 9840), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {'side_effect': 'recv_cb'}), '(side_effect=recv_cb)\n', (9819, 9840), False, 'from unittest import mock\n'), ((10687, 10703), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {}), '()\n', (10701, 10703), False, 'from unittest import mock\n'), ((10740, 10795), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {'side_effect': '(lambda : connection_context)'}), '(side_effect=lambda : connection_context)\n', (10754, 10795), False, 'from unittest import mock\n'), ((10849, 10884), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {'side_effect': 'recv_cb'}), '(side_effect=recv_cb)\n', (10863, 10884), False, 'from unittest import mock\n'), ((11420, 11436), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {}), '()\n', (11434, 11436), False, 'from unittest import mock\n'), ((11473, 11528), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {'side_effect': '(lambda : connection_context)'}), '(side_effect=lambda : connection_context)\n', (11487, 11528), False, 'from unittest import mock\n'), ((11582, 11598), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {}), '()\n', (11596, 11598), False, 'from unittest import mock\n'), ((11971, 11987), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {}), '()\n', (11985, 11987), False, 'from unittest import mock\n'), ((12024, 12079), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {'side_effect': '(lambda : connection_context)'}), '(side_effect=lambda : connection_context)\n', (12038, 12079), False, 'from unittest import mock\n'), ((12133, 12149), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {}), '()\n', (12147, 12149), False, 'from unittest import mock\n'), ((12574, 12590), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {}), '()\n', (12588, 12590), False, 'from unittest import mock\n'), ((12627, 12682), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {'side_effect': '(lambda : connection_context)'}), '(side_effect=lambda : connection_context)\n', (12641, 12682), False, 'from unittest import mock\n'), ((12736, 12752), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {}), '()\n', (12750, 12752), False, 'from unittest import mock\n'), ((13111, 13127), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {}), '()\n', (13125, 13127), False, 'from unittest import mock\n'), ((13164, 13219), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {'side_effect': '(lambda : connection_context)'}), '(side_effect=lambda : connection_context)\n', (13178, 13219), False, 'from unittest import mock\n'), ((13273, 13289), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {}), '()\n', (13287, 13289), False, 'from unittest import mock\n'), ((13734, 13750), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {}), '()\n', (13748, 13750), False, 'from unittest import mock\n'), ((13977, 13993), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {}), '()\n', (13991, 13993), False, 'from unittest import mock\n'), ((14172, 14188), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {}), '()\n', (14186, 14188), False, 'from unittest import mock\n'), ((14248, 14264), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {}), '()\n', (14262, 14264), False, 'from unittest import mock\n'), ((14564, 14580), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {}), '()\n', (14578, 14580), False, 'from unittest import mock\n'), ((14604, 14620), 'unittest.mock.MagicMock', 'mock.MagicMock', ([], {}), '()\n', (14618, 14620), False, 'from unittest import mock\n'), ((3535, 3546), 'time.time', 'time.time', ([], {}), '()\n', (3544, 3546), False, 'import time\n'), ((4047, 4081), 'unittest.mock.patch', 'patch', (['"""time.time"""', '(lambda : 12345)'], {}), "('time.time', lambda : 12345)\n", (4052, 4081), False, 'from unittest.mock import patch, call\n'), ((5978, 5990), 'gc.collect', 'gc.collect', ([], {}), '()\n', (5988, 5990), False, 'import gc\n'), ((6266, 6308), 'unittest.mock.call', 'call', (['stream'], {'wait_timeout': 'None', 'test_kw': '(1)'}), '(stream, wait_timeout=None, test_kw=1)\n', (6270, 6308), False, 'from unittest.mock import patch, call\n'), ((7251, 7293), 'unittest.mock.call', 'call', (['stream'], {'wait_timeout': 'None', 'test_kw': '(1)'}), '(stream, wait_timeout=None, test_kw=1)\n', (7255, 7293), False, 'from unittest.mock import patch, call\n'), ((8279, 8321), 'unittest.mock.call', 'call', (['stream'], {'wait_timeout': 'None', 'test_kw': '(1)'}), '(stream, wait_timeout=None, test_kw=1)\n', (8283, 8321), False, 'from unittest.mock import patch, call\n'), ((9292, 9334), 'unittest.mock.call', 'call', (['stream'], {'wait_timeout': 'None', 'test_kw': '(1)'}), '(stream, wait_timeout=None, test_kw=1)\n', (9296, 9334), False, 'from unittest.mock import patch, call\n'), ((10336, 10378), 'unittest.mock.call', 'call', (['stream'], {'wait_timeout': 'None', 'test_kw': '(1)'}), '(stream, wait_timeout=None, test_kw=1)\n', (10340, 10378), False, 'from unittest.mock import patch, call\n'), ((12266, 12292), 'unittest.mock.call', 'call', (['stream', 'i'], {'test_kw': '(1)'}), '(stream, i, test_kw=1)\n', (12270, 12292), False, 'from unittest.mock import patch, call\n'), ((5914, 5946), 'platform.python_implementation', 'platform.python_implementation', ([], {}), '()\n', (5944, 5946), False, 'import platform\n')]