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.""" |