comparison tests/run-tests.py @ 21312:986b8a58a6d3

run-tests: move t test parsing into its own function Test parsing is somewhat complicated. This patch extracts it into its own function. The impetus of this patch is folding tsttest() into the TTest class. Subsequent patches will continue this work until tsttest() no longer exists.
author Gregory Szorc <gregory.szorc@gmail.com>
date Sat, 19 Apr 2014 15:19:28 -0700
parents f9a7018a35ff
children a2bd02a3b6d2
comparison
equal deleted inserted replaced
21311:f9a7018a35ff 21312:986b8a58a6d3
745 return globmatch(el[:-8], l) 745 return globmatch(el[:-8], l)
746 if os.altsep and l.replace('\\', '/') == el: 746 if os.altsep and l.replace('\\', '/') == el:
747 return '+glob' 747 return '+glob'
748 return False 748 return False
749 749
750 def tsttest(test, wd, options, replacements, env): 750 def tsttest(t, test, wd, options, replacements, env):
751 # We generate a shell script which outputs unique markers to line
752 # up script results with our source. These markers include input
753 # line number and the last return code
754 salt = "SALT" + str(time.time())
755 def addsalt(line, inpython):
756 if inpython:
757 script.append('%s %d 0\n' % (salt, line))
758 else:
759 script.append('echo %s %s $?\n' % (salt, line))
760
761 # After we run the shell script, we re-unify the script output
762 # with non-active parts of the source, with synchronization by our
763 # SALT line number markers. The after table contains the
764 # non-active components, ordered by line number
765 after = {}
766 pos = prepos = -1
767
768 # Expected shell script output
769 expected = {}
770
771 # We keep track of whether or not we're in a Python block so we
772 # can generate the surrounding doctest magic
773 inpython = False
774
775 # True or False when in a true or false conditional section
776 skipping = None
777
778 def hghave(reqs):
779 # TODO: do something smarter when all other uses of hghave is gone
780 tdir = TESTDIR.replace('\\', '/')
781 proc = Popen4('%s -c "%s/hghave %s"' %
782 (options.shell, tdir, ' '.join(reqs)), wd, 0)
783 stdout, stderr = proc.communicate()
784 ret = proc.wait()
785 if wifexited(ret):
786 ret = os.WEXITSTATUS(ret)
787 if ret == 2:
788 print stdout
789 sys.exit(1)
790 return ret == 0
791
792 f = open(test) 751 f = open(test)
793 t = f.readlines() 752 tlines = f.readlines()
794 f.close() 753 f.close()
795 754
796 script = [] 755 salt, script, after, expected = t._parsetest(tlines, wd)
797 if options.debug:
798 script.append('set -x\n')
799 if os.getenv('MSYSTEM'):
800 script.append('alias pwd="pwd -W"\n')
801 n = 0
802 for n, l in enumerate(t):
803 if not l.endswith('\n'):
804 l += '\n'
805 if l.startswith('#if'):
806 lsplit = l.split()
807 if len(lsplit) < 2 or lsplit[0] != '#if':
808 after.setdefault(pos, []).append(' !!! invalid #if\n')
809 if skipping is not None:
810 after.setdefault(pos, []).append(' !!! nested #if\n')
811 skipping = not hghave(lsplit[1:])
812 after.setdefault(pos, []).append(l)
813 elif l.startswith('#else'):
814 if skipping is None:
815 after.setdefault(pos, []).append(' !!! missing #if\n')
816 skipping = not skipping
817 after.setdefault(pos, []).append(l)
818 elif l.startswith('#endif'):
819 if skipping is None:
820 after.setdefault(pos, []).append(' !!! missing #if\n')
821 skipping = None
822 after.setdefault(pos, []).append(l)
823 elif skipping:
824 after.setdefault(pos, []).append(l)
825 elif l.startswith(' >>> '): # python inlines
826 after.setdefault(pos, []).append(l)
827 prepos = pos
828 pos = n
829 if not inpython:
830 # we've just entered a Python block, add the header
831 inpython = True
832 addsalt(prepos, False) # make sure we report the exit code
833 script.append('%s -m heredoctest <<EOF\n' % PYTHON)
834 addsalt(n, True)
835 script.append(l[2:])
836 elif l.startswith(' ... '): # python inlines
837 after.setdefault(prepos, []).append(l)
838 script.append(l[2:])
839 elif l.startswith(' $ '): # commands
840 if inpython:
841 script.append("EOF\n")
842 inpython = False
843 after.setdefault(pos, []).append(l)
844 prepos = pos
845 pos = n
846 addsalt(n, False)
847 cmd = l[4:].split()
848 if len(cmd) == 2 and cmd[0] == 'cd':
849 l = ' $ cd %s || exit 1\n' % cmd[1]
850 script.append(l[4:])
851 elif l.startswith(' > '): # continuations
852 after.setdefault(prepos, []).append(l)
853 script.append(l[4:])
854 elif l.startswith(' '): # results
855 # queue up a list of expected results
856 expected.setdefault(pos, []).append(l[2:])
857 else:
858 if inpython:
859 script.append("EOF\n")
860 inpython = False
861 # non-command/result - queue up for merged output
862 after.setdefault(pos, []).append(l)
863
864 if inpython:
865 script.append("EOF\n")
866 if skipping is not None:
867 after.setdefault(pos, []).append(' !!! missing #endif\n')
868 addsalt(n + 1, False)
869 756
870 # Write out the script and execute it 757 # Write out the script and execute it
871 name = wd + '.sh' 758 name = wd + '.sh'
872 f = open(name, 'w') 759 f = open(name, 'w')
873 for l in script: 760 for l in script:
944 831
945 class TTest(Test): 832 class TTest(Test):
946 """A "t test" is a test backed by a .t file.""" 833 """A "t test" is a test backed by a .t file."""
947 834
948 def _run(self, testtmp, replacements, env): 835 def _run(self, testtmp, replacements, env):
949 return tsttest(self._path, testtmp, self._options, replacements, 836 return tsttest(self, self._path, testtmp, self._options, replacements,
950 env) 837 env)
838
839 def _hghave(self, reqs, testtmp):
840 # TODO do something smarter when all other uses of hghave are gone.
841 tdir = TESTDIR.replace('\\', '/')
842 proc = Popen4('%s -c "%s/hghave %s"' %
843 (self._options.shell, tdir, ' '.join(reqs)),
844 testtmp, 0)
845 stdout, stderr = proc.communicate()
846 ret = proc.wait()
847 if wifexited(ret):
848 ret = os.WEXITSTATUS(ret)
849 if ret == 2:
850 print stdout
851 sys.exit(1)
852
853 return ret == 0
854
855 def _parsetest(self, lines, testtmp):
856 # We generate a shell script which outputs unique markers to line
857 # up script results with our source. These markers include input
858 # line number and the last return code.
859 salt = "SALT" + str(time.time())
860 def addsalt(line, inpython):
861 if inpython:
862 script.append('%s %d 0\n' % (salt, line))
863 else:
864 script.append('echo %s %s $?\n' % (salt, line))
865
866 script = []
867
868 # After we run the shell script, we re-unify the script output
869 # with non-active parts of the source, with synchronization by our
870 # SALT line number markers. The after table contains the non-active
871 # components, ordered by line number.
872 after = {}
873
874 # Expected shell script output.
875 expected = {}
876
877 pos = prepos = -1
878
879 # True or False when in a true or false conditional section
880 skipping = None
881
882 # We keep track of whether or not we're in a Python block so we
883 # can generate the surrounding doctest magic.
884 inpython = False
885
886 if self._options.debug:
887 script.append('set -x\n')
888 if os.getenv('MSYSTEM'):
889 script.append('alias pwd="pwd -W"\n')
890
891 for n, l in enumerate(lines):
892 if not l.endswith('\n'):
893 l += '\n'
894 if l.startswith('#if'):
895 lsplit = l.split()
896 if len(lsplit) < 2 or lsplit[0] != '#if':
897 after.setdefault(pos, []).append(' !!! invalid #if\n')
898 if skipping is not None:
899 after.setdefault(pos, []).append(' !!! nested #if\n')
900 skipping = not self._hghave(lsplit[1:], testtmp)
901 after.setdefault(pos, []).append(l)
902 elif l.startswith('#else'):
903 if skipping is None:
904 after.setdefault(pos, []).append(' !!! missing #if\n')
905 skipping = not skipping
906 after.setdefault(pos, []).append(l)
907 elif l.startswith('#endif'):
908 if skipping is None:
909 after.setdefault(pos, []).append(' !!! missing #if\n')
910 skipping = None
911 after.setdefault(pos, []).append(l)
912 elif skipping:
913 after.setdefault(pos, []).append(l)
914 elif l.startswith(' >>> '): # python inlines
915 after.setdefault(pos, []).append(l)
916 prepos = pos
917 pos = n
918 if not inpython:
919 # We've just entered a Python block. Add the header.
920 inpython = True
921 addsalt(prepos, False) # Make sure we report the exit code.
922 script.append('%s -m heredoctest <<EOF\n' % PYTHON)
923 addsalt(n, True)
924 script.append(l[2:])
925 elif l.startswith(' ... '): # python inlines
926 after.setdefault(prepos, []).append(l)
927 script.append(l[2:])
928 elif l.startswith(' $ '): # commands
929 if inpython:
930 script.append('EOF\n')
931 inpython = False
932 after.setdefault(pos, []).append(l)
933 prepos = pos
934 pos = n
935 addsalt(n, False)
936 cmd = l[4:].split()
937 if len(cmd) == 2 and cmd[0] == 'cd':
938 l = ' $ cd %s || exit 1\n' % cmd[1]
939 script.append(l[4:])
940 elif l.startswith(' > '): # continuations
941 after.setdefault(prepos, []).append(l)
942 script.append(l[4:])
943 elif l.startswith(' '): # results
944 # Queue up a list of expected results.
945 expected.setdefault(pos, []).append(l[2:])
946 else:
947 if inpython:
948 script.append('EOF\n')
949 inpython = False
950 # Non-command/result. Queue up for merged output.
951 after.setdefault(pos, []).append(l)
952
953 if inpython:
954 script.append('EOF\n')
955 if skipping is not None:
956 after.setdefault(pos, []).append(' !!! missing #endif\n')
957 addsalt(n + 1, False)
958
959 return salt, script, after, expected
960
951 961
952 wifexited = getattr(os, "WIFEXITED", lambda x: False) 962 wifexited = getattr(os, "WIFEXITED", lambda x: False)
953 def run(cmd, wd, options, replacements, env): 963 def run(cmd, wd, options, replacements, env):
954 """Run command in a sub-process, capturing the output (stdout and stderr). 964 """Run command in a sub-process, capturing the output (stdout and stderr).
955 Return a tuple (exitcode, output). output is None in debug mode.""" 965 Return a tuple (exitcode, output). output is None in debug mode."""