text: # -*- coding: utf-8 -*-
  #
  # Copyright 2017 Google, Inc
  #
  # SPDX-License-Identifier:	GPL-2.0+
  #
  
  import contextlib
  import os
  import re
  import shutil
  import sys
  import tempfile
  import unittest
  
  import gitutil
  import patchstream
  import settings
  
  
  @contextlib.contextmanager
  def capture():
      import sys
      from cStringIO import StringIO
      oldout,olderr = sys.stdout, sys.stderr
      try:
          out=[StringIO(), StringIO()]
          sys.stdout,sys.stderr = out
          yield out
      finally:
          sys.stdout,sys.stderr = oldout, olderr
          out[0] = out[0].getvalue()
          out[1] = out[1].getvalue()
  
  
  class TestFunctional(unittest.TestCase):
      def setUp(self):
          self.tmpdir = tempfile.mkdtemp(prefix='patman.')
  
      def tearDown(self):
          shutil.rmtree(self.tmpdir)
  
      @staticmethod
      def GetPath(fname):
          return os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),
                              'test', fname)
  
      @classmethod
      def GetText(self, fname):
          return open(self.GetPath(fname)).read()
  
      @classmethod
      def GetPatchName(self, subject):
          fname = re.sub('[ :]', '-', subject)
          return fname.replace('--', '-')
  
      def CreatePatchesForTest(self, series):
          cover_fname = None
          fname_list = []
          for i, commit in enumerate(series.commits):
              clean_subject = self.GetPatchName(commit.subject)
              src_fname = '%04d-%s.patch' % (i + 1, clean_subject[:52])
              fname = os.path.join(self.tmpdir, src_fname)
              shutil.copy(self.GetPath(src_fname), fname)
              fname_list.append(fname)
          if series.get('cover'):
              src_fname = '0000-cover-letter.patch'
              cover_fname = os.path.join(self.tmpdir, src_fname)
              fname = os.path.join(self.tmpdir, src_fname)
              shutil.copy(self.GetPath(src_fname), fname)
  
          return cover_fname, fname_list
  
      def testBasic(self):
          """Tests the basic flow of patman
  
          This creates a series from some hard-coded patches build from a simple
          tree with the following metadata in the top commit:
  
              Series-to: u-boot
              Series-prefix: RFC
              Series-cc: Stefan Brüns <stefan.bruens@rwth-aachen.de>
              Cover-letter-cc: Lord Mëlchett <clergy@palace.gov>
              Series-version: 2
              Series-changes: 4
              - Some changes
  
              Cover-letter:
              test: A test patch series
              This is a test of how the cover
              leter
              works
              END
  
          and this in the first commit:
  
              Series-notes:
              some notes
              about some things
              from the first commit
              END
  
              Commit-notes:
              Some notes about
              the first commit
              END
  
          with the following commands:
  
             git log -n2 --reverse >/path/to/tools/patman/test/test01.txt
             git format-patch --subject-prefix RFC --cover-letter HEAD~2
             mv 00* /path/to/tools/patman/test
  
          It checks these aspects:
              - git log can be processed by patchstream
              - emailing patches uses the correct command
              - CC file has information on each commit
              - cover letter has the expected text and subject
              - each patch has the correct subject
              - dry-run information prints out correctly
              - unicode is handled correctly
              - Series-to, Series-cc, Series-prefix, Cover-letter
              - Cover-letter-cc, Series-version, Series-changes, Series-notes
              - Commit-notes
          """
          process_tags = True
          ignore_bad_tags = True
          stefan = u'Stefan Brüns <stefan.bruens@rwth-aachen.de>'
          rick = 'Richard III <richard@palace.gov>'
          mel = u'Lord Mëlchett <clergy@palace.gov>'
          ed = u'Lond Edmund Blackaddër <weasel@blackadder.org'
          fred = 'Fred Bloggs <f.bloggs@napier.net>'
          add_maintainers = [stefan, rick]
          dry_run = True
          in_reply_to = mel
          count = 2
          settings.alias = {
                  'fdt': ['simon'],
                  'u-boot': ['u-boot@lists.denx.de'],
                  'simon': [ed],
                  'fred': [fred],
          }
  
          text = self.GetText('test01.txt')
          series = patchstream.GetMetaDataForTest(text)
          cover_fname, args = self.CreatePatchesForTest(series)
          with capture() as out:
              patchstream.FixPatches(series, args)
              if cover_fname and series.get('cover'):
                  patchstream.InsertCoverLetter(cover_fname, series, count)
              series.DoChecks()
              cc_file = series.MakeCcFile(process_tags, cover_fname,
                                          not ignore_bad_tags, add_maintainers)
              cmd = gitutil.EmailPatches(series, cover_fname, args,
                      dry_run, not ignore_bad_tags, cc_file,
                      in_reply_to=in_reply_to, thread=None)
              series.ShowActions(args, cmd, process_tags)
          cc_lines = open(cc_file).read().splitlines()
          os.remove(cc_file)
  
          lines = out[0].splitlines()
          #print '\n'.join(lines)
          self.assertEqual('Cleaned %s patches' % len(series.commits), lines[0])
          self.assertEqual('Change log missing for v2', lines[1])
          self.assertEqual('Change log missing for v3', lines[2])
          self.assertEqual('Change log for unknown version v4', lines[3])
          self.assertEqual("Alias 'pci' not found", lines[4])
          self.assertIn('Dry run', lines[5])
          self.assertIn('Send a total of %d patches' % count, lines[7])
          line = 8
          for i, commit in enumerate(series.commits):
              self.assertEqual('   %s' % args[i], lines[line + 0])
              line += 1
              while 'Cc:' in lines[line]:
                  line += 1
          self.assertEqual('To:	  u-boot@lists.denx.de', lines[line])
          self.assertEqual('Cc:	  %s' % stefan.encode('utf-8'), lines[line + 1])
          self.assertEqual('Version:  3', lines[line + 2])
          self.assertEqual('Prefix:\t  RFC', lines[line + 3])
          self.assertEqual('Cover: 4 lines', lines[line + 4])
          line += 5
          self.assertEqual('      Cc:  %s' % mel.encode('utf-8'), lines[line + 0])
          self.assertEqual('      Cc:  %s' % rick, lines[line + 1])
          self.assertEqual('      Cc:  %s' % fred, lines[line + 2])
          self.assertEqual('      Cc:  %s' % ed.encode('utf-8'), lines[line + 3])
          expected = ('Git command: git send-email --annotate '
                      '--in-reply-to="%s" --to "u-boot@lists.denx.de" '
                      '--cc "%s" --cc-cmd "%s --cc-cmd %s" %s %s'
                      % (in_reply_to, stefan, sys.argv[0], cc_file, cover_fname,
                         ' '.join(args))).encode('utf-8')
          line += 4
          self.assertEqual(expected, lines[line])
  
          self.assertEqual(('%s %s, %s' % (args[0], rick, stefan))
                           .encode('utf-8'), cc_lines[0])
          self.assertEqual(('%s %s, %s, %s, %s' % (args[1], fred, rick, stefan,
                                              ed)).encode('utf-8'), cc_lines[1])
  
          expected = '''
  This is a test of how the cover
  leter
  works
  
  some notes
  about some things
  from the first commit
  
  Changes in v4:
  - Some changes
  
  Simon Glass (2):
    pci: Correct cast for sandbox
    fdt: Correct cast for sandbox in fdtdec_setup_memory_size()
  
   cmd/pci.c                   | 3 ++-
   fs/fat/fat.c                | 1 +
   lib/efi_loader/efi_memory.c | 1 +
   lib/fdtdec.c                | 3 ++-
   4 files changed, 6 insertions(+), 2 deletions(-)
  
  --\x20
  2.7.4
  
  '''
          lines = open(cover_fname).read().splitlines()
          #print '\n'.join(lines)
          self.assertEqual(
                  'Subject: [RFC PATCH v3 0/2] test: A test patch series',
                  lines[3])
          self.assertEqual(expected.splitlines(), lines[7:])
  
          for i, fname in enumerate(args):
              lines = open(fname).read().splitlines()
              #print '\n'.join(lines)
              subject = [line for line in lines if line.startswith('Subject')]
              self.assertEqual('Subject: [RFC %d/%d]' % (i + 1, count),
                               subject[0][:18])
              if i == 0:
                  # Check that we got our commit notes
                  self.assertEqual('---', lines[17])
                  self.assertEqual('Some notes about', lines[18])
                  self.assertEqual('the first commit', lines[19])
  