text: from unittest.mock import call, patch
  
  from .test_fetch import FlickrFetchTestCase
  from ditto.flickr.fetch import FetchError
  from ditto.flickr.fetch.fetchers import PhotosetsFetcher, RecentPhotosFetcher
  from ditto.flickr.fetch.filesfetchers import OriginalFilesFetcher
  from ditto.flickr.fetch.multifetchers import (
      MultiAccountFetcher,
      OriginalFilesMultiAccountFetcher,
      PhotosetsMultiAccountFetcher,
      RecentPhotosMultiAccountFetcher,
  )
  from ditto.flickr.factories import AccountFactory, UserFactory
  
  
  class MultiAccountFetcherTestCase(FlickrFetchTestCase):
      def setUp(self):
          self.account_1 = AccountFactory(
              api_key="1234", api_secret="9876", user=UserFactory(nsid="35034346050@N01")
          )
          self.inactive_account = AccountFactory(
              api_key="2345",
              api_secret="8765",
              is_active=False,
              user=UserFactory(nsid="12345678901@N01"),
          )
          self.account_2 = AccountFactory(
              api_key="3456", api_secret="7654", user=UserFactory(nsid="98765432101@N01")
          )
  
      def tearDown(self):
          pass
  
      def test_inherits_from_multi_account_fetcher(self):
          self.assertTrue(
              issubclass(RecentPhotosMultiAccountFetcher, MultiAccountFetcher)
          )
  
      def test_fetch_throws_exception(self):
          "Throws an exception if its own fetch() method is called."
          with self.assertRaises(FetchError):
              MultiAccountFetcher().fetch()
  
      def test_uses_all_accounts_by_default(self):
          fetcher = MultiAccountFetcher()
          self.assertEqual(len(fetcher.accounts), 2)
  
      def test_throws_exception_with_no_active_accounts(self):
          self.account_1.is_active = False
          self.account_2.is_active = False
          self.account_1.save()
          self.account_2.save()
          with self.assertRaises(FetchError):
              MultiAccountFetcher()
  
      def test_throws_exception_with_invalid_nsid(self):
          with self.assertRaises(FetchError):
              MultiAccountFetcher(nsid="nope")
  
      def test_throws_exception_with_no_account(self):
          "If the NSID is not attached to an Account."
          UserFactory(nsid="99999999999@N01")
          with self.assertRaises(FetchError):
              MultiAccountFetcher(nsid="99999999999@N01")
  
      def test_throws_exception_with_inactive_account(self):
          with self.assertRaises(FetchError):
              MultiAccountFetcher(nsid="12345678901@N01")
  
      def test_works_with_valid_nsid(self):
          fetcher = MultiAccountFetcher(nsid="35034346050@N01")
          self.assertEqual(len(fetcher.accounts), 1)
          self.assertEqual(fetcher.accounts[0], self.account_1)
  
  
  class RecentPhotosMultiAccountFetcherTestCase(MultiAccountFetcherTestCase):
      @patch.object(RecentPhotosFetcher, "__init__")
      @patch.object(RecentPhotosFetcher, "fetch")
      def test_inits_fetcher_with_active_accounts(self, fetch, init):
          "RecentPhotosFetcher should be called with 2 active accounts."
          init.return_value = None
          RecentPhotosMultiAccountFetcher().fetch()
          init.assert_has_calls([call(self.account_1), call(self.account_2)])
  
      @patch.object(RecentPhotosFetcher, "fetch")
      def test_calls_fetch_for_active_accounts(self, fetch):
          "RecentPhotosFetcher.fetch() should be called twice."
          RecentPhotosMultiAccountFetcher().fetch(days=3)
          fetch.assert_has_calls([call(days=3), call(days=3)])
  
      @patch.object(RecentPhotosFetcher, "fetch")
      def test_returns_list_of_return_values(self, fetch):
          "Should return a list of the dicts that RecentPhotosFetcher.fetch() returns"
          ret = {"success": True, "account": "bob", "fetched": 7}
          fetch.side_effect = [ret, ret]
  
          return_value = RecentPhotosMultiAccountFetcher().fetch(days=3)
  
          self.assertEqual(len(return_value), 2)
          self.assertEqual(return_value[0]["account"], "bob")
  
  
  class PhotosetsMultiAccountFetcherTestCase(MultiAccountFetcherTestCase):
      @patch.object(PhotosetsFetcher, "__init__")
      @patch.object(PhotosetsFetcher, "fetch")
      def test_inits_fetcher_with_active_accounts(self, fetch, init):
          "PhotosetsFetcher should be called with 2 active accounts."
          init.return_value = None
          PhotosetsMultiAccountFetcher().fetch()
          init.assert_has_calls([call(self.account_1), call(self.account_2)])
  
      @patch.object(PhotosetsFetcher, "fetch")
      def test_calls_fetch_for_active_accounts(self, fetch):
          "PhotosetsFetcher.fetch() should be called twice."
          PhotosetsMultiAccountFetcher().fetch()
          fetch.assert_has_calls([call(), call()])
  
      @patch.object(PhotosetsFetcher, "fetch")
      def test_returns_list_of_return_values(self, fetch):
          "Should return a list of the dicts that PhotosetsFetcher.fetch() returns"
          ret = {"success": True, "account": "bob", "fetched": 7}
          fetch.side_effect = [ret, ret]
  
          return_value = PhotosetsMultiAccountFetcher().fetch()
  
          self.assertEqual(len(return_value), 2)
          self.assertEqual(return_value[0]["account"], "bob")
  
  
  class OriginalFilesMultiAccountFetcherTestCase(MultiAccountFetcherTestCase):
      @patch.object(OriginalFilesFetcher, "__init__")
      @patch.object(OriginalFilesFetcher, "fetch")
      def test_inits_fetcher_with_active_accounts(self, fetch, init):
          "OriginalFilesFetcher should be called with 2 active accounts."
          init.return_value = None
          OriginalFilesMultiAccountFetcher().fetch()
          init.assert_has_calls([call(self.account_1), call(self.account_2)])
  
      @patch.object(OriginalFilesFetcher, "fetch")
      def test_calls_fetch_for_active_accounts(self, fetch):
          "OriginalFilesFetcher.fetch() should be called twice."
          OriginalFilesMultiAccountFetcher().fetch()
          fetch.assert_has_calls([call(fetch_all=False), call(fetch_all=False)])
  
      @patch.object(OriginalFilesFetcher, "fetch")
      def test_calls_fetch_with_fetch_all_param(self, fetch):
          "fetch() should pass on the fetch_all param"
          OriginalFilesMultiAccountFetcher().fetch(fetch_all=True)
          fetch.assert_has_calls([call(fetch_all=True), call(fetch_all=True)])
  
      @patch.object(OriginalFilesFetcher, "fetch")
      def test_returns_list_of_return_values(self, fetch):
          "Should return a list of the dicts that OriginalFilesFetcher.fetch() returns"
          ret = {"success": True, "account": "bob", "fetched": 7}
          fetch.side_effect = [ret, ret]
  
          return_value = OriginalFilesMultiAccountFetcher().fetch()
  
          self.assertEqual(len(return_value), 2)
          self.assertEqual(return_value[0]["account"], "bob")
  