# Path: oslash/ioaction.py
# class Put(IO[TSource]):
#     """The Put action.
# 
#     A container holding a string to be printed to stdout, followed by
#     another IO Action.
#     """
# 
#     def __init__(self, text: str, io: IO) -> None:
#         self._value = text, io
# 
#     def bind(self, func: Callable[[TSource], IO[TResult]]) -> 'IO[TResult]':
#         """IO a -> (a -> IO b) -> IO b"""
# 
#         text, io = self._value
#         return Put(text, io.bind(func))
# 
#     def map(self, func: Callable[[TSource], TResult]) -> "IO[TResult]":
#         # Put s (fmap f io)
#         assert self._value is not None
#         text, action = self._value
#         return Put(text, action.map(func))
# 
#     def run(self, world: int) -> TSource:
#         """Run IO action"""
# 
#         assert self._value is not None
#         text, action = self._value
#         new_world = pure_print(world, text)
#         return action(world=new_world)
# 
#     def __call__(self, world: int = 0) -> TSource:
#         return self.run(world)
# 
#     def __str__(self, m: int = 0, n: int = 0) -> str:
#         s, io = self._value
#         a = io.__str__(m + 1, n)
#         return '%sPut ("%s",\n%s\n%s)' % (ind(m), s, a, ind(m))
# 
# class Return(IO[TSource]):
#     def __init__(self, value: TSource) -> None:
#         """Create IO Action."""
# 
#         self._value = value
# 
#     def map(self, func: Callable[[TSource], TResult]) -> "IO[TResult]":
#         return Return(func(self._value))
# 
#     def bind(self, func: Callable[[TSource], "IO[TResult]"]) -> "IO[TResult]":
#         """IO a -> (a -> IO b) -> IO b."""
# 
#         return func(self._value)
# 
#     def run(self, world: int) -> TSource:
#         """Run IO action."""
#         return self._value
# 
#     def __str__(self, m: int = 0, n: int = 0) -> str:
#         a = self._value
#         return f"{ind(m)}Return {a}"
# 
# def put_line(text: str) -> IO:
#     return Put(text, Return(Unit))
# 
# def get_line() -> IO[str]:
#     return Get(Return)
# 
# Path: oslash/util/basic.py
# def indent(level, size=2):


import unittest
import oslash.ioaction
from typing import Tuple, Optional
from oslash import Put, Return, put_line, get_line
from oslash.util import Unit


class MyMock:
    """Mock for testing side effects"""

    def __init__(self) -> None:
        self.value: Optional[str] = None
        oslash.ioaction.pure_input = self.pure_input
        oslash.ioaction.pure_print = self.pure_print

    def pure_print(self, world: int, text: str) -> int:
        self.value = text
        return world + 1

    def pure_input(self, world: int) -> Tuple[int, str]:
        text = self.value
        new_world = world + 1
        return new_world, text


class TestPut(unittest.TestCase):

    def test_put_line(self) -> None:
        pm = MyMock()
        action = put_line("hello, world!")
        action()
        self.assertEqual(pm.value, "hello, world!")

    def test_put_return(self) -> None:
        pm = MyMock()

# Path: oslash/ioaction.py
# class Put(IO[TSource]):
#     """The Put action.
# 
#     A container holding a string to be printed to stdout, followed by
#     another IO Action.
#     """
# 
#     def __init__(self, text: str, io: IO) -> None:
#         self._value = text, io
# 
#     def bind(self, func: Callable[[TSource], IO[TResult]]) -> 'IO[TResult]':
#         """IO a -> (a -> IO b) -> IO b"""
# 
#         text, io = self._value
#         return Put(text, io.bind(func))
# 
#     def map(self, func: Callable[[TSource], TResult]) -> "IO[TResult]":
#         # Put s (fmap f io)
#         assert self._value is not None
#         text, action = self._value
#         return Put(text, action.map(func))
# 
#     def run(self, world: int) -> TSource:
#         """Run IO action"""
# 
#         assert self._value is not None
#         text, action = self._value
#         new_world = pure_print(world, text)
#         return action(world=new_world)
# 
#     def __call__(self, world: int = 0) -> TSource:
#         return self.run(world)
# 
#     def __str__(self, m: int = 0, n: int = 0) -> str:
#         s, io = self._value
#         a = io.__str__(m + 1, n)
#         return '%sPut ("%s",\n%s\n%s)' % (ind(m), s, a, ind(m))
# 
# class Return(IO[TSource]):
#     def __init__(self, value: TSource) -> None:
#         """Create IO Action."""
# 
#         self._value = value
# 
#     def map(self, func: Callable[[TSource], TResult]) -> "IO[TResult]":
#         return Return(func(self._value))
# 
#     def bind(self, func: Callable[[TSource], "IO[TResult]"]) -> "IO[TResult]":
#         """IO a -> (a -> IO b) -> IO b."""
# 
#         return func(self._value)
# 
#     def run(self, world: int) -> TSource:
#         """Run IO action."""
#         return self._value
# 
#     def __str__(self, m: int = 0, n: int = 0) -> str:
#         a = self._value
#         return f"{ind(m)}Return {a}"
# 
# def put_line(text: str) -> IO:
#     return Put(text, Return(Unit))
# 
# def get_line() -> IO[str]:
#     return Get(Return)
# 
# Path: oslash/util/basic.py
# def indent(level, size=2):


# Path: tests/test_ioaction.py
import unittest
import oslash.ioaction
from typing import Tuple, Optional
from oslash import Put, Return, put_line, get_line
from oslash.util import Unit



class MyMock:
    """Mock for testing side effects"""

    def __init__(self) -> None:
        self.value: Optional[str] = None
        oslash.ioaction.pure_input = self.pure_input
        oslash.ioaction.pure_print = self.pure_print

    def pure_print(self, world: int, text: str) -> int:
        self.value = text
        return world + 1

    def pure_input(self, world: int) -> Tuple[int, str]:
        text = self.value
        new_world = world + 1
        return new_world, text


class TestPut(unittest.TestCase):

    def test_put_line(self) -> None:
        pm = MyMock()
        action = put_line("hello, world!")
        action()
        self.assertEqual(pm.value, "hello, world!")

    def test_put_return(self) -> None:
        pm = MyMock()

        action: Put = Put("hello, world!", Return(Unit))