text: import sys
  import io
  import uuid
  
  from unittest import mock, TestCase
  
  from reppy.robots import Robots
  from reppy.exceptions import ReppyException
  
  from lib.monad.either import Left, Right
  
  from daddicts_spider import *
  
  
  class FakeRobots():
      def fetch(self, url):
          raise ReppyException({'obj': self, 'url': url})
  
  
  class FakeCLIArgs(object):
      def __init__(self, fake_cli_args):
          self.fake_cli_args = fake_cli_args
  
      def __enter__(self):
          self.argv = sys.argv
          sys.argv = ['daddicts_spider.py'] + self.fake_cli_args
          return self.argv
  
      def __exit__(self, *_):
          sys.argv = self.argv
  
  
  class FakeparsedCLIArgs():
      def __init__(self, delay=None, take=None, crawl=None):
          self.delay = delay
          self.take = take
          self.crawl = crawl
  
  
  class MemStdOut(object):
      def __enter__(self):
          self.stdout = sys.stdout
          sys.stdout = io.StringIO()
          return sys.stdout
  
      def __exit__(self, *_):
          sys.stdout = self.stdout
  
  
  class TopLevelTest(TestCase):
      def test_unsorted_group_by(self):
          tag_file_or_page_link = ABCSpider.tag_file_or_page_link
          links = {"d.com/1file.php?id=", "d.com/page1", "d.com/page2"}
          self.assertCountEqual(unsorted_group_by(links, tag_file_or_page_link),
                                {'subs': ["d.com/1file.php?id="],
                                 'pages': ["d.com/page1", "d.com/page2"]})
  
      def test_take_opt_main(self):
          cli_args = FakeparsedCLIArgs(delay=0, take=2)
          with MemStdOut() as stdo:
              main(cli_args)
              main_out = stdo.getvalue()
              link_common_part = 'http://www.d-addicts.com/forums/download/file.php?id='
              self.assertGreaterEqual(main_out.count(link_common_part), 2)
  
      def test_crawl_opt_main(self):
          cli_args = FakeparsedCLIArgs(delay=0, crawl=1)
          file_persistable_set = FilePersistableSet('daddicts_page_links.txt', set())
          with MemStdOut():
              main(cli_args)
              count_pages_before = len(file_persistable_set.retrieve())
              main(cli_args)
              count_pages_after = len(file_persistable_set.retrieve())
              self.assertEqual(count_pages_before - count_pages_after, 1)
  
  
  class PathTest(TestCase):
      def test_is_file_with_content(self):
          path = Path(str(uuid.uuid4()))
          self.assertFalse(path.is_file_with_content())
          path.touch()
          self.assertFalse(path.is_file_with_content())
          path.write_text('random content')
          self.assertTrue(path.is_file_with_content())
          path.unlink()
  
  
  class FilePersistableSetTest(TestCase):
      def test_repr(self):
          rand_filename = str(uuid.uuid4())
          file_persistable_set = FilePersistableSet(rand_filename, set())
          file_persistable_set_repr = repr(file_persistable_set)
          self.assertEqual(file_persistable_set_repr, "")
          file_persistable_set = FilePersistableSet(rand_filename, {1})
          file_persistable_set_repr = repr(file_persistable_set)
          self.assertEqual(file_persistable_set_repr, '{1}')
  
      def integration_test(self):
          rand_filename = str(uuid.uuid4())
          file_persistable_set = FilePersistableSet(rand_filename, {1, 2})
          self.assertFalse(file_persistable_set.retrieve())
          file_persistable_set.persist()
          self.assertEqual(file_persistable_set.retrieve(), {1, 2})
          Path(rand_filename).unlink()
  
  
  class FileLinkStoreTest(TestCase):
      def test_file_link_store_update(self):
          file_link_store = FileLinkStore()
          links = file_link_store.update({'d.co/file.php?id=1'})
          self.assertSetEqual(links, {'d.co/file.php?id=1'})
          links = file_link_store.update({'d.co/file.php?id=1', 'd.co/file.php?id=2'})
          self.assertSetEqual(links, {'d.co/file.php?id=2'})
  
      def test_file_link_store_can_take(self):
          can_always_take_file_link_store = FileLinkStore()
          self.assertTrue(can_always_take_file_link_store)
          can_take_file_link_store = FileLinkStore(1)
          self.assertTrue(can_take_file_link_store.can_take())
          cant_take_file_link_store = FileLinkStore(0)
          self.assertFalse(cant_take_file_link_store.can_take())
  
  
  class ABCSpiderTest(TestCase):
      def test_tag_file_or_page_link(self):
          tag_file_or_page_link = ABCSpider.tag_file_or_page_link
          self.assertEqual(tag_file_or_page_link('d.com/file.php?id='), 'subs')
          self.assertEqual(tag_file_or_page_link('d.com/page1'), 'pages')
  
      def test_group_links(self):
          group_links = ABCSpider.group_links
          self.assertSetEqual(group_links({"d.co/p1"}).get('subs'), set())
          self.assertSetEqual(group_links({"d.co/file.php?id="}).get('pages'), set())
          self.assertSetEqual(group_links({"d.co/p1"}).get('pages'), {"d.co/p1"})
  
      def test_robots_delay(self):  # TODO impl. monad either to test l/r branch
          get_robots_delay = ABCSpider.get_robots_delay
          robots_delay = get_robots_delay('http://www.d-addicts.com')
          self.assertTrue(isinstance(robots_delay, Right))
          self.assertGreaterEqual(robots_delay.getValue(), 0)
          with mock.patch('daddicts_spider.Robots', new_callable=FakeRobots):
              self.assertEqual(get_robots_delay('http://www.d-addicts.com'), Left(None))
  
      def test_choose_delay(self):
          get_robots_delay = ABCSpider.get_robots_delay
          choose_delay = ABCSpider.choose_delay
          default_delay = ABCSpider.default_delay
          self.assertEqual(choose_delay(0, 'http://www.d-addicts.com'), Right(0))
          self.assertEqual(choose_delay(None, 'http://www.d-addicts.com').getValue(),
                           get_robots_delay('http://www.d-addicts.com').getValue())
          self.assertEqual(choose_delay(0, 'bad_website'), Right(0))
          self.assertEqual(choose_delay(None, 'bad_website'), Left(default_delay))
  
  
  class DAddictsSpiderTest(TestCase):
      def test_extract_topic_links(self):
          filename = 'tests/resources/d_addicts_base_page.html'
          with open(filename, encoding='UTF-8') as file:
              links = DAddictsSpider.extract_topic_links(file.read())
              self.assertGreater(len(links), 543)
              for link in links:
                  self.assertIn('www.d-addicts.com/forums/viewtopic.php?t=', link)
  
      def test_extract_links_of_interest(self):
          filename = 'tests/resources/viewtopic.php?t=99358'
          with open(filename, encoding='UTF-8') as file:
              links = DAddictsSpider.extract_links_of_interest(file.read())
              self.assertGreater(len(links), 8)
              for link in links:
                  self.assertIn(DAddictsSpider.file_of_interest_subs, link)
  
      def test_complete_link(self):
          rel_link = './download/file.php?id=51885&sid=09fccbbc6636ee1d35b7f021384574ce'
          link = 'http://www.d-addicts.com/forums/download/file.php?id=51885'
          self.assertEqual(DAddictsSpider.complete_link(rel_link), link)
  
      def test_next(self):
          self.assertIn('/download/file.php?id=', next(DAddictsSpider(0)).pop())
  
  
  class AppArgParserTest(TestCase):
      def test_each_arg(self):
          with FakeCLIArgs(['--crawl', '5']):
              cli_args = AppArgParser().parse_args()
              self.assertEqual(cli_args.crawl, 5)
  
          with FakeCLIArgs(['--take', '2']):
              cli_args = AppArgParser().parse_args()
              self.assertEqual(cli_args.take, 2)
  
      def test_arg_combinations(self):
          with FakeCLIArgs(['--delay', '1', '--crawl', '5']):
              cli_args = AppArgParser().parse_args()
              self.assertEqual(cli_args.delay, 1)
              self.assertEqual(cli_args.crawl, 5)
  
          with FakeCLIArgs(['--delay', '1', '--take', '2']):
              cli_args = AppArgParser().parse_args()
              self.assertEqual(cli_args.delay, 1)
              self.assertEqual(cli_args.take, 2)
  