diff options
Diffstat (limited to 'build/pymake/tests')
163 files changed, 3318 insertions, 0 deletions
diff --git a/build/pymake/tests/automatic-variables.mk b/build/pymake/tests/automatic-variables.mk new file mode 100644 index 0000000000..5302c08ead --- /dev/null +++ b/build/pymake/tests/automatic-variables.mk @@ -0,0 +1,79 @@ +$(shell \ +mkdir -p src/subd; \ +mkdir subd; \ +touch dummy; \ +sleep 2; \ +touch subd/test.out src/subd/test.in2; \ +sleep 2; \ +touch subd/test.out2 src/subd/test.in; \ +sleep 2; \ +touch subd/host_test.out subd/host_test.out2; \ +sleep 2; \ +touch host_prog; \ +) + +VPATH = src + +all: prog host_prog prog dir/ + test "$@" = "all" + test "$<" = "prog" + test "$^" = "prog host_prog dir" + test "$?" = "prog host_prog dir" + test "$+" = "prog host_prog prog dir" + test "$(@D)" = "." + test "$(@F)" = "all" + test "$(<D)" = "." + test "$(<F)" = "prog" + test "$(^D)" = ". . ." + test "$(^F)" = "prog host_prog dir" + test "$(?D)" = ". . ." + test "$(?F)" = "prog host_prog dir" + test "$(+D)" = ". . . ." + test "$(+F)" = "prog host_prog prog dir" + @echo TEST-PASS + +dir/: + test "$@" = "dir" + test "$<" = "" + test "$^" = "" + test "$(@D)" = "." + test "$(@F)" = "dir" + mkdir $@ + +prog: subd/test.out subd/test.out2 + test "$@" = "prog" + test "$<" = "subd/test.out" + test "$^" = "subd/test.out subd/test.out2" # ^ + test "$?" = "subd/test.out subd/test.out2" # ? + cat $< + test "$$(cat $<)" = "remade" + test "$$(cat $(word 2,$^))" = "" + +host_prog: subd/host_test.out subd/host_test.out2 + @echo TEST-FAIL No need to remake + +%.out: %.in dummy + test "$@" = "subd/test.out" + test "$*" = "subd/test" # * + test "$<" = "src/subd/test.in" # < + test "$^" = "src/subd/test.in dummy" # ^ + test "$?" = "src/subd/test.in" # ? + test "$+" = "src/subd/test.in dummy" # + + test "$(@D)" = "subd" + test "$(@F)" = "test.out" + test "$(*D)" = "subd" + test "$(*F)" = "test" + test "$(<D)" = "src/subd" + test "$(<F)" = "test.in" + test "$(^D)" = "src/subd ." # ^D + test "$(^F)" = "test.in dummy" + test "$(?D)" = "src/subd" + test "$(?F)" = "test.in" + test "$(+D)" = "src/subd ." # +D + test "$(+F)" = "test.in dummy" + printf "remade" >$@ + +%.out2: %.in2 dummy + @echo TEST_FAIL No need to remake + +.PHONY: all diff --git a/build/pymake/tests/bad-command-continuation.mk b/build/pymake/tests/bad-command-continuation.mk new file mode 100644 index 0000000000..d9ceccfc28 --- /dev/null +++ b/build/pymake/tests/bad-command-continuation.mk @@ -0,0 +1,3 @@ +all: + echo 'hello'\ +TEST-PASS diff --git a/build/pymake/tests/call.mk b/build/pymake/tests/call.mk new file mode 100644 index 0000000000..9eeb7e00c3 --- /dev/null +++ b/build/pymake/tests/call.mk @@ -0,0 +1,12 @@ +test = $0 +reverse = $2 $1 +twice = $1$1 +sideeffect = $(shell echo "called$1:" >>dummyfile) + +all: + test "$(call test)" = "test" + test "$(call reverse,1,2)" = "2 1" +# expansion happens *before* substitution, thank sanity + test "$(call twice,$(sideeffect))" = "" + test `cat dummyfile` = "called:" + @echo TEST-PASS diff --git a/build/pymake/tests/cmd-stripdotslash.mk b/build/pymake/tests/cmd-stripdotslash.mk new file mode 100644 index 0000000000..ce5ed42441 --- /dev/null +++ b/build/pymake/tests/cmd-stripdotslash.mk @@ -0,0 +1,5 @@ +all: + $(MAKE) -f $(TESTPATH)/cmd-stripdotslash.mk ./foo + +./foo: + @echo TEST-PASS diff --git a/build/pymake/tests/cmdgoals.mk b/build/pymake/tests/cmdgoals.mk new file mode 100644 index 0000000000..a3b25e7513 --- /dev/null +++ b/build/pymake/tests/cmdgoals.mk @@ -0,0 +1,9 @@ +default: + test "$(MAKECMDGOALS)" = "" + $(MAKE) -f $(TESTPATH)/cmdgoals.mk t1 t2 + @echo TEST-PASS + +t1: + test "$(MAKECMDGOALS)" = "t1 t2" + +t2: diff --git a/build/pymake/tests/commandmodifiers.mk b/build/pymake/tests/commandmodifiers.mk new file mode 100644 index 0000000000..8440462f32 --- /dev/null +++ b/build/pymake/tests/commandmodifiers.mk @@ -0,0 +1,21 @@ +define COMMAND +$(1) + $(1) + +endef + +all: + $(call COMMAND,@true #TEST-FAIL) + $(call COMMAND,-exit 4) + $(call COMMAND,@-exit 1 # TEST-FAIL) + $(call COMMAND,-@exit 1 # TEST-FAIL) + $(call COMMAND,+exit 0) + $(call COMMAND,+-exit 1) + $(call COMMAND,@+exit 0 # TEST-FAIL) + $(call COMMAND,+@exit 0 # TEST-FAIL) + $(call COMMAND,-+@exit 1 # TEST-FAIL) + $(call COMMAND,+-@exit 1 # TEST-FAIL) + $(call COMMAND,@+-exit 1 # TEST-FAIL) + $(call COMMAND,@+-@+-exit 1 # TEST-FAIL) + $(call COMMAND,@@++exit 0 # TEST-FAIL) + @echo TEST-PASS diff --git a/build/pymake/tests/comment-parsing.mk b/build/pymake/tests/comment-parsing.mk new file mode 100644 index 0000000000..d469e1aea1 --- /dev/null +++ b/build/pymake/tests/comment-parsing.mk @@ -0,0 +1,29 @@ +# where do comments take effect? + +VAR = val1 # comment +VAR2 = lit2\#hash +VAR2_1 = lit2.1\\\#hash +VAR3 = val3 +VAR4 = lit4\\#backslash +VAR4_1 = lit4\\\\#backslash +VAR5 = lit5\char +VAR6 = lit6\\char +VAR7 = lit7\\ +VAR8 = lit8\\\\ +VAR9 = lit9\\\\extra +# This comment extends to the next line \ +VAR3 = ignored + +all: + test "$(VAR)" = "val1 " + test "$(VAR2)" = "lit2#hash" + test '$(VAR2_1)' = 'lit2.1\#hash' + test "$(VAR3)" = "val3" + test '$(VAR4)' = 'lit4\' + test '$(VAR4_1)' = 'lit4\\' + test '$(VAR5)' = 'lit5\char' + test '$(VAR6)' = 'lit6\\char' + test '$(VAR7)' = 'lit7\\' + test '$(VAR8)' = 'lit8\\\\' + test '$(VAR9)' = 'lit9\\\\extra' + @echo "TEST-PASS" diff --git a/build/pymake/tests/continuations-in-functions.mk b/build/pymake/tests/continuations-in-functions.mk new file mode 100644 index 0000000000..533df61763 --- /dev/null +++ b/build/pymake/tests/continuations-in-functions.mk @@ -0,0 +1,6 @@ +all: + test 'Hello world.' = '$(if 1,Hello \ + world.)' + test '(Hello world.)' != '(Hello \ + world.)' + @echo TEST-PASS diff --git a/build/pymake/tests/datatests.py b/build/pymake/tests/datatests.py new file mode 100644 index 0000000000..513028b0b2 --- /dev/null +++ b/build/pymake/tests/datatests.py @@ -0,0 +1,237 @@ +import pymake.data, pymake.functions, pymake.util +import unittest +import re +from cStringIO import StringIO + +def multitest(cls): + for name in cls.testdata.iterkeys(): + def m(self, name=name): + return self.runSingle(*self.testdata[name]) + + setattr(cls, 'test_%s' % name, m) + return cls + +class SplitWordsTest(unittest.TestCase): + testdata = ( + (' test test.c test.o ', ['test', 'test.c', 'test.o']), + ('\ttest\t test.c \ntest.o', ['test', 'test.c', 'test.o']), + ) + + def runTest(self): + for s, e in self.testdata: + w = s.split() + self.assertEqual(w, e, 'splitwords(%r)' % (s,)) + +class GetPatSubstTest(unittest.TestCase): + testdata = ( + ('%.c', '%.o', ' test test.c test.o ', 'test test.o test.o'), + ('%', '%.o', ' test.c test.o ', 'test.c.o test.o.o'), + ('foo', 'bar', 'test foo bar', 'test bar bar'), + ('foo', '%bar', 'test foo bar', 'test %bar bar'), + ('%', 'perc_%', 'path', 'perc_path'), + ('\\%', 'sub%', 'p %', 'p sub%'), + ('%.c', '\\%%.o', 'foo.c bar.o baz.cpp', '%foo.o bar.o baz.cpp'), + ) + + def runTest(self): + for s, r, d, e in self.testdata: + words = d.split() + p = pymake.data.Pattern(s) + a = ' '.join((p.subst(r, word, False) + for word in words)) + self.assertEqual(a, e, 'Pattern(%r).subst(%r, %r)' % (s, r, d)) + +class LRUTest(unittest.TestCase): + # getkey, expected, funccount, debugitems + expected = ( + (0, '', 1, (0,)), + (0, '', 2, (0,)), + (1, ' ', 3, (1, 0)), + (1, ' ', 3, (1, 0)), + (0, '', 4, (0, 1)), + (2, ' ', 5, (2, 0, 1)), + (1, ' ', 5, (1, 2, 0)), + (3, ' ', 6, (3, 1, 2)), + ) + + def spaceFunc(self, l): + self.funccount += 1 + return ''.ljust(l) + + def runTest(self): + self.funccount = 0 + c = pymake.util.LRUCache(3, self.spaceFunc, lambda k, v: k % 2) + self.assertEqual(tuple(c.debugitems()), ()) + + for i in xrange(0, len(self.expected)): + k, e, fc, di = self.expected[i] + + v = c.get(k) + self.assertEqual(v, e) + self.assertEqual(self.funccount, fc, + "funccount, iteration %i, got %i expected %i" % (i, self.funccount, fc)) + goti = tuple(c.debugitems()) + self.assertEqual(goti, di, + "debugitems, iteration %i, got %r expected %r" % (i, goti, di)) + +class EqualityTest(unittest.TestCase): + def test_string_expansion(self): + s1 = pymake.data.StringExpansion('foo bar', None) + s2 = pymake.data.StringExpansion('foo bar', None) + + self.assertEqual(s1, s2) + + def test_expansion_simple(self): + s1 = pymake.data.Expansion(None) + s2 = pymake.data.Expansion(None) + + self.assertEqual(s1, s2) + + s1.appendstr('foo') + s2.appendstr('foo') + self.assertEqual(s1, s2) + + def test_expansion_string_finish(self): + """Adjacent strings should normalize to same value.""" + s1 = pymake.data.Expansion(None) + s2 = pymake.data.Expansion(None) + + s1.appendstr('foo') + s2.appendstr('foo') + + s1.appendstr(' bar') + s1.appendstr(' baz') + s2.appendstr(' bar baz') + + self.assertEqual(s1, s2) + + def test_function(self): + s1 = pymake.data.Expansion(None) + s2 = pymake.data.Expansion(None) + + n1 = pymake.data.StringExpansion('FOO', None) + n2 = pymake.data.StringExpansion('FOO', None) + + v1 = pymake.functions.VariableRef(None, n1) + v2 = pymake.functions.VariableRef(None, n2) + + s1.appendfunc(v1) + s2.appendfunc(v2) + + self.assertEqual(s1, s2) + + +class StringExpansionTest(unittest.TestCase): + def test_base_expansion_interface(self): + s1 = pymake.data.StringExpansion('FOO', None) + + self.assertTrue(s1.is_static_string) + + funcs = list(s1.functions()) + self.assertEqual(len(funcs), 0) + + funcs = list(s1.functions(True)) + self.assertEqual(len(funcs), 0) + + refs = list(s1.variable_references()) + self.assertEqual(len(refs), 0) + + +class ExpansionTest(unittest.TestCase): + def test_is_static_string(self): + e1 = pymake.data.Expansion() + e1.appendstr('foo') + + self.assertTrue(e1.is_static_string) + + e1.appendstr('bar') + self.assertTrue(e1.is_static_string) + + vname = pymake.data.StringExpansion('FOO', None) + func = pymake.functions.VariableRef(None, vname) + + e1.appendfunc(func) + + self.assertFalse(e1.is_static_string) + + def test_get_functions(self): + e1 = pymake.data.Expansion() + e1.appendstr('foo') + + vname1 = pymake.data.StringExpansion('FOO', None) + vname2 = pymake.data.StringExpansion('BAR', None) + + func1 = pymake.functions.VariableRef(None, vname1) + func2 = pymake.functions.VariableRef(None, vname2) + + e1.appendfunc(func1) + e1.appendfunc(func2) + + funcs = list(e1.functions()) + self.assertEqual(len(funcs), 2) + + func3 = pymake.functions.SortFunction(None) + func3.append(vname1) + + e1.appendfunc(func3) + + funcs = list(e1.functions()) + self.assertEqual(len(funcs), 3) + + refs = list(e1.variable_references()) + self.assertEqual(len(refs), 2) + + def test_get_functions_descend(self): + e1 = pymake.data.Expansion() + vname1 = pymake.data.StringExpansion('FOO', None) + func1 = pymake.functions.VariableRef(None, vname1) + e2 = pymake.data.Expansion() + e2.appendfunc(func1) + + func2 = pymake.functions.SortFunction(None) + func2.append(e2) + + e1.appendfunc(func2) + + funcs = list(e1.functions()) + self.assertEqual(len(funcs), 1) + + funcs = list(e1.functions(True)) + self.assertEqual(len(funcs), 2) + + self.assertTrue(isinstance(funcs[0], pymake.functions.SortFunction)) + + def test_is_filesystem_dependent(self): + e = pymake.data.Expansion() + vname1 = pymake.data.StringExpansion('FOO', None) + func1 = pymake.functions.VariableRef(None, vname1) + e.appendfunc(func1) + + self.assertFalse(e.is_filesystem_dependent) + + func2 = pymake.functions.WildcardFunction(None) + func2.append(vname1) + e.appendfunc(func2) + + self.assertTrue(e.is_filesystem_dependent) + + def test_is_filesystem_dependent_descend(self): + sort = pymake.functions.SortFunction(None) + wildcard = pymake.functions.WildcardFunction(None) + + e = pymake.data.StringExpansion('foo/*', None) + wildcard.append(e) + + e = pymake.data.Expansion(None) + e.appendfunc(wildcard) + + sort.append(e) + + e = pymake.data.Expansion(None) + e.appendfunc(sort) + + self.assertTrue(e.is_filesystem_dependent) + + +if __name__ == '__main__': + unittest.main() diff --git a/build/pymake/tests/default-goal-set-first.mk b/build/pymake/tests/default-goal-set-first.mk new file mode 100644 index 0000000000..00a5b53a2a --- /dev/null +++ b/build/pymake/tests/default-goal-set-first.mk @@ -0,0 +1,7 @@ +.DEFAULT_GOAL := default + +not-default: + @echo TEST-FAIL did not run default rule + +default: + @echo TEST-PASS diff --git a/build/pymake/tests/default-goal.mk b/build/pymake/tests/default-goal.mk new file mode 100644 index 0000000000..699d6c0cdc --- /dev/null +++ b/build/pymake/tests/default-goal.mk @@ -0,0 +1,8 @@ +not-default: + @echo TEST-FAIL did not run default rule + +default: + @echo $(if $(filter not-default,$(INTERMEDIATE_DEFAULT_GOAL)),TEST-PASS,TEST-FAIL .DEFAULT_GOAL not set by $(MAKE)) + +INTERMEDIATE_DEFAULT_GOAL := $(.DEFAULT_GOAL) +.DEFAULT_GOAL := default diff --git a/build/pymake/tests/default-target.mk b/build/pymake/tests/default-target.mk new file mode 100644 index 0000000000..701ac6916e --- /dev/null +++ b/build/pymake/tests/default-target.mk @@ -0,0 +1,14 @@ +test: VAR = value + +%.do: + @echo TEST-FAIL: ran target "$@", should have run "all" + +.PHONY: test + +all: + @echo TEST-PASS: the default target is all + +test: + @echo TEST-FAIL: ran target "$@", should have run "all" + +test.do: diff --git a/build/pymake/tests/default-target2.mk b/build/pymake/tests/default-target2.mk new file mode 100644 index 0000000000..b5a4b1bbf2 --- /dev/null +++ b/build/pymake/tests/default-target2.mk @@ -0,0 +1,6 @@ +test.foo: %.foo: + test "$@" = "test.foo" + @echo TEST-PASS made test.foo by default + +all: + @echo TEST-FAIL made $@, should have made test.foo diff --git a/build/pymake/tests/define-directive.mk b/build/pymake/tests/define-directive.mk new file mode 100644 index 0000000000..7899886663 --- /dev/null +++ b/build/pymake/tests/define-directive.mk @@ -0,0 +1,69 @@ +define COMMANDS +shellvar=hello +test "$$shellvar" != "hello" +endef + +define COMMANDS2 +shellvar=hello; \ + test "$$shellvar" = "hello" +endef + +define VARWITHCOMMENT # comment +value +endef + +define TEST3 + whitespace +endef + +define TEST4 +define TEST5 +random +endef + endef + +ifdef TEST5 +$(error TEST5 should not be set) +endif + +define TEST6 + define TEST7 +random +endef +endef + +ifdef TEST7 +$(error TEST7 should not be set) +endif + +define TEST8 +is this # a comment? +endef + +ifneq ($(TEST8),is this \# a comment?) +$(error TEST8 value not expected: $(TEST8)) +endif + +# A backslash continuation "hides" the endef +define TEST9 +value \ +endef +endef + +# Test ridiculous spacing + define TEST10 + define TEST11 + baz +endef +define TEST12 + foo + endef + endef + +all: + $(COMMANDS) + $(COMMANDS2) + test '$(VARWITHCOMMENT)' = 'value' + test '$(COMMANDS2)' = 'shellvar=hello; test "$$shellvar" = "hello"' + test "$(TEST3)" = " whitespace" + @echo TEST-PASS diff --git a/build/pymake/tests/depfailed.mk b/build/pymake/tests/depfailed.mk new file mode 100644 index 0000000000..ce4137c38b --- /dev/null +++ b/build/pymake/tests/depfailed.mk @@ -0,0 +1,4 @@ +#T returncode: 2 + +all: foo.out foo.in + @echo TEST-PASS diff --git a/build/pymake/tests/depfailedj.mk b/build/pymake/tests/depfailedj.mk new file mode 100644 index 0000000000..a94c74f6f3 --- /dev/null +++ b/build/pymake/tests/depfailedj.mk @@ -0,0 +1,10 @@ +#T returncode: 2 +#T commandline: ['-j4'] + +$(shell touch foo.in) + +all: foo.in foo.out missing + @echo TEST-PASS + +%.out: %.in + cp $< $@ diff --git a/build/pymake/tests/diamond-deps.mk b/build/pymake/tests/diamond-deps.mk new file mode 100644 index 0000000000..40a4176d98 --- /dev/null +++ b/build/pymake/tests/diamond-deps.mk @@ -0,0 +1,13 @@ +# If the dependency graph includes a diamond dependency, we should only remake +# once! + +all: depA depB + cat testfile + test `cat testfile` = "data"; + @echo TEST-PASS + +depA: testfile +depB: testfile + +testfile: + printf "data" >>$@ diff --git a/build/pymake/tests/dotslash-dir.mk b/build/pymake/tests/dotslash-dir.mk new file mode 100644 index 0000000000..8b30d1e3ca --- /dev/null +++ b/build/pymake/tests/dotslash-dir.mk @@ -0,0 +1,8 @@ +#T grep-for: "dotslash-built" +.PHONY: $(dir foo) + +all: $(dir foo) + @echo TEST-PASS + +$(dir foo): + @echo dotslash-built diff --git a/build/pymake/tests/dotslash-parse.mk b/build/pymake/tests/dotslash-parse.mk new file mode 100644 index 0000000000..91461bedb5 --- /dev/null +++ b/build/pymake/tests/dotslash-parse.mk @@ -0,0 +1,4 @@ +./: + +# This is merely a test to see that pymake doesn't choke on parsing ./ +$(info TEST-PASS) diff --git a/build/pymake/tests/dotslash-phony.mk b/build/pymake/tests/dotslash-phony.mk new file mode 100644 index 0000000000..06b6ae78db --- /dev/null +++ b/build/pymake/tests/dotslash-phony.mk @@ -0,0 +1,3 @@ +.PHONY: ./ +./: + @echo TEST-PASS diff --git a/build/pymake/tests/dotslash.mk b/build/pymake/tests/dotslash.mk new file mode 100644 index 0000000000..585db96b79 --- /dev/null +++ b/build/pymake/tests/dotslash.mk @@ -0,0 +1,9 @@ +$(shell touch foo.in) + +all: foo.out + test "$(wildcard ./*.in)" = "./foo.in" + @echo TEST-PASS + +./%.out: %.in + test "$@" = "foo.out" + cp $< $@ diff --git a/build/pymake/tests/doublecolon-exists.mk b/build/pymake/tests/doublecolon-exists.mk new file mode 100644 index 0000000000..5d99a1f6bf --- /dev/null +++ b/build/pymake/tests/doublecolon-exists.mk @@ -0,0 +1,16 @@ +$(shell touch foo.testfile1 foo.testfile2) + +# when a rule has commands and no prerequisites, should it be executed? +# double-colon: yes +# single-colon: no + +all: foo.testfile1 foo.testfile2 + test "$$(cat foo.testfile1)" = "" + test "$$(cat foo.testfile2)" = "remade:foo.testfile2" + @echo TEST-PASS + +foo.testfile1: + @echo TEST-FAIL + +foo.testfile2:: + printf "remade:$@"> $@ diff --git a/build/pymake/tests/doublecolon-priordeps.mk b/build/pymake/tests/doublecolon-priordeps.mk new file mode 100644 index 0000000000..6cdf3a8e71 --- /dev/null +++ b/build/pymake/tests/doublecolon-priordeps.mk @@ -0,0 +1,19 @@ +#T commandline: ['-j3'] + +# All *prior* dependencies of a doublecolon rule must be satisfied before +# subsequent commands are run. + +all:: target1 + +all:: target2 + test -f target1 + @echo TEST-PASS + +target1: + touch starting-$@ + sleep 1 + touch $@ + +target2: + sleep 0.1 + test -f starting-target1 diff --git a/build/pymake/tests/doublecolon-remake.mk b/build/pymake/tests/doublecolon-remake.mk new file mode 100644 index 0000000000..52aa9265ca --- /dev/null +++ b/build/pymake/tests/doublecolon-remake.mk @@ -0,0 +1,4 @@ +$(shell touch somefile) + +all:: somefile + @echo TEST-PASS diff --git a/build/pymake/tests/dynamic-var.mk b/build/pymake/tests/dynamic-var.mk new file mode 100644 index 0000000000..0993b9ccf0 --- /dev/null +++ b/build/pymake/tests/dynamic-var.mk @@ -0,0 +1,18 @@ +# The *name* of variables can be constructed dynamically. + +VARNAME = FOOBAR + +$(VARNAME) = foovalue +$(VARNAME)2 = foo2value + +$(VARNAME:%BAR=%BAM) = foobam + +all: + test "$(FOOBAR)" = "foovalue" + test "$(flavor FOOBAZ)" = "undefined" + test "$(FOOBAR2)" = "bazvalue" + test "$(FOOBAM)" = "foobam" + @echo TEST-PASS + +VARNAME = FOOBAZ +FOOBAR2 = bazvalue diff --git a/build/pymake/tests/empty-arg.mk b/build/pymake/tests/empty-arg.mk new file mode 100644 index 0000000000..616e5b694f --- /dev/null +++ b/build/pymake/tests/empty-arg.mk @@ -0,0 +1,2 @@ +all: + @ sh -c 'if [ $$# = 3 ] ; then echo TEST-PASS; else echo TEST-FAIL; fi' -- a "" b diff --git a/build/pymake/tests/empty-command-semicolon.mk b/build/pymake/tests/empty-command-semicolon.mk new file mode 100644 index 0000000000..07789f3f1c --- /dev/null +++ b/build/pymake/tests/empty-command-semicolon.mk @@ -0,0 +1,5 @@ +all: + @echo TEST-PASS + +foo: ; + diff --git a/build/pymake/tests/empty-with-deps.mk b/build/pymake/tests/empty-with-deps.mk new file mode 100644 index 0000000000..284e5a1131 --- /dev/null +++ b/build/pymake/tests/empty-with-deps.mk @@ -0,0 +1,4 @@ +default.test: default.c + +default.c: + @echo TEST-PASS diff --git a/build/pymake/tests/env-var-append.mk b/build/pymake/tests/env-var-append.mk new file mode 100644 index 0000000000..4db39c45ff --- /dev/null +++ b/build/pymake/tests/env-var-append.mk @@ -0,0 +1,7 @@ +#T environment: {'FOO': 'TEST'} + +FOO += $(BAR) +BAR := PASS + +all: + @echo $(subst $(NULL) ,-,$(FOO)) diff --git a/build/pymake/tests/env-var-append2.mk b/build/pymake/tests/env-var-append2.mk new file mode 100644 index 0000000000..fc0735d884 --- /dev/null +++ b/build/pymake/tests/env-var-append2.mk @@ -0,0 +1,8 @@ +#T environment: {'FOO': '$(BAZ)'} + +FOO += $(BAR) +BAR := PASS +BAZ := TEST + +all: + @echo $(subst $(NULL) ,-,$(FOO)) diff --git a/build/pymake/tests/eof-continuation.mk b/build/pymake/tests/eof-continuation.mk new file mode 100644 index 0000000000..daeaabc3e7 --- /dev/null +++ b/build/pymake/tests/eof-continuation.mk @@ -0,0 +1,5 @@ +all: + test '$(TESTVAR)' = 'testval\' + @echo TEST-PASS + +TESTVAR = testval\
\ No newline at end of file diff --git a/build/pymake/tests/escape-chars.mk b/build/pymake/tests/escape-chars.mk new file mode 100644 index 0000000000..ebea330743 --- /dev/null +++ b/build/pymake/tests/escape-chars.mk @@ -0,0 +1,26 @@ +space = $(NULL) $(NULL) +hello$(space)world$(space) = hellovalue + +A = aval + +VAR = value1\\ +VARAWFUL = value1\\#comment +VAR2 = value2 +VAR3 = test\$A +VAR4 = value4\\value5 + +VAR5 = value1\\ \ \ + value2 + +EPERCENT = \% + +all: + test "$(hello world )" = "hellovalue" + test "$(VAR)" = "value1\\" + test '$(VARAWFUL)' = 'value1\' + test "$(VAR2)" = "value2" + test "$(VAR3)" = "test\aval" + test "$(VAR4)" = "value4\\value5" + test "$(VAR5)" = "value1\\ \ value2" + test "$(EPERCENT)" = "\%" + @echo TEST-PASS diff --git a/build/pymake/tests/escaped-continuation.mk b/build/pymake/tests/escaped-continuation.mk new file mode 100644 index 0000000000..537f7547f4 --- /dev/null +++ b/build/pymake/tests/escaped-continuation.mk @@ -0,0 +1,6 @@ +#T returncode: 2 + +all: + echo "Hello" \\ + test "world" = "not!" + @echo TEST-PASS diff --git a/build/pymake/tests/eval-duringexecute.mk b/build/pymake/tests/eval-duringexecute.mk new file mode 100644 index 0000000000..dff8480322 --- /dev/null +++ b/build/pymake/tests/eval-duringexecute.mk @@ -0,0 +1,12 @@ +#T returncode: 2 + +# Once parsing is finished, recursive expansion in commands are not allowed to create any new rules (it may only set variables) + +define MORERULE +all: + @echo TEST-FAIL +endef + +all: + $(eval $(MORERULE)) + @echo done diff --git a/build/pymake/tests/eval.mk b/build/pymake/tests/eval.mk new file mode 100644 index 0000000000..de9759f02b --- /dev/null +++ b/build/pymake/tests/eval.mk @@ -0,0 +1,7 @@ +TESTVAR = val1 + +$(eval TESTVAR = val2) + +all: + test "$(TESTVAR)" = "val2" + @echo TEST-PASS diff --git a/build/pymake/tests/exit-code.mk b/build/pymake/tests/exit-code.mk new file mode 100644 index 0000000000..84dcffcf91 --- /dev/null +++ b/build/pymake/tests/exit-code.mk @@ -0,0 +1,5 @@ +#T returncode: 2 + +all: + exit 1 + @echo TEST-PASS diff --git a/build/pymake/tests/file-functions-symlinks.mk b/build/pymake/tests/file-functions-symlinks.mk new file mode 100644 index 0000000000..dcc0f6eefe --- /dev/null +++ b/build/pymake/tests/file-functions-symlinks.mk @@ -0,0 +1,22 @@ +#T returncode-on: {'win32': 2} +$(shell \ +touch test.file; \ +ln -s test.file test.symlink; \ +ln -s test.missing missing.symlink; \ +touch .testhidden; \ +mkdir foo; \ +touch foo/testfile; \ +ln -s foo symdir; \ +) + +all: + test "$(abspath test.file test.symlink)" = "$(CURDIR)/test.file $(CURDIR)/test.symlink" + test "$(realpath test.file test.symlink)" = "$(CURDIR)/test.file $(CURDIR)/test.file" + test "$(sort $(wildcard *))" = "foo symdir test.file test.symlink" + test "$(sort $(wildcard .*))" = ". .. .testhidden" + test "$(sort $(wildcard test*))" = "test.file test.symlink" + test "$(sort $(wildcard foo/*))" = "foo/testfile" + test "$(sort $(wildcard ./*))" = "./foo ./symdir ./test.file ./test.symlink" + test "$(sort $(wildcard f?o/*))" = "foo/testfile" + test "$(sort $(wildcard */*))" = "foo/testfile symdir/testfile" + @echo TEST-PASS diff --git a/build/pymake/tests/file-functions.mk b/build/pymake/tests/file-functions.mk new file mode 100644 index 0000000000..7e4c68e85e --- /dev/null +++ b/build/pymake/tests/file-functions.mk @@ -0,0 +1,19 @@ +$(shell \ +touch test.file; \ +touch .testhidden; \ +mkdir foo; \ +touch foo/testfile; \ +) + +all: + test "$(abspath test.file)" = "$(CURDIR)/test.file" + test "$(realpath test.file)" = "$(CURDIR)/test.file" + test "$(sort $(wildcard *))" = "foo test.file" +# commented out because GNU make matches . and .. while python doesn't, and I don't +# care enough +# test "$(sort $(wildcard .*))" = ". .. .testhidden" + test "$(sort $(wildcard test*))" = "test.file" + test "$(sort $(wildcard foo/*))" = "foo/testfile" + test "$(sort $(wildcard ./*))" = "./foo ./test.file" + test "$(sort $(wildcard f?o/*))" = "foo/testfile" + @echo TEST-PASS diff --git a/build/pymake/tests/foreach-local-variable.mk b/build/pymake/tests/foreach-local-variable.mk new file mode 100644 index 0000000000..2551621eb9 --- /dev/null +++ b/build/pymake/tests/foreach-local-variable.mk @@ -0,0 +1,8 @@ +# This test ensures that a local variable in a $(foreach) is bound to +# the local value, not a global value. +i := dummy + +all: + test "$(foreach i,foo bar,found:$(i))" = "found:foo found:bar" + test "$(i)" = "dummy" + @echo TEST-PASS diff --git a/build/pymake/tests/formattingtests.py b/build/pymake/tests/formattingtests.py new file mode 100644 index 0000000000..7aad6d4cc1 --- /dev/null +++ b/build/pymake/tests/formattingtests.py @@ -0,0 +1,289 @@ +# This file contains test code for the formatting of parsed statements back to +# make file "source." It essentially verifies to to_source() functions +# scattered across the tree. + +import glob +import logging +import os.path +import unittest + +from pymake.data import Expansion +from pymake.data import StringExpansion +from pymake.functions import BasenameFunction +from pymake.functions import SubstitutionRef +from pymake.functions import VariableRef +from pymake.functions import WordlistFunction +from pymake.parserdata import Include +from pymake.parserdata import SetVariable +from pymake.parser import parsestring +from pymake.parser import SyntaxError + +class TestBase(unittest.TestCase): + pass + +class VariableRefTest(TestBase): + def test_string_name(self): + e = StringExpansion('foo', None) + v = VariableRef(None, e) + + self.assertEqual(v.to_source(), '$(foo)') + + def test_special_variable(self): + e = StringExpansion('<', None) + v = VariableRef(None, e) + + self.assertEqual(v.to_source(), '$<') + + def test_expansion_simple(self): + e = Expansion() + e.appendstr('foo') + e.appendstr('bar') + + v = VariableRef(None, e) + + self.assertEqual(v.to_source(), '$(foobar)') + +class StandardFunctionTest(TestBase): + def test_basename(self): + e1 = StringExpansion('foo', None) + v = VariableRef(None, e1) + e2 = Expansion(None) + e2.appendfunc(v) + + b = BasenameFunction(None) + b.append(e2) + + self.assertEqual(b.to_source(), '$(basename $(foo))') + + def test_wordlist(self): + e1 = StringExpansion('foo', None) + e2 = StringExpansion('bar ', None) + e3 = StringExpansion(' baz', None) + + w = WordlistFunction(None) + w.append(e1) + w.append(e2) + w.append(e3) + + self.assertEqual(w.to_source(), '$(wordlist foo,bar , baz)') + + def test_curly_brackets(self): + e1 = Expansion(None) + e1.appendstr('foo') + + e2 = Expansion(None) + e2.appendstr('foo ( bar') + + f = WordlistFunction(None) + f.append(e1) + f.append(e2) + + self.assertEqual(f.to_source(), '${wordlist foo,foo ( bar}') + +class StringExpansionTest(TestBase): + def test_simple(self): + e = StringExpansion('foobar', None) + self.assertEqual(e.to_source(), 'foobar') + + e = StringExpansion('$var', None) + self.assertEqual(e.to_source(), '$var') + + def test_escaping(self): + e = StringExpansion('$var', None) + self.assertEqual(e.to_source(escape_variables=True), '$$var') + + e = StringExpansion('this is # not a comment', None) + self.assertEqual(e.to_source(escape_comments=True), + 'this is \# not a comment') + + def test_empty(self): + e = StringExpansion('', None) + self.assertEqual(e.to_source(), '') + + e = StringExpansion(' ', None) + self.assertEqual(e.to_source(), ' ') + +class ExpansionTest(TestBase): + def test_single_string(self): + e = Expansion() + e.appendstr('foo') + + self.assertEqual(e.to_source(), 'foo') + + def test_multiple_strings(self): + e = Expansion() + e.appendstr('hello') + e.appendstr('world') + + self.assertEqual(e.to_source(), 'helloworld') + + def test_string_escape(self): + e = Expansion() + e.appendstr('$var') + self.assertEqual(e.to_source(), '$var') + self.assertEqual(e.to_source(escape_variables=True), '$$var') + + e = Expansion() + e.appendstr('foo') + e.appendstr(' $bar') + self.assertEqual(e.to_source(escape_variables=True), 'foo $$bar') + +class SubstitutionRefTest(TestBase): + def test_simple(self): + name = StringExpansion('foo', None) + c = StringExpansion('%.c', None) + o = StringExpansion('%.o', None) + s = SubstitutionRef(None, name, c, o) + + self.assertEqual(s.to_source(), '$(foo:%.c=%.o)') + +class SetVariableTest(TestBase): + def test_simple(self): + v = SetVariable(StringExpansion('foo', None), '=', 'bar', None, None) + self.assertEqual(v.to_source(), 'foo = bar') + + def test_multiline(self): + s = 'hello\nworld' + foo = StringExpansion('FOO', None) + + v = SetVariable(foo, '=', s, None, None) + + self.assertEqual(v.to_source(), 'define FOO\nhello\nworld\nendef') + + def test_multiline_immediate(self): + source = 'define FOO :=\nhello\nworld\nendef' + + statements = parsestring(source, 'foo.mk') + self.assertEqual(statements.to_source(), source) + + def test_target_specific(self): + foo = StringExpansion('FOO', None) + bar = StringExpansion('BAR', None) + + v = SetVariable(foo, '+=', 'value', None, bar) + + self.assertEqual(v.to_source(), 'BAR: FOO += value') + +class IncludeTest(TestBase): + def test_include(self): + e = StringExpansion('rules.mk', None) + i = Include(e, True, False) + self.assertEqual(i.to_source(), 'include rules.mk') + + i = Include(e, False, False) + self.assertEqual(i.to_source(), '-include rules.mk') + +class IfdefTest(TestBase): + def test_simple(self): + source = 'ifdef FOO\nbar := $(value)\nendif' + + statements = parsestring(source, 'foo.mk') + self.assertEqual(statements[0].to_source(), source) + + def test_nested(self): + source = 'ifdef FOO\nifdef BAR\nhello = world\nendif\nendif' + + statements = parsestring(source, 'foo.mk') + self.assertEqual(statements[0].to_source(), source) + + def test_negation(self): + source = 'ifndef FOO\nbar += value\nendif' + + statements = parsestring(source, 'foo.mk') + self.assertEqual(statements[0].to_source(), source) + +class IfeqTest(TestBase): + def test_simple(self): + source = 'ifeq ($(foo),bar)\nhello = $(world)\nendif' + + statements = parsestring(source, 'foo.mk') + self.assertEqual(statements[0].to_source(), source) + + def test_negation(self): + source = 'ifneq (foo,bar)\nhello = world\nendif' + + statements = parsestring(source, 'foo.mk') + self.assertEqual(statements.to_source(), source) + +class ConditionBlocksTest(TestBase): + def test_mixed_conditions(self): + source = 'ifdef FOO\nifeq ($(FOO),bar)\nvar += $(value)\nendif\nendif' + + statements = parsestring(source, 'foo.mk') + self.assertEqual(statements.to_source(), source) + + def test_extra_statements(self): + source = 'ifdef FOO\nF := 1\nifdef BAR\nB += 1\nendif\nC = 1\nendif' + + statements = parsestring(source, 'foo.mk') + self.assertEqual(statements.to_source(), source) + + def test_whitespace_preservation(self): + source = "ifeq ' x' 'x '\n$(error stripping)\nendif" + + statements = parsestring(source, 'foo.mk') + self.assertEqual(statements.to_source(), source) + + source = 'ifneq (x , x)\n$(error stripping)\nendif' + statements = parsestring(source, 'foo.mk') + self.assertEqual(statements.to_source(), + 'ifneq (x,x)\n$(error stripping)\nendif') + +class MakefileCorupusTest(TestBase): + """Runs the make files from the pymake corpus through the formatter. + + All the above tests are child's play compared to this. + """ + + # Our reformatting isn't perfect. We ignore files with known failures until + # we make them work. + # TODO Address these formatting corner cases. + _IGNORE_FILES = [ + # We are thrown off by backslashes at end of lines. + 'comment-parsing.mk', + 'escape-chars.mk', + 'include-notfound.mk', + ] + + def _get_test_files(self): + ourdir = os.path.dirname(os.path.abspath(__file__)) + + for makefile in glob.glob(os.path.join(ourdir, '*.mk')): + if os.path.basename(makefile) in self._IGNORE_FILES: + continue + + source = None + with open(makefile, 'rU') as fh: + source = fh.read() + + try: + yield (makefile, source, parsestring(source, makefile)) + except SyntaxError: + continue + + def test_reparse_consistency(self): + for filename, source, statements in self._get_test_files(): + reformatted = statements.to_source() + + # We should be able to parse the reformatted source fine. + new_statements = parsestring(reformatted, filename) + + # If we do the formatting again, the representation shouldn't + # change. i.e. the only lossy change should be the original + # (whitespace and some semantics aren't preserved). + reformatted_again = new_statements.to_source() + self.assertEqual(reformatted, reformatted_again, + '%s has lossless reformat.' % filename) + + self.assertEqual(len(statements), len(new_statements)) + + for i in xrange(0, len(statements)): + original = statements[i] + formatted = new_statements[i] + + self.assertEqual(original, formatted, '%s %d: %s != %s' % (filename, + i, original, formatted)) + +if __name__ == '__main__': + logging.basicConfig(level=logging.DEBUG) + unittest.main() diff --git a/build/pymake/tests/func-refs.mk b/build/pymake/tests/func-refs.mk new file mode 100644 index 0000000000..82ab17ba89 --- /dev/null +++ b/build/pymake/tests/func-refs.mk @@ -0,0 +1,11 @@ +unknown var = uval + +all: + test "$(subst a,b,value)" = "vblue" + test "${subst a,b,va)lue}" = "vb)lue" + test "$(subst /,\,ab/c)" = "ab\c" + test '$(subst a,b,\\#)' = '\\#' + test "$( subst a,b,value)" = "" + test "$(Subst a,b,value)" = "" + test "$(unknown var)" = "uval" + @echo TEST-PASS diff --git a/build/pymake/tests/functions.mk b/build/pymake/tests/functions.mk new file mode 100644 index 0000000000..817be07aab --- /dev/null +++ b/build/pymake/tests/functions.mk @@ -0,0 +1,36 @@ +all: + test "$(subst e,EE,hello)" = "hEEllo" + test "$(strip $(NULL) test data )" = "test data" + test "$(findstring hell,hello)" = "hell" + test "$(findstring heaven,hello)" = "" + test "$(filter foo/%.c b%,foo/a.c b.c foo/a.o)" = "foo/a.c b.c" + test "$(filter foo,foo bar)" = "foo" + test "$(filter-out foo/%.c b%,foo/a.c b.c foo/a.o)" = "foo/a.o" + test "$(filter-out %.c,foo,bar.c foo,bar.o)" = "foo,bar.o" + test "$(sort .go a b aa A c cc)" = ".go A a aa b c cc" + test "$(word 1, hello )" = "hello" + test "$(word 2, hello )" = "" + test "$(wordlist 1, 2, foo bar baz )" = "foo bar" + test "$(words 1 2 3)" = "3" + test "$(words )" = "0" + test "$(firstword $(NULL) foo bar baz)" = "foo" + test "$(firstword )" = "" + test "$(dir foo.c path/foo.o dir/dir2/)" = "./ path/ dir/dir2/" + test "$(notdir foo.c path/foo.o dir/dir2/)" = "foo.c foo.o " + test "$(suffix src/foo.c dir/my.dir/foo foo.o)" = ".c .o" + test "$(basename src/foo.c dir/my.dir/foo foo.c .c)" = "src/foo dir/my.dir/foo foo " + test "$(addprefix src/,foo bar.c dir/foo)" = "src/foo src/bar.c src/dir/foo" + test "$(addsuffix .c,foo dir/bar)" = "foo.c dir/bar.c" + test "$(join a b c, 1 2 3)" = "a1 b2 c3" + test "$(join a b, 1 2 3)" = "a1 b2 3" + test "$(join a b c, 1 2)" = "a1 b2 c" + test "$(if $(NULL) ,yes)" = "" + test "$(if 1,yes,no)" = "yes" + test "$(if ,yes,no )" = "no " + test "$(if ,$(error Short-circuit problem))" = "" + test "$(or $(NULL),1)" = "1" + test "$(or $(NULL),2,$(warning TEST-FAIL bad or short-circuit))" = "2" + test "$(and ,$(warning TEST-FAIL bad and short-circuit))" = "" + test "$(and 1,2)" = "2" + test "$(foreach i,foo bar,found:$(i))" = "found:foo found:bar" + @echo TEST-PASS diff --git a/build/pymake/tests/functiontests.py b/build/pymake/tests/functiontests.py new file mode 100644 index 0000000000..43a344a059 --- /dev/null +++ b/build/pymake/tests/functiontests.py @@ -0,0 +1,54 @@ +import unittest + +import pymake.data +import pymake.functions + +class VariableRefTest(unittest.TestCase): + def test_get_expansions(self): + e = pymake.data.StringExpansion('FOO', None) + f = pymake.functions.VariableRef(None, e) + + exps = list(f.expansions()) + self.assertEqual(len(exps), 1) + +class GetExpansionsTest(unittest.TestCase): + def test_get_arguments(self): + f = pymake.functions.SubstFunction(None) + + e1 = pymake.data.StringExpansion('FOO', None) + e2 = pymake.data.StringExpansion('BAR', None) + e3 = pymake.data.StringExpansion('BAZ', None) + + f.append(e1) + f.append(e2) + f.append(e3) + + exps = list(f.expansions()) + self.assertEqual(len(exps), 3) + + def test_descend(self): + f = pymake.functions.StripFunction(None) + + e = pymake.data.Expansion(None) + + e1 = pymake.data.StringExpansion('FOO', None) + f1 = pymake.functions.VariableRef(None, e1) + e.appendfunc(f1) + + f2 = pymake.functions.WildcardFunction(None) + e2 = pymake.data.StringExpansion('foo/*', None) + f2.append(e2) + e.appendfunc(f2) + + f.append(e) + + exps = list(f.expansions()) + self.assertEqual(len(exps), 1) + + exps = list(f.expansions(True)) + self.assertEqual(len(exps), 3) + + self.assertFalse(f.is_filesystem_dependent) + +if __name__ == '__main__': + unittest.main() diff --git a/build/pymake/tests/if-syntaxerr.mk b/build/pymake/tests/if-syntaxerr.mk new file mode 100644 index 0000000000..c172492ef3 --- /dev/null +++ b/build/pymake/tests/if-syntaxerr.mk @@ -0,0 +1,6 @@ +#T returncode: 2 + +ifeq ($(FOO,VAR)) +all: + @echo TEST_FAIL +endif diff --git a/build/pymake/tests/ifdefs-nesting.mk b/build/pymake/tests/ifdefs-nesting.mk new file mode 100644 index 0000000000..340530ffa9 --- /dev/null +++ b/build/pymake/tests/ifdefs-nesting.mk @@ -0,0 +1,13 @@ +ifdef RANDOM +ifeq (,$(error Not evaluated!)) +endif +endif + +ifdef RANDOM +ifeq (,) +else ifeq (,$(error Not evaluated!)) +endif +endif + +all: + @echo TEST-PASS diff --git a/build/pymake/tests/ifdefs.mk b/build/pymake/tests/ifdefs.mk new file mode 100644 index 0000000000..a779d197b8 --- /dev/null +++ b/build/pymake/tests/ifdefs.mk @@ -0,0 +1,127 @@ +ifdef FOO +$(error FOO is not defined!) +endif + +FOO = foo +FOOFOUND = false +BARFOUND = false +BAZFOUND = false + +ifdef FOO +FOOFOUND = true +else ifdef BAR +BARFOUND = true +else +BAZFOUND = true +endif + +BAR2 = bar2 +FOO2FOUND = false +BAR2FOUND = false +BAZ2FOUND = false + +ifdef FOO2 +FOO2FOUND = true +else ifdef BAR2 +BAR2FOUND = true +else +BAZ2FOUND = true +endif + +FOO3FOUND = false +BAR3FOUND = false +BAZ3FOUND = false + +ifdef FOO3 +FOO3FOUND = true +else ifdef BAR3 +BAR3FOUND = true +else +BAZ3FOUND = true +endif + +ifdef RANDOM +CONTINUATION = \ +else \ +endif +endif + +ifndef ASDFJK +else +$(error ASFDJK was not set) +endif + +TESTSET = + +ifdef TESTSET +$(error TESTSET was not set) +endif + +TESTEMPTY = $(NULL) +ifndef TESTEMPTY +$(error TEST-FAIL TESTEMPTY was probably expanded!) +endif + +# ifneq ( a,a) +# $(error Arguments to ifeq should be stripped before evaluation) +# endif + +XSPACE = x # trick + +ifneq ($(NULL),$(NULL)) +$(error TEST-FAIL ifneq) +endif + +ifneq (x , x) +$(error argument-stripping1) +endif + +ifeq ( x,x ) +$(error argument-stripping2) +endif + +ifneq ($(XSPACE), x ) +$(error argument-stripping3) +endif + +ifeq 'x ' ' x' +$(error TEST-FAIL argument-stripping4) +endif + +all: + test $(FOOFOUND) = true # FOOFOUND + test $(BARFOUND) = false # BARFOUND + test $(BAZFOUND) = false # BAZFOUND + test $(FOO2FOUND) = false # FOO2FOUND + test $(BAR2FOUND) = true # BAR2FOUND + test $(BAZ2FOUND) = false # BAZ2FOUND + test $(FOO3FOUND) = false # FOO3FOUND + test $(BAR3FOUND) = false # BAR3FOUND + test $(BAZ3FOUND) = true # BAZ3FOUND +ifneq ($(FOO),foo) + echo TEST-FAIL 'FOO neq foo: "$(FOO)"' +endif +ifneq ($(FOO), foo) # Whitespace after the comma is stripped + echo TEST-FAIL 'FOO plus whitespace' +endif +ifeq ($(FOO), foo ) # But not trailing whitespace + echo TEST-FAIL 'FOO plus trailing whitespace' +endif +ifeq ( $(FOO),foo) # Not whitespace after the paren + echo TEST-FAIL 'FOO with leading whitespace' +endif +ifeq ($(FOO),$(NULL) foo) # Nor whitespace after expansion + echo TEST-FAIL 'FOO with embedded ws' +endif +ifeq ($(BAR2),bar) + echo TEST-FAIL 'BAR2 eq bar' +endif +ifeq '$(BAR3FOUND)' 'false' + echo BAR3FOUND is ok +else + echo TEST-FAIL BAR3FOUND is not ok +endif +ifndef FOO + echo TEST-FAIL "foo not defined?" +endif + @echo TEST-PASS diff --git a/build/pymake/tests/ignore-error.mk b/build/pymake/tests/ignore-error.mk new file mode 100644 index 0000000000..dc8d3a72c9 --- /dev/null +++ b/build/pymake/tests/ignore-error.mk @@ -0,0 +1,13 @@ +all: + -rm foo + +-rm bar + -+rm baz + @-rm bah + -@rm humbug + +-@rm sincere + +@-rm flattery + @+-rm will + @-+rm not + -+@rm save + -@+rm you + @echo TEST-PASS diff --git a/build/pymake/tests/implicit-chain.mk b/build/pymake/tests/implicit-chain.mk new file mode 100644 index 0000000000..16288b3f5a --- /dev/null +++ b/build/pymake/tests/implicit-chain.mk @@ -0,0 +1,12 @@ +all: test.prog + test "$$(cat $<)" = "Program: Object: Source: test.source" + @echo TEST-PASS + +%.prog: %.object + printf "Program: %s" "$$(cat $<)" > $@ + +%.object: %.source + printf "Object: %s" "$$(cat $<)" > $@ + +%.source: + printf "Source: %s" $@ > $@ diff --git a/build/pymake/tests/implicit-dir.mk b/build/pymake/tests/implicit-dir.mk new file mode 100644 index 0000000000..c7f75e8d42 --- /dev/null +++ b/build/pymake/tests/implicit-dir.mk @@ -0,0 +1,16 @@ +# Implicit rules have special instructions to deal with directories, so that a pattern rule which doesn't directly apply +# may still be used. + +all: dir/host_test.otest + +host_%.otest: %.osource extra.file + @echo making $@ from $< + +test.osource: + @echo TEST-FAIL should have made dir/test.osource + +dir/test.osource: + @echo TEST-PASS made the correct dependency + +extra.file: + @echo building $@ diff --git a/build/pymake/tests/implicit-terminal.mk b/build/pymake/tests/implicit-terminal.mk new file mode 100644 index 0000000000..db2e244ed4 --- /dev/null +++ b/build/pymake/tests/implicit-terminal.mk @@ -0,0 +1,16 @@ +#T returncode: 2 + +# the %.object rule is "terminal". This means that additional implicit rules cannot be chained to it. + +all: test.prog + test "$$(cat $<)" = "Program: Object: Source: test.source" + @echo TEST-FAIL + +%.prog: %.object + printf "Program: %s" "$$(cat $<)" > $@ + +%.object:: %.source + printf "Object: %s" "$$(cat $<)" > $@ + +%.source: + printf "Source: %s" $@ > $@ diff --git a/build/pymake/tests/implicitsubdir.mk b/build/pymake/tests/implicitsubdir.mk new file mode 100644 index 0000000000..b9d854a2a5 --- /dev/null +++ b/build/pymake/tests/implicitsubdir.mk @@ -0,0 +1,12 @@ +$(shell \ +mkdir foo; \ +touch test.in \ +) + +all: foo/test.out + @echo TEST-PASS + +foo/%.out: %.in + cp $< $@ + + diff --git a/build/pymake/tests/include-dynamic.mk b/build/pymake/tests/include-dynamic.mk new file mode 100644 index 0000000000..571895dc3c --- /dev/null +++ b/build/pymake/tests/include-dynamic.mk @@ -0,0 +1,21 @@ +$(shell \ +if ! test -f include-dynamic.inc; then \ + echo "TESTVAR = oldval" > include-dynamic.inc; \ + sleep 2; \ + echo "TESTVAR = newval" > include-dynamic.inc.in; \ +fi \ +) + +# before running the 'all' rule, we should be rebuilding include-dynamic.inc, +# because there is a rule to do so + +all: + test $(TESTVAR) = newval + test "$(MAKE_RESTARTS)" = 1 + @echo TEST-PASS + +include-dynamic.inc: include-dynamic.inc.in + test "$(MAKE_RESTARTS)" = "" + cp $< $@ + +include include-dynamic.inc diff --git a/build/pymake/tests/include-file.inc b/build/pymake/tests/include-file.inc new file mode 100644 index 0000000000..d5d495dec8 --- /dev/null +++ b/build/pymake/tests/include-file.inc @@ -0,0 +1 @@ +INCLUDED = yes diff --git a/build/pymake/tests/include-missing.mk b/build/pymake/tests/include-missing.mk new file mode 100644 index 0000000000..583d0a065a --- /dev/null +++ b/build/pymake/tests/include-missing.mk @@ -0,0 +1,9 @@ +#T returncode: 2 + +# If an include file isn't present and doesn't have a rule to remake it, make +# should fail. + +include notfound.mk + +all: + @echo TEST-FAIL diff --git a/build/pymake/tests/include-notfound.mk b/build/pymake/tests/include-notfound.mk new file mode 100644 index 0000000000..1ee7e05b28 --- /dev/null +++ b/build/pymake/tests/include-notfound.mk @@ -0,0 +1,19 @@ +ifdef __WIN32__ +PS:=\\# +else +PS:=/ +endif + +ifneq ($(strip $(MAKEFILE_LIST)),$(NATIVE_TESTPATH)$(PS)include-notfound.mk) +$(error MAKEFILE_LIST incorrect: '$(MAKEFILE_LIST)' (expected '$(NATIVE_TESTPATH)$(PS)include-notfound.mk')) +endif + +-include notfound.inc-dummy + +ifneq ($(strip $(MAKEFILE_LIST)),$(NATIVE_TESTPATH)$(PS)include-notfound.mk) +$(error MAKEFILE_LIST incorrect: '$(MAKEFILE_LIST)' (expected '$(NATIVE_TESTPATH)$(PS)include-notfound.mk')) +endif + +all: + @echo TEST-PASS + diff --git a/build/pymake/tests/include-optional-warning.mk b/build/pymake/tests/include-optional-warning.mk new file mode 100644 index 0000000000..901938dffc --- /dev/null +++ b/build/pymake/tests/include-optional-warning.mk @@ -0,0 +1,4 @@ +-include TEST-FAIL.mk + +all: + @echo TEST-PASS diff --git a/build/pymake/tests/include-regen.mk b/build/pymake/tests/include-regen.mk new file mode 100644 index 0000000000..c86e0c78d6 --- /dev/null +++ b/build/pymake/tests/include-regen.mk @@ -0,0 +1,10 @@ +# avoid infinite loops by not remaking makefiles with +# double-colon no-dependency rules +# http://www.gnu.org/software/make/manual/make.html#Remaking-Makefiles +-include notfound.mk + +all: + @echo TEST-PASS + +notfound.mk:: + @echo TEST-FAIL diff --git a/build/pymake/tests/include-regen2.mk b/build/pymake/tests/include-regen2.mk new file mode 100644 index 0000000000..fc7fef073e --- /dev/null +++ b/build/pymake/tests/include-regen2.mk @@ -0,0 +1,10 @@ +# make should make makefiles that it has rules for if they are
+# included
+include test.mk
+
+all:
+ test "$(X)" = "1"
+ @echo "TEST-PASS"
+
+test.mk:
+ @echo "X = 1" > $@
diff --git a/build/pymake/tests/include-regen3.mk b/build/pymake/tests/include-regen3.mk new file mode 100644 index 0000000000..878ce0adc6 --- /dev/null +++ b/build/pymake/tests/include-regen3.mk @@ -0,0 +1,10 @@ +# make should make makefiles that it has rules for if they are
+# included
+-include test.mk
+
+all:
+ test "$(X)" = "1"
+ @echo "TEST-PASS"
+
+test.mk:
+ @echo "X = 1" > $@
diff --git a/build/pymake/tests/include-test.mk b/build/pymake/tests/include-test.mk new file mode 100644 index 0000000000..3608fc2690 --- /dev/null +++ b/build/pymake/tests/include-test.mk @@ -0,0 +1,8 @@ +$(shell echo "INCLUDED2 = yes" >local-include.inc) + +include $(TESTPATH)/include-file.inc local-include.inc + +all: + test "$(INCLUDED)" = "yes" + test "$(INCLUDED2)" = "yes" + @echo TEST-PASS diff --git a/build/pymake/tests/includedeps-norebuild.mk b/build/pymake/tests/includedeps-norebuild.mk new file mode 100644 index 0000000000..e30abd4397 --- /dev/null +++ b/build/pymake/tests/includedeps-norebuild.mk @@ -0,0 +1,15 @@ +#T gmake skip + +$(shell \ +touch filemissing; \ +sleep 2; \ +touch file1; \ +) + +all: file1 + @echo TEST-PASS + +includedeps $(TESTPATH)/includedeps.deps + +file1: + @echo TEST-FAIL diff --git a/build/pymake/tests/includedeps-sideeffects.mk b/build/pymake/tests/includedeps-sideeffects.mk new file mode 100644 index 0000000000..7e4ea30a2d --- /dev/null +++ b/build/pymake/tests/includedeps-sideeffects.mk @@ -0,0 +1,10 @@ +#T gmake skip +#T returncode: 2 + +all: file1 filemissing + @echo TEST-PASS + +includedeps $(TESTPATH)/includedeps.deps + +file: + touch $@ diff --git a/build/pymake/tests/includedeps-stripdotslash.deps b/build/pymake/tests/includedeps-stripdotslash.deps new file mode 100644 index 0000000000..352fca1bb9 --- /dev/null +++ b/build/pymake/tests/includedeps-stripdotslash.deps @@ -0,0 +1 @@ +./test: TEST-PASS diff --git a/build/pymake/tests/includedeps-stripdotslash.mk b/build/pymake/tests/includedeps-stripdotslash.mk new file mode 100644 index 0000000000..ee942e6dbb --- /dev/null +++ b/build/pymake/tests/includedeps-stripdotslash.mk @@ -0,0 +1,8 @@ +#T gmake skip + +test: + @echo $< + +includedeps $(TESTPATH)/includedeps-stripdotslash.deps + +TEST-PASS: diff --git a/build/pymake/tests/includedeps-variables.deps b/build/pymake/tests/includedeps-variables.deps new file mode 100644 index 0000000000..ba69e9b6cc --- /dev/null +++ b/build/pymake/tests/includedeps-variables.deps @@ -0,0 +1 @@ +$(FILE)1: filemissing diff --git a/build/pymake/tests/includedeps-variables.mk b/build/pymake/tests/includedeps-variables.mk new file mode 100644 index 0000000000..314618da4e --- /dev/null +++ b/build/pymake/tests/includedeps-variables.mk @@ -0,0 +1,10 @@ +#T gmake skip + +FILE = includedeps-variables + +all: $(FILE)1 + +includedeps $(TESTPATH)/includedeps-variables.deps + +filemissing: + @echo TEST-PASS diff --git a/build/pymake/tests/includedeps.deps b/build/pymake/tests/includedeps.deps new file mode 100644 index 0000000000..d3017c078f --- /dev/null +++ b/build/pymake/tests/includedeps.deps @@ -0,0 +1 @@ +file1: filemissing diff --git a/build/pymake/tests/includedeps.mk b/build/pymake/tests/includedeps.mk new file mode 100644 index 0000000000..deaa71fe8c --- /dev/null +++ b/build/pymake/tests/includedeps.mk @@ -0,0 +1,9 @@ +#T gmake skip + +all: file1 + @echo TEST-PASS + +includedeps $(TESTPATH)/includedeps.deps + +file1: + touch $@ diff --git a/build/pymake/tests/info.mk b/build/pymake/tests/info.mk new file mode 100644 index 0000000000..8dddfd8155 --- /dev/null +++ b/build/pymake/tests/info.mk @@ -0,0 +1,8 @@ +#T grep-for: "info-printed\ninfo-nth" +all: + +INFO = info-printed + +$(info $(INFO)) +$(info $(subst second,nth,info-second)) +$(info TEST-PASS) diff --git a/build/pymake/tests/justprint-native.mk b/build/pymake/tests/justprint-native.mk new file mode 100644 index 0000000000..580e402e97 --- /dev/null +++ b/build/pymake/tests/justprint-native.mk @@ -0,0 +1,28 @@ +## $(TOUCH) and $(RM) are native commands in pymake.
+## Test that pymake --just-print just prints them.
+
+ifndef TOUCH
+TOUCH = touch
+endif
+
+all:
+ $(RM) justprint-native-file1.txt
+ $(TOUCH) justprint-native-file2.txt
+ $(MAKE) --just-print -f $(TESTPATH)/justprint-native.mk justprint_target > justprint.log
+# make --just-print shouldn't have actually done anything.
+ test ! -f justprint-native-file1.txt
+ test -f justprint-native-file2.txt
+# but it should have printed each command
+ grep -q 'touch justprint-native-file1.txt' justprint.log
+ grep -q 'rm -f justprint-native-file2.txt' justprint.log
+ grep -q 'this string is "unlikely to appear in the log by chance"' justprint.log
+# tidy up
+ $(RM) justprint-native-file2.txt
+ @echo TEST-PASS
+
+justprint_target:
+ $(TOUCH) justprint-native-file1.txt
+ $(RM) justprint-native-file2.txt
+ this string is "unlikely to appear in the log by chance"
+
+.PHONY: justprint_target
diff --git a/build/pymake/tests/justprint.mk b/build/pymake/tests/justprint.mk new file mode 100644 index 0000000000..be11ba8dec --- /dev/null +++ b/build/pymake/tests/justprint.mk @@ -0,0 +1,5 @@ +#T commandline: ['-n']
+
+all:
+ false # without -n, we wouldn't get past this
+ TEST-PASS # heh
diff --git a/build/pymake/tests/keep-going-doublecolon.mk b/build/pymake/tests/keep-going-doublecolon.mk new file mode 100644 index 0000000000..fa5b31df81 --- /dev/null +++ b/build/pymake/tests/keep-going-doublecolon.mk @@ -0,0 +1,16 @@ +#T commandline: ['-k'] +#T returncode: 2 +#T grep-for: "TEST-PASS" + +all:: t1 + @echo TEST-FAIL "(t1)" + +all:: t2 + @echo TEST-PASS + +t1: + @false + +t2: + touch $@ + diff --git a/build/pymake/tests/keep-going-parallel.mk b/build/pymake/tests/keep-going-parallel.mk new file mode 100644 index 0000000000..a91d1a6ed5 --- /dev/null +++ b/build/pymake/tests/keep-going-parallel.mk @@ -0,0 +1,11 @@ +#T commandline: ['-k', '-j2'] +#T returncode: 2 +#T grep-for: "TEST-PASS" + +all: t1 slow1 slow2 slow3 t2 + +t2: + @echo TEST-PASS + +slow%: + sleep 1 diff --git a/build/pymake/tests/keep-going.mk b/build/pymake/tests/keep-going.mk new file mode 100644 index 0000000000..4c709288ca --- /dev/null +++ b/build/pymake/tests/keep-going.mk @@ -0,0 +1,14 @@ +#T commandline: ['-k'] +#T returncode: 2 +#T grep-for: "TEST-PASS" + +all: t2 t3 + +t1: + @false + +t2: t1 + @echo TEST-FAIL + +t3: + @echo TEST-PASS diff --git a/build/pymake/tests/line-continuations.mk b/build/pymake/tests/line-continuations.mk new file mode 100644 index 0000000000..8b44480eae --- /dev/null +++ b/build/pymake/tests/line-continuations.mk @@ -0,0 +1,24 @@ +VAR = val1 \ + val2 + +VAR2 = val1space\ +val2 + +VAR3 = val3 \\\ + cont3 + +all: otarget test.target + test "$(VAR)" = "val1 val2 " + test "$(VAR2)" = "val1space val2" + test '$(VAR3)' = 'val3 \ cont3' + test "hello \ + world" = "hello world" + test "hello" = \ +"hello" + @echo TEST-PASS + +otarget: ; test "hello\ + world" = "helloworld" + +test.target: %.target: ; test "hello\ + world" = "helloworld" diff --git a/build/pymake/tests/link-search.mk b/build/pymake/tests/link-search.mk new file mode 100644 index 0000000000..ea827f3913 --- /dev/null +++ b/build/pymake/tests/link-search.mk @@ -0,0 +1,7 @@ +$(shell \ +touch libfoo.so \ +) + +all: -lfoo + test "$<" = "libfoo.so" + @echo TEST-PASS diff --git a/build/pymake/tests/makeflags.mk b/build/pymake/tests/makeflags.mk new file mode 100644 index 0000000000..288ff78663 --- /dev/null +++ b/build/pymake/tests/makeflags.mk @@ -0,0 +1,7 @@ +#T environment: {'MAKEFLAGS': 'OVAR=oval'} + +all: + test "$(OVAR)" = "oval" + test "$$OVAR" = "oval" + @echo TEST-PASS + diff --git a/build/pymake/tests/matchany.mk b/build/pymake/tests/matchany.mk new file mode 100644 index 0000000000..7876c90a31 --- /dev/null +++ b/build/pymake/tests/matchany.mk @@ -0,0 +1,14 @@ +#T returncode: 2 + +# we should fail to make foo.ooo from foo.ooo.test +all: foo.ooo + @echo TEST-FAIL + +%.ooo: + +# this match-anything pattern should not apply to %.ooo +%: %.test + cp $< $@ + +foo.ooo.test: + touch $@ diff --git a/build/pymake/tests/matchany2.mk b/build/pymake/tests/matchany2.mk new file mode 100644 index 0000000000..d21d9702cb --- /dev/null +++ b/build/pymake/tests/matchany2.mk @@ -0,0 +1,13 @@ +# we should succeed in making foo.ooo from foo.ooo.test +all: foo.ooo + @echo TEST-PASS + +%.ooo: %.ccc + exit 1 + +# this match-anything rule is terminal, and therefore applies +%:: %.test + cp $< $@ + +foo.ooo.test: + touch $@ diff --git a/build/pymake/tests/matchany3.mk b/build/pymake/tests/matchany3.mk new file mode 100644 index 0000000000..83de8af2b7 --- /dev/null +++ b/build/pymake/tests/matchany3.mk @@ -0,0 +1,10 @@ +$(shell \ +echo "target" > target.in; \ +) + +all: target + test "$$(cat $^)" = "target" + @echo TEST-PASS + +%: %.in + cp $< $@ diff --git a/build/pymake/tests/mkdir-fail.mk b/build/pymake/tests/mkdir-fail.mk new file mode 100644 index 0000000000..b05734aa90 --- /dev/null +++ b/build/pymake/tests/mkdir-fail.mk @@ -0,0 +1,7 @@ +#T returncode: 2 +all: + mkdir newdir/subdir + test ! -d newdir/subdir + test ! -d newdir + rm -r newdir + @echo TEST-PASS diff --git a/build/pymake/tests/mkdir.mk b/build/pymake/tests/mkdir.mk new file mode 100644 index 0000000000..413348f77d --- /dev/null +++ b/build/pymake/tests/mkdir.mk @@ -0,0 +1,27 @@ +MKDIR ?= mkdir + +all: + $(MKDIR) newdir + test -d newdir + # subdir, parent exists + $(MKDIR) newdir/subdir + test -d newdir/subdir + # -p, existing dir + $(MKDIR) -p newdir + # -p, existing subdir + $(MKDIR) -p newdir/subdir + # multiple subdirs, existing parent + $(MKDIR) newdir/subdir1 newdir/subdir2 + test -d newdir/subdir1 -a -d newdir/subdir2 + rm -r newdir + # -p, subdir, no existing parent + $(MKDIR) -p newdir/subdir + test -d newdir/subdir + rm -r newdir + # -p, multiple subdirs, no existing parent + $(MKDIR) -p newdir/subdir1 newdir/subdir2 + test -d newdir/subdir1 -a -d newdir/subdir2 + # -p, multiple existing subdirs + $(MKDIR) -p newdir/subdir1 newdir/subdir2 + rm -r newdir + @echo TEST-PASS diff --git a/build/pymake/tests/multiple-rules-prerequisite-merge.mk b/build/pymake/tests/multiple-rules-prerequisite-merge.mk new file mode 100644 index 0000000000..480d3b58c4 --- /dev/null +++ b/build/pymake/tests/multiple-rules-prerequisite-merge.mk @@ -0,0 +1,25 @@ +# When a target is defined multiple times, the prerequisites should get +# merged. + +default: foo bar baz + +foo: + test "$<" = "foo.in1" + @echo TEST-PASS + +foo: foo.in1 + +bar: bar.in1 + test "$<" = "bar.in1" + test "$^" = "bar.in1 bar.in2" + @echo TEST-PASS + +bar: bar.in2 + +baz: baz.in2 +baz: baz.in1 + test "$<" = "baz.in1" + test "$^" = "baz.in1 baz.in2" + @echo TEST-PASS + +foo.in1 bar.in1 bar.in2 baz.in1 baz.in2: diff --git a/build/pymake/tests/native-command-delay-load.mk b/build/pymake/tests/native-command-delay-load.mk new file mode 100644 index 0000000000..a9f3774eb4 --- /dev/null +++ b/build/pymake/tests/native-command-delay-load.mk @@ -0,0 +1,12 @@ +#T gmake skip + +# This test exists to verify that sys.path is adjusted during command +# execution and that delay importing a module will work. + +CMD = %pycmd delayloadfn +PYCOMMANDPATH = $(TESTPATH) $(TESTPATH)/subdir + +all: + $(CMD) + @echo TEST-PASS + diff --git a/build/pymake/tests/native-command-raise.mk b/build/pymake/tests/native-command-raise.mk new file mode 100644 index 0000000000..d1b28b3316 --- /dev/null +++ b/build/pymake/tests/native-command-raise.mk @@ -0,0 +1,9 @@ +#T gmake skip +#T returncode: 2 +#T grep-for: "Exception: info-exception" + +CMD = %pycmd asplode_raise +PYCOMMANDPATH = $(TESTPATH) $(TESTPATH)/subdir + +all: + @$(CMD) info-exception diff --git a/build/pymake/tests/native-command-return-fail1.mk b/build/pymake/tests/native-command-return-fail1.mk new file mode 100644 index 0000000000..0cf085ae24 --- /dev/null +++ b/build/pymake/tests/native-command-return-fail1.mk @@ -0,0 +1,8 @@ +#T gmake skip +#T returncode: 2 + +CMD = %pycmd asplode_return +PYCOMMANDPATH = $(TESTPATH) $(TESTPATH)/subdir + +all: + $(CMD) 1 diff --git a/build/pymake/tests/native-command-return-fail2.mk b/build/pymake/tests/native-command-return-fail2.mk new file mode 100644 index 0000000000..c071fc879b --- /dev/null +++ b/build/pymake/tests/native-command-return-fail2.mk @@ -0,0 +1,8 @@ +#T gmake skip +#T returncode: 2 + +CMD = %pycmd asplode_return +PYCOMMANDPATH = $(TESTPATH) $(TESTPATH)/subdir + +all: + $(CMD) not-an-integer diff --git a/build/pymake/tests/native-command-return.mk b/build/pymake/tests/native-command-return.mk new file mode 100644 index 0000000000..3e4d2e0c48 --- /dev/null +++ b/build/pymake/tests/native-command-return.mk @@ -0,0 +1,11 @@ +#T gmake skip + +CMD = %pycmd asplode_return +PYCOMMANDPATH = $(TESTPATH) $(TESTPATH)/subdir + +all: + $(CMD) 0 + -$(CMD) 1 + $(CMD) None + -$(CMD) not-an-integer + @echo TEST-PASS diff --git a/build/pymake/tests/native-command-shell-glob.mk b/build/pymake/tests/native-command-shell-glob.mk new file mode 100644 index 0000000000..4bcdad8b9e --- /dev/null +++ b/build/pymake/tests/native-command-shell-glob.mk @@ -0,0 +1,11 @@ +#T gmake skip +all: + mkdir shell-glob-test + touch shell-glob-test/foo.txt + touch shell-glob-test/bar.txt + touch shell-glob-test/a.foo + touch shell-glob-test/b.foo + $(RM) shell-glob-test/*.txt + $(RM) shell-glob-test/?.foo + rmdir shell-glob-test + @echo TEST-PASS diff --git a/build/pymake/tests/native-command-sys-exit-fail1.mk b/build/pymake/tests/native-command-sys-exit-fail1.mk new file mode 100644 index 0000000000..8e74800ed5 --- /dev/null +++ b/build/pymake/tests/native-command-sys-exit-fail1.mk @@ -0,0 +1,8 @@ +#T gmake skip +#T returncode: 2 + +CMD = %pycmd asplode +PYCOMMANDPATH = $(TESTPATH) $(TESTPATH)/subdir + +all: + $(CMD) 1 diff --git a/build/pymake/tests/native-command-sys-exit-fail2.mk b/build/pymake/tests/native-command-sys-exit-fail2.mk new file mode 100644 index 0000000000..0a04395ad7 --- /dev/null +++ b/build/pymake/tests/native-command-sys-exit-fail2.mk @@ -0,0 +1,8 @@ +#T gmake skip +#T returncode: 2 + +CMD = %pycmd asplode +PYCOMMANDPATH = $(TESTPATH) $(TESTPATH)/subdir + +all: + $(CMD) not-an-integer diff --git a/build/pymake/tests/native-command-sys-exit.mk b/build/pymake/tests/native-command-sys-exit.mk new file mode 100644 index 0000000000..c04913acaf --- /dev/null +++ b/build/pymake/tests/native-command-sys-exit.mk @@ -0,0 +1,11 @@ +#T gmake skip + +CMD = %pycmd asplode +PYCOMMANDPATH = $(TESTPATH) $(TESTPATH)/subdir + +all: + $(CMD) 0 + -$(CMD) 1 + $(CMD) None + -$(CMD) not-an-integer + @echo TEST-PASS diff --git a/build/pymake/tests/native-environment.mk b/build/pymake/tests/native-environment.mk new file mode 100644 index 0000000000..36bd5894a0 --- /dev/null +++ b/build/pymake/tests/native-environment.mk @@ -0,0 +1,11 @@ +#T gmake skip +export EXPECTED := some data + +PYCOMMANDPATH = $(TESTPATH) + +all: + %pycmd writeenvtofile results EXPECTED + test "$$(cat results)" = "$(EXPECTED)" + %pycmd writesubprocessenvtofile results EXPECTED + test "$$(cat results)" = "$(EXPECTED)" + @echo TEST-PASS diff --git a/build/pymake/tests/native-pycommandpath-sep.mk b/build/pymake/tests/native-pycommandpath-sep.mk new file mode 100644 index 0000000000..b1c2c2b97e --- /dev/null +++ b/build/pymake/tests/native-pycommandpath-sep.mk @@ -0,0 +1,21 @@ +#T gmake skip +EXPECTED := some data + +# verify that we can load native command modules from +# multiple directories in PYCOMMANDPATH separated by the native +# path separator +ifdef __WIN32__ +PS:=; +else +PS:=: +endif +CMD = %pycmd writetofile +CMD2 = %pymod writetofile +PYCOMMANDPATH = $(TESTPATH)$(PS)$(TESTPATH)/subdir + +all: + $(CMD) results $(EXPECTED) + test "$$(cat results)" = "$(EXPECTED)" + $(CMD2) results2 $(EXPECTED) + test "$$(cat results2)" = "$(EXPECTED)" + @echo TEST-PASS diff --git a/build/pymake/tests/native-pycommandpath.mk b/build/pymake/tests/native-pycommandpath.mk new file mode 100644 index 0000000000..dd0fbc9f9b --- /dev/null +++ b/build/pymake/tests/native-pycommandpath.mk @@ -0,0 +1,15 @@ +#T gmake skip +EXPECTED := some data + +# verify that we can load native command modules from +# multiple space-separated directories in PYCOMMANDPATH +CMD = %pycmd writetofile +CMD2 = %pymod writetofile +PYCOMMANDPATH = $(TESTPATH) $(TESTPATH)/subdir + +all: + $(CMD) results $(EXPECTED) + test "$$(cat results)" = "$(EXPECTED)" + $(CMD2) results2 $(EXPECTED) + test "$$(cat results2)" = "$(EXPECTED)" + @echo TEST-PASS diff --git a/build/pymake/tests/native-simple.mk b/build/pymake/tests/native-simple.mk new file mode 100644 index 0000000000..626a586705 --- /dev/null +++ b/build/pymake/tests/native-simple.mk @@ -0,0 +1,12 @@ +ifndef TOUCH
+TOUCH = touch
+endif
+
+all: testfile {testfile2} (testfile3)
+ test -f testfile
+ test -f {testfile2}
+ test -f "(testfile3)"
+ @echo TEST-PASS
+
+testfile {testfile2} (testfile3):
+ $(TOUCH) "$@"
diff --git a/build/pymake/tests/native-touch.mk b/build/pymake/tests/native-touch.mk new file mode 100644 index 0000000000..811161ece7 --- /dev/null +++ b/build/pymake/tests/native-touch.mk @@ -0,0 +1,15 @@ +TOUCH ?= touch + +foo: + $(TOUCH) bar + $(TOUCH) baz + $(MAKE) -f $(TESTPATH)/native-touch.mk baz + $(TOUCH) -t 198007040802 baz + $(MAKE) -f $(TESTPATH)/native-touch.mk baz + +bar: + $(TOUCH) $@ + +baz: bar + echo TEST-PASS + $(TOUCH) $@ diff --git a/build/pymake/tests/newlines.mk b/build/pymake/tests/newlines.mk new file mode 100644 index 0000000000..5d8195c949 --- /dev/null +++ b/build/pymake/tests/newlines.mk @@ -0,0 +1,30 @@ +#T gmake skip + +# Test that we handle \\\n properly + +all: dep1 dep2 dep3 + cat testfile + test `cat testfile` = "data"; + test "$$(cat results)" = "$(EXPECTED)"; + @echo TEST-PASS + +# Test that something that still needs to go to the shell works +testfile: + printf "data" \ + >>$@ + +dep1: testfile + +# Test that something that does not need to go to the shell works +dep2: + $(echo foo) \ + $(echo bar) + +export EXPECTED := some data + +CMD = %pycmd writeenvtofile +PYCOMMANDPATH = $(TESTPATH) + +dep3: + $(CMD) \ + results EXPECTED diff --git a/build/pymake/tests/no-remake.mk b/build/pymake/tests/no-remake.mk new file mode 100644 index 0000000000..c8df81bc32 --- /dev/null +++ b/build/pymake/tests/no-remake.mk @@ -0,0 +1,7 @@ +$(shell date >testfile) + +all: testfile + @echo TEST-PASS + +testfile: + @echo TEST-FAIL "We shouldn't have remade this!" diff --git a/build/pymake/tests/nosuchfile.mk b/build/pymake/tests/nosuchfile.mk new file mode 100644 index 0000000000..cca9ce1e94 --- /dev/null +++ b/build/pymake/tests/nosuchfile.mk @@ -0,0 +1,4 @@ +#T returncode: 2 + +all: + reallythereisnosuchcommand diff --git a/build/pymake/tests/notargets.mk b/build/pymake/tests/notargets.mk new file mode 100644 index 0000000000..8e55d944f6 --- /dev/null +++ b/build/pymake/tests/notargets.mk @@ -0,0 +1,5 @@ +$(NULL): foo.c + @echo TEST-FAIL + +all: + @echo TEST-PASS diff --git a/build/pymake/tests/notparallel.mk b/build/pymake/tests/notparallel.mk new file mode 100644 index 0000000000..4fd8b1a8d4 --- /dev/null +++ b/build/pymake/tests/notparallel.mk @@ -0,0 +1,8 @@ +#T commandline: ['-j3'] + +include $(TESTPATH)/serial-rule-execution.mk + +all:: + $(MAKE) -f $(TESTPATH)/parallel-simple.mk + +.NOTPARALLEL: diff --git a/build/pymake/tests/oneline-command-continuations.mk b/build/pymake/tests/oneline-command-continuations.mk new file mode 100644 index 0000000000..c11f3df524 --- /dev/null +++ b/build/pymake/tests/oneline-command-continuations.mk @@ -0,0 +1,5 @@ +all: test + @echo TEST-PASS + +test: ; test "Hello \ + world" = "Hello world" diff --git a/build/pymake/tests/override-propagate.mk b/build/pymake/tests/override-propagate.mk new file mode 100644 index 0000000000..a1663ff41d --- /dev/null +++ b/build/pymake/tests/override-propagate.mk @@ -0,0 +1,37 @@ +#T commandline: ['-w', 'OVAR=oval'] + +OVAR=mval + +all: vartest run-override + $(MAKE) -f $(TESTPATH)/override-propagate.mk vartest + @echo TEST-PASS + +CLINE := OVAR=oval TESTPATH=$(TESTPATH) NATIVE_TESTPATH=$(NATIVE_TESTPATH) +ifdef __WIN32__ +CLINE += __WIN32__=1 +endif + +SORTED_CLINE := $(subst \,\\,$(sort $(CLINE))) + +vartest: + @echo MAKELEVEL: '$(MAKELEVEL)' + test '$(value MAKEFLAGS)' = 'w -- $$(MAKEOVERRIDES)' + test '$(origin MAKEFLAGS)' = 'file' + test '$(value MAKEOVERRIDES)' = '$${-*-command-variables-*-}' + test "$(sort $(MAKEOVERRIDES))" = "$(SORTED_CLINE)" + test '$(origin MAKEOVERRIDES)' = 'environment' + test '$(origin -*-command-variables-*-)' = 'automatic' + test "$(origin OVAR)" = "command line" + test "$(OVAR)" = "oval" + +run-override: MAKEOVERRIDES= +run-override: + test "$(OVAR)" = "oval" + $(MAKE) -f $(TESTPATH)/override-propagate.mk otest + +otest: + test '$(value MAKEFLAGS)' = 'w' + test '$(value MAKEOVERRIDES)' = '$${-*-command-variables-*-}' + test '$(MAKEOVERRIDES)' = '' + test '$(origin -*-command-variables-*-)' = 'undefined' + test "$(OVAR)" = "mval" diff --git a/build/pymake/tests/parallel-dep-resolution.mk b/build/pymake/tests/parallel-dep-resolution.mk new file mode 100644 index 0000000000..7967eba2de --- /dev/null +++ b/build/pymake/tests/parallel-dep-resolution.mk @@ -0,0 +1,8 @@ +#T commandline: ['-j3'] +#T returncode: 2 + +all: t1 t2 + +t1: + sleep 1 + touch t1 t2 diff --git a/build/pymake/tests/parallel-dep-resolution2.mk b/build/pymake/tests/parallel-dep-resolution2.mk new file mode 100644 index 0000000000..7d61e6b3e5 --- /dev/null +++ b/build/pymake/tests/parallel-dep-resolution2.mk @@ -0,0 +1,9 @@ +#T commandline: ['-j3'] +#T returncode: 2 + +all:: + sleep 1 + touch somefile + +all:: somefile + @echo TEST-PASS diff --git a/build/pymake/tests/parallel-native.mk b/build/pymake/tests/parallel-native.mk new file mode 100644 index 0000000000..d50cfbdbb3 --- /dev/null +++ b/build/pymake/tests/parallel-native.mk @@ -0,0 +1,21 @@ +#T commandline: ['-j2'] + +# ensure that calling python commands doesn't block other targets +ifndef SLEEP +SLEEP := sleep +endif + +PRINTF = printf "$@:0:" >>results +EXPECTED = target2:0:target1:0: + +all:: target1 target2 + cat results + test "$$(cat results)" = "$(EXPECTED)" + @echo TEST-PASS + +target1: + $(SLEEP) 0.1 + $(PRINTF) + +target2: + $(PRINTF) diff --git a/build/pymake/tests/parallel-simple.mk b/build/pymake/tests/parallel-simple.mk new file mode 100644 index 0000000000..f1aafc5f12 --- /dev/null +++ b/build/pymake/tests/parallel-simple.mk @@ -0,0 +1,27 @@ +#T commandline: ['-j2'] + +# CAUTION: this makefile is also used by serial-toparallel.mk + +define SLOWMAKE +printf "$@:0:" >>results +sleep 0.5 +printf "$@:1:" >>results +sleep 0.5 +printf "$@:2:" >>results +endef + +EXPECTED = target1:0:target2:0:target1:1:target2:1:target1:2:target2:2: + +all:: target1 target2 + cat results + test "$$(cat results)" = "$(EXPECTED)" + @echo TEST-PASS + +target1: + $(SLOWMAKE) + +target2: + sleep 0.1 + $(SLOWMAKE) + +.PHONY: all diff --git a/build/pymake/tests/parallel-submake.mk b/build/pymake/tests/parallel-submake.mk new file mode 100644 index 0000000000..65cb2cf7c3 --- /dev/null +++ b/build/pymake/tests/parallel-submake.mk @@ -0,0 +1,17 @@ +#T commandline: ['-j2'] + +# A submake shouldn't return control to the parent until it has actually finished doing everything. + +all: + -$(MAKE) -f $(TESTPATH)/parallel-submake.mk subtarget + cat results + test "$$(cat results)" = "0123" + @echo TEST-PASS + +subtarget: succeed-slowly fail-quickly + +succeed-slowly: + printf 0 >>results; sleep 1; printf 1 >>results; sleep 1; printf 2 >>results; sleep 1; printf 3 >>results + +fail-quickly: + exit 1 diff --git a/build/pymake/tests/parallel-toserial.mk b/build/pymake/tests/parallel-toserial.mk new file mode 100644 index 0000000000..9a355eb336 --- /dev/null +++ b/build/pymake/tests/parallel-toserial.mk @@ -0,0 +1,31 @@ +#T commandline: ['-j4'] + +# Test that -j1 in a submake has the proper effect. + +define SLOWCMD +printf "$@:0:" >>$(RFILE) +sleep 0.5 +printf "$@:1:" >>$(RFILE) +endef + +all: p1 p2 +subtarget: s1 s2 + +p1 p2: RFILE = presult +s1 s2: RFILE = sresult + +p1 s1: + $(SLOWCMD) + +p2 s2: + sleep 0.1 + $(SLOWCMD) + +all: + $(MAKE) -j1 -f $(TESTPATH)/parallel-toserial.mk subtarget + printf "presult: %s\n" "$$(cat presult)" + test "$$(cat presult)" = "p1:0:p2:0:p1:1:p2:1:" + printf "sresult: %s\n" "$$(cat sresult)" + test "$$(cat sresult)" = "s1:0:s1:1:s2:0:s2:1:" + @echo TEST-PASS + diff --git a/build/pymake/tests/parallel-waiting.mk b/build/pymake/tests/parallel-waiting.mk new file mode 100644 index 0000000000..40a6e0d501 --- /dev/null +++ b/build/pymake/tests/parallel-waiting.mk @@ -0,0 +1,21 @@ +#T commandline: ['-j2'] + +EXPECTED = target1:before:target2:1:target2:2:target2:3:target1:after + +all:: target1 target2 + cat results + test "$$(cat results)" = "$(EXPECTED)" + @echo TEST-PASS + +target1: + printf "$@:before:" >>results + sleep 4 + printf "$@:after" >>results + +target2: + sleep 0.2 + printf "$@:1:" >>results + sleep 0.1 + printf "$@:2:" >>results + sleep 0.1 + printf "$@:3:" >>results diff --git a/build/pymake/tests/parentheses.mk b/build/pymake/tests/parentheses.mk new file mode 100644 index 0000000000..f207234ffe --- /dev/null +++ b/build/pymake/tests/parentheses.mk @@ -0,0 +1,2 @@ +all: + @(echo TEST-PASS) diff --git a/build/pymake/tests/parsertests.py b/build/pymake/tests/parsertests.py new file mode 100644 index 0000000000..ab6406be0f --- /dev/null +++ b/build/pymake/tests/parsertests.py @@ -0,0 +1,314 @@ +import pymake.data, pymake.parser, pymake.parserdata, pymake.functions +import unittest +import logging + +from cStringIO import StringIO + +def multitest(cls): + for name in cls.testdata.iterkeys(): + def m(self, name=name): + return self.runSingle(*self.testdata[name]) + + setattr(cls, 'test_%s' % name, m) + return cls + +class TestBase(unittest.TestCase): + def assertEqual(self, a, b, msg=""): + """Actually print the values which weren't equal, if things don't work out!""" + unittest.TestCase.assertEqual(self, a, b, "%s got %r expected %r" % (msg, a, b)) + +class DataTest(TestBase): + testdata = { + 'oneline': + ("He\tllo", "f", 1, 0, + ((0, "f", 1, 0), (2, "f", 1, 2), (3, "f", 1, 4))), + 'twoline': + ("line1 \n\tl\tine2", "f", 1, 4, + ((0, "f", 1, 4), (5, "f", 1, 9), (6, "f", 1, 10), (7, "f", 2, 0), (8, "f", 2, 4), (10, "f", 2, 8), (13, "f", 2, 11))), + } + + def runSingle(self, data, filename, line, col, results): + d = pymake.parser.Data(data, 0, len(data), pymake.parserdata.Location(filename, line, col)) + for pos, file, lineno, col in results: + loc = d.getloc(pos) + self.assertEqual(loc.path, file, "data file offset %i" % pos) + self.assertEqual(loc.line, lineno, "data line offset %i" % pos) + self.assertEqual(loc.column, col, "data col offset %i" % pos) +multitest(DataTest) + +class LineEnumeratorTest(TestBase): + testdata = { + 'simple': ( + 'Hello, world', [ + ('Hello, world', 1), + ] + ), + 'multi': ( + 'Hello\nhappy \n\nworld\n', [ + ('Hello', 1), + ('happy ', 2), + ('', 3), + ('world', 4), + ('', 5), + ] + ), + 'continuation': ( + 'Hello, \\\n world\nJellybeans!', [ + ('Hello, \\\n world', 1), + ('Jellybeans!', 3), + ] + ), + 'multislash': ( + 'Hello, \\\\\n world', [ + ('Hello, \\\\', 1), + (' world', 2), + ] + ) + } + + def runSingle(self, s, lines): + gotlines = [(d.s[d.lstart:d.lend], d.loc.line) for d in pymake.parser.enumeratelines(s, 'path')] + self.assertEqual(gotlines, lines) + +multitest(LineEnumeratorTest) + +class IterTest(TestBase): + testdata = { + 'plaindata': ( + pymake.parser.iterdata, + "plaindata # test\n", + "plaindata # test\n" + ), + 'makecomment': ( + pymake.parser.itermakefilechars, + "VAR = val # comment", + "VAR = val " + ), + 'makeescapedcomment': ( + pymake.parser.itermakefilechars, + "VAR = val \# escaped hash", + "VAR = val # escaped hash" + ), + 'makeescapedslash': ( + pymake.parser.itermakefilechars, + "VAR = val\\\\", + "VAR = val\\\\", + ), + 'makecontinuation': ( + pymake.parser.itermakefilechars, + "VAR = VAL \\\n continuation # comment \\\n continuation", + "VAR = VAL continuation " + ), + 'makecontinuation2': ( + pymake.parser.itermakefilechars, + "VAR = VAL \\ \\\n continuation", + "VAR = VAL \\ continuation" + ), + 'makeawful': ( + pymake.parser.itermakefilechars, + "VAR = VAL \\\\# comment\n", + "VAR = VAL \\" + ), + 'command': ( + pymake.parser.itercommandchars, + "echo boo # comment", + "echo boo # comment", + ), + 'commandcomment': ( + pymake.parser.itercommandchars, + "echo boo \# comment", + "echo boo \# comment", + ), + 'commandcontinue': ( + pymake.parser.itercommandchars, + "echo boo # \\\n\t command 2", + "echo boo # \\\n command 2" + ), + } + + def runSingle(self, ifunc, idata, expected): + d = pymake.parser.Data.fromstring(idata, 'IterTest data') + + it = pymake.parser._alltokens.finditer(d.s, 0, d.lend) + actual = ''.join( [c for c, t, o, oo in ifunc(d, 0, ('dummy-token',), it)] ) + self.assertEqual(actual, expected) + + if ifunc == pymake.parser.itermakefilechars: + print "testing %r" % expected + self.assertEqual(pymake.parser.flattenmakesyntax(d, 0), expected) + +multitest(IterTest) + + +# 'define': ( +# pymake.parser.iterdefinechars, +# "endef", +# "" +# ), +# 'definenesting': ( +# pymake.parser.iterdefinechars, +# """define BAR # comment +#random text +#endef not what you think! +#endef # comment is ok\n""", +# """define BAR # comment +#random text +#endef not what you think!""" +# ), +# 'defineescaped': ( +# pymake.parser.iterdefinechars, +# """value \\ +#endef +#endef\n""", +# "value endef" +# ), + +class MakeSyntaxTest(TestBase): + # (string, startat, stopat, stopoffset, expansion + testdata = { + 'text': ('hello world', 0, (), None, ['hello world']), + 'singlechar': ('hello $W', 0, (), None, + ['hello ', + {'type': 'VariableRef', + '.vname': ['W']} + ]), + 'stopat': ('hello: world', 0, (':', '='), 6, ['hello']), + 'funccall': ('h $(flavor FOO)', 0, (), None, + ['h ', + {'type': 'FlavorFunction', + '[0]': ['FOO']} + ]), + 'escapedollar': ('hello$$world', 0, (), None, ['hello$world']), + 'varref': ('echo $(VAR)', 0, (), None, + ['echo ', + {'type': 'VariableRef', + '.vname': ['VAR']} + ]), + 'dynamicvarname': ('echo $($(VARNAME):.c=.o)', 0, (':',), None, + ['echo ', + {'type': 'SubstitutionRef', + '.vname': [{'type': 'VariableRef', + '.vname': ['VARNAME']} + ], + '.substfrom': ['.c'], + '.substto': ['.o']} + ]), + 'substref': (' $(VAR:VAL) := $(VAL)', 0, (':=', '+=', '=', ':'), 15, + [' ', + {'type': 'VariableRef', + '.vname': ['VAR:VAL']}, + ' ']), + 'vadsubstref': (' $(VAR:VAL) = $(VAL)', 15, (), None, + [{'type': 'VariableRef', + '.vname': ['VAL']}, + ]), + } + + def compareRecursive(self, actual, expected, path): + self.assertEqual(len(actual), len(expected), + "compareRecursive: %s %r" % (path, actual)) + for i in xrange(0, len(actual)): + ipath = path + [i] + + a, isfunc = actual[i] + e = expected[i] + if isinstance(e, str): + self.assertEqual(a, e, "compareRecursive: %s" % (ipath,)) + else: + self.assertEqual(type(a), getattr(pymake.functions, e['type']), + "compareRecursive: %s" % (ipath,)) + for k, v in e.iteritems(): + if k == 'type': + pass + elif k[0] == '[': + item = int(k[1:-1]) + proppath = ipath + [item] + self.compareRecursive(a[item], v, proppath) + elif k[0] == '.': + item = k[1:] + proppath = ipath + [item] + self.compareRecursive(getattr(a, item), v, proppath) + else: + raise Exception("Unexpected property at %s: %s" % (ipath, k)) + + def runSingle(self, s, startat, stopat, stopoffset, expansion): + d = pymake.parser.Data.fromstring(s, pymake.parserdata.Location('testdata', 1, 0)) + + a, t, offset = pymake.parser.parsemakesyntax(d, startat, stopat, pymake.parser.itermakefilechars) + self.compareRecursive(a, expansion, []) + self.assertEqual(offset, stopoffset) + +multitest(MakeSyntaxTest) + +class VariableTest(TestBase): + testdata = """ + VAR = value + VARNAME = TESTVAR + $(VARNAME) = testvalue + $(VARNAME:VAR=VAL) = moretesting + IMM := $(VARNAME) # this is a comment + MULTIVAR = val1 \\ + val2 + VARNAME = newname + """ + expected = {'VAR': 'value', + 'VARNAME': 'newname', + 'TESTVAR': 'testvalue', + 'TESTVAL': 'moretesting', + 'IMM': 'TESTVAR ', + 'MULTIVAR': 'val1 val2', + 'UNDEF': None} + + def runTest(self): + stmts = pymake.parser.parsestring(self.testdata, 'VariableTest') + + m = pymake.data.Makefile() + stmts.execute(m) + for k, v in self.expected.iteritems(): + flavor, source, val = m.variables.get(k) + if val is None: + self.assertEqual(val, v, 'variable named %s' % k) + else: + self.assertEqual(val.resolvestr(m, m.variables), v, 'variable named %s' % k) + +class SimpleRuleTest(TestBase): + testdata = """ + VAR = value +TSPEC = dummy +all: TSPEC = myrule +all:: test test2 $(VAR) + echo "Hello, $(TSPEC)" + +%.o: %.c + $(CC) -o $@ $< +""" + + def runTest(self): + stmts = pymake.parser.parsestring(self.testdata, 'SimpleRuleTest') + + m = pymake.data.Makefile() + stmts.execute(m) + self.assertEqual(m.defaulttarget, 'all', "Default target") + + self.assertTrue(m.hastarget('all'), "Has 'all' target") + target = m.gettarget('all') + rules = target.rules + self.assertEqual(len(rules), 1, "Number of rules") + prereqs = rules[0].prerequisites + self.assertEqual(prereqs, ['test', 'test2', 'value'], "Prerequisites") + commands = rules[0].commands + self.assertEqual(len(commands), 1, "Number of commands") + expanded = commands[0].resolvestr(m, target.variables) + self.assertEqual(expanded, 'echo "Hello, myrule"') + + irules = m.implicitrules + self.assertEqual(len(irules), 1, "Number of implicit rules") + + irule = irules[0] + self.assertEqual(len(irule.targetpatterns), 1, "%.o target pattern count") + self.assertEqual(len(irule.prerequisites), 1, "%.o prerequisite count") + self.assertEqual(irule.targetpatterns[0].match('foo.o'), 'foo', "%.o stem") + +if __name__ == '__main__': + logging.basicConfig(level=logging.DEBUG) + unittest.main() diff --git a/build/pymake/tests/path-length.mk b/build/pymake/tests/path-length.mk new file mode 100644 index 0000000000..10c33b5edc --- /dev/null +++ b/build/pymake/tests/path-length.mk @@ -0,0 +1,9 @@ +#T gmake skip + +$(shell \ +mkdir foo; \ +touch tfile; \ +) + +all: foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../foo/../tfile + @echo TEST-PASS diff --git a/build/pymake/tests/pathdir/pathtest b/build/pymake/tests/pathdir/pathtest new file mode 100755 index 0000000000..17037159fd --- /dev/null +++ b/build/pymake/tests/pathdir/pathtest @@ -0,0 +1,2 @@ +#!/bin/sh +echo Called shell script: 2f7cdd0b-7277-48c1-beaf-56cb0dbacb24 diff --git a/build/pymake/tests/pathdir/pathtest.exe b/build/pymake/tests/pathdir/pathtest.exe Binary files differnew file mode 100644 index 0000000000..3178db9a94 --- /dev/null +++ b/build/pymake/tests/pathdir/pathtest.exe diff --git a/build/pymake/tests/pathdir/src/Makefile b/build/pymake/tests/pathdir/src/Makefile new file mode 100644 index 0000000000..6c24bd8f94 --- /dev/null +++ b/build/pymake/tests/pathdir/src/Makefile @@ -0,0 +1,2 @@ +pathtest.exe: pathtest.cpp + cl -EHsc -MT $^ diff --git a/build/pymake/tests/pathdir/src/pathtest.cpp b/build/pymake/tests/pathdir/src/pathtest.cpp new file mode 100644 index 0000000000..bef8d8a118 --- /dev/null +++ b/build/pymake/tests/pathdir/src/pathtest.cpp @@ -0,0 +1,6 @@ +#include <cstdio> + +int main() { + std::printf("Called Windows executable: 2f7cdd0b-7277-48c1-beaf-56cb0dbacb24\n"); + return 0; +} diff --git a/build/pymake/tests/patsubst.mk b/build/pymake/tests/patsubst.mk new file mode 100644 index 0000000000..0c3efdc4b8 --- /dev/null +++ b/build/pymake/tests/patsubst.mk @@ -0,0 +1,7 @@ +all: + test "$(patsubst foo,%.bar,foo)" = "%.bar" + test "$(patsubst \%word,replace,word %word other)" = "word replace other" + test "$(patsubst %.c,\%%.o,foo.c bar.o baz.cpp)" = "%foo.o bar.o baz.cpp" + test "$(patsubst host_%.c,host_%.o,dir/host_foo.c host_bar.c)" = "dir/host_foo.c host_bar.o" + test "$(patsubst foo,bar,dir/foo foo baz)" = "dir/foo bar baz" + @echo TEST-PASS diff --git a/build/pymake/tests/phony.mk b/build/pymake/tests/phony.mk new file mode 100644 index 0000000000..36db4d121b --- /dev/null +++ b/build/pymake/tests/phony.mk @@ -0,0 +1,10 @@ +$(shell \ +touch dep; \ +sleep 2; \ +touch all; \ +) + +all:: dep + @echo TEST-PASS + +.PHONY: all diff --git a/build/pymake/tests/pycmd.py b/build/pymake/tests/pycmd.py new file mode 100644 index 0000000000..83b9b966b4 --- /dev/null +++ b/build/pymake/tests/pycmd.py @@ -0,0 +1,38 @@ +import os, sys, subprocess + +def writetofile(args): + with open(args[0], 'w') as f: + f.write(' '.join(args[1:])) + +def writeenvtofile(args): + with open(args[0], 'w') as f: + f.write(os.environ[args[1]]) + +def writesubprocessenvtofile(args): + with open(args[0], 'w') as f: + p = subprocess.Popen([sys.executable, "-c", + "import os; print os.environ['%s']" % args[1]], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + stdout, stderr = p.communicate() + assert p.returncode == 0 + f.write(stdout) + +def convertasplode(arg): + try: + return int(arg) + except: + return (None if arg == "None" else arg) + +def asplode(args): + arg0 = convertasplode(args[0]) + sys.exit(arg0) + +def asplode_return(args): + arg0 = convertasplode(args[0]) + return arg0 + +def asplode_raise(args): + raise Exception(args[0]) + +def delayloadfn(args): + import delayload diff --git a/build/pymake/tests/recursive-set.mk b/build/pymake/tests/recursive-set.mk new file mode 100644 index 0000000000..853f90463e --- /dev/null +++ b/build/pymake/tests/recursive-set.mk @@ -0,0 +1,7 @@ +#T returncode: 2 + +FOO = $(FOO) + +all: + echo $(FOO) + @echo TEST-FAIL diff --git a/build/pymake/tests/recursive-set2.mk b/build/pymake/tests/recursive-set2.mk new file mode 100644 index 0000000000..b68e34f0d7 --- /dev/null +++ b/build/pymake/tests/recursive-set2.mk @@ -0,0 +1,8 @@ +#T returncode: 2 + +FOO = $(BAR) +BAR = $(FOO) + +all: + echo $(FOO) + @echo TEST-FAIL diff --git a/build/pymake/tests/remake-mtime.mk b/build/pymake/tests/remake-mtime.mk new file mode 100644 index 0000000000..47c775b93e --- /dev/null +++ b/build/pymake/tests/remake-mtime.mk @@ -0,0 +1,14 @@ +# mtime(dep1) < mtime(target) so the target should not be made +$(shell touch dep1; sleep 1; touch target) + +all: target + echo TEST-PASS + +target: dep1 + echo TEST-FAIL target should not have been made + +dep1: dep2 + @echo "Remaking dep1 (actually not)" + +dep2: + @echo "Making dep2 (actually not)" diff --git a/build/pymake/tests/rm-fail.mk b/build/pymake/tests/rm-fail.mk new file mode 100644 index 0000000000..1a9aefb57e --- /dev/null +++ b/build/pymake/tests/rm-fail.mk @@ -0,0 +1,7 @@ +#T returncode: 2 +all: + mkdir newdir + test -d newdir + touch newdir/newfile + $(RM) newdir + @echo TEST-PASS diff --git a/build/pymake/tests/rm.mk b/build/pymake/tests/rm.mk new file mode 100644 index 0000000000..6c7140e39d --- /dev/null +++ b/build/pymake/tests/rm.mk @@ -0,0 +1,21 @@ +all: +# $(RM) defaults to -f + $(RM) nosuchfile + touch newfile + test -f newfile + $(RM) newfile + test ! -f newfile + mkdir newdir + test -d newdir + touch newdir/newfile + mkdir newdir/subdir + $(RM) -r newdir/subdir + test ! -d newdir/subdir + test -d newdir + mkdir newdir/subdir1 newdir/subdir2 + $(RM) -r newdir/subdir1 newdir/subdir2 + test ! -d newdir/subdir1 -a ! -d newdir/subdir2 + test -d newdir + $(RM) -r newdir + test ! -d newdir + @echo TEST-PASS diff --git a/build/pymake/tests/runtests.py b/build/pymake/tests/runtests.py new file mode 100644 index 0000000000..ab149ecfb1 --- /dev/null +++ b/build/pymake/tests/runtests.py @@ -0,0 +1,215 @@ +#!/usr/bin/env python +""" +Run the test(s) listed on the command line. If a directory is listed, the script will recursively +walk the directory for files named .mk and run each. + +For each test, we run gmake -f test.mk. By default, make must exit with an exit code of 0, and must print 'TEST-PASS'. + +Each test is run in an empty directory. + +The test file may contain lines at the beginning to alter the default behavior. These are all evaluated as python: + +#T commandline: ['extra', 'params', 'here'] +#T returncode: 2 +#T returncode-on: {'win32': 2} +#T environment: {'VAR': 'VALUE} +#T grep-for: "text" +""" + +from subprocess import Popen, PIPE, STDOUT +from optparse import OptionParser +import os, re, sys, shutil, glob + +class ParentDict(dict): + def __init__(self, parent, **kwargs): + self.d = dict(kwargs) + self.parent = parent + + def __setitem__(self, k, v): + self.d[k] = v + + def __getitem__(self, k): + if k in self.d: + return self.d[k] + + return self.parent[k] + +thisdir = os.path.dirname(os.path.abspath(__file__)) + +pymake = [sys.executable, os.path.join(os.path.dirname(thisdir), 'make.py')] +manifest = os.path.join(thisdir, 'tests.manifest') + +o = OptionParser() +o.add_option('-g', '--gmake', + dest="gmake", default="gmake") +o.add_option('-d', '--tempdir', + dest="tempdir", default="_mktests") +opts, args = o.parse_args() + +if len(args) == 0: + args = [thisdir] + +makefiles = [] +for a in args: + if os.path.isfile(a): + makefiles.append(a) + elif os.path.isdir(a): + makefiles.extend(sorted(glob.glob(os.path.join(a, '*.mk')))) + +def runTest(makefile, make, logfile, options): + """ + Given a makefile path, test it with a given `make` and return + (pass, message). + """ + + if os.path.exists(opts.tempdir): shutil.rmtree(opts.tempdir) + os.mkdir(opts.tempdir, 0755) + + logfd = open(logfile, 'w') + p = Popen(make + options['commandline'], stdout=logfd, stderr=STDOUT, env=options['env']) + logfd.close() + retcode = p.wait() + + if retcode != options['returncode']: + return False, "FAIL (returncode=%i)" % retcode + + logfd = open(logfile) + stdout = logfd.read() + logfd.close() + + if stdout.find('TEST-FAIL') != -1: + print stdout + return False, "FAIL (TEST-FAIL printed)" + + if options['grepfor'] and stdout.find(options['grepfor']) == -1: + print stdout + return False, "FAIL (%s not in output)" % options['grepfor'] + + if options['returncode'] == 0 and stdout.find('TEST-PASS') == -1: + print stdout + return False, 'FAIL (No TEST-PASS printed)' + + if options['returncode'] != 0: + return True, 'PASS (retcode=%s)' % retcode + + return True, 'PASS' + +print "%-30s%-28s%-28s" % ("Test:", "gmake:", "pymake:") + +gmakefails = 0 +pymakefails = 0 + +tre = re.compile('^#T (gmake |pymake )?([a-z-]+)(?:: (.*))?$') + +for makefile in makefiles: + # For some reason, MAKEFILE_LIST uses native paths in GNU make on Windows + # (even in MSYS!) so we pass both TESTPATH and NATIVE_TESTPATH + cline = ['-C', opts.tempdir, '-f', os.path.abspath(makefile), 'TESTPATH=%s' % thisdir.replace('\\','/'), 'NATIVE_TESTPATH=%s' % thisdir] + if sys.platform == 'win32': + #XXX: hack so we can specialize the separator character on windows. + # we really shouldn't need this, but y'know + cline += ['__WIN32__=1'] + + options = { + 'returncode': 0, + 'grepfor': None, + 'env': dict(os.environ), + 'commandline': cline, + 'pass': True, + 'skip': False, + } + + gmakeoptions = ParentDict(options) + pymakeoptions = ParentDict(options) + + dmap = {None: options, 'gmake ': gmakeoptions, 'pymake ': pymakeoptions} + + mdata = open(makefile) + for line in mdata: + line = line.strip() + m = tre.search(line) + if m is None: + break + + make, key, data = m.group(1, 2, 3) + d = dmap[make] + if data is not None: + data = eval(data) + if key == 'commandline': + assert make is None + d['commandline'].extend(data) + elif key == 'returncode': + d['returncode'] = data + elif key == 'returncode-on': + if sys.platform in data: + d['returncode'] = data[sys.platform] + elif key == 'environment': + for k, v in data.iteritems(): + d['env'][k] = v + elif key == 'grep-for': + d['grepfor'] = data + elif key == 'fail': + d['pass'] = False + elif key == 'skip': + d['skip'] = True + else: + print >>sys.stderr, "%s: Unexpected #T key: %s" % (makefile, key) + sys.exit(1) + + mdata.close() + + if gmakeoptions['skip']: + gmakepass, gmakemsg = True, '' + else: + gmakepass, gmakemsg = runTest(makefile, [opts.gmake], + makefile + '.gmakelog', gmakeoptions) + + if gmakeoptions['pass']: + if not gmakepass: + gmakefails += 1 + else: + if gmakepass: + gmakefails += 1 + gmakemsg = "UNEXPECTED PASS" + else: + gmakemsg = "KNOWN FAIL" + + if pymakeoptions['skip']: + pymakepass, pymakemsg = True, '' + else: + pymakepass, pymakemsg = runTest(makefile, pymake, + makefile + '.pymakelog', pymakeoptions) + + if pymakeoptions['pass']: + if not pymakepass: + pymakefails += 1 + else: + if pymakepass: + pymakefails += 1 + pymakemsg = "UNEXPECTED PASS" + else: + pymakemsg = "OK (known fail)" + + print "%-30.30s%-28.28s%-28.28s" % (os.path.basename(makefile), + gmakemsg, pymakemsg) + +print +print "Summary:" +print "%-30s%-28s%-28s" % ("", "gmake:", "pymake:") + +if gmakefails == 0: + gmakemsg = 'PASS' +else: + gmakemsg = 'FAIL (%i failures)' % gmakefails + +if pymakefails == 0: + pymakemsg = 'PASS' +else: + pymakemsg = 'FAIL (%i failures)' % pymakefails + +print "%-30.30s%-28.28s%-28.28s" % ('', gmakemsg, pymakemsg) + +shutil.rmtree(opts.tempdir) + +if gmakefails or pymakefails: + sys.exit(1) diff --git a/build/pymake/tests/serial-dep-resolution.mk b/build/pymake/tests/serial-dep-resolution.mk new file mode 100644 index 0000000000..e65f1ed038 --- /dev/null +++ b/build/pymake/tests/serial-dep-resolution.mk @@ -0,0 +1,5 @@ +all: t1 t2 + @echo TEST-PASS + +t1: + touch t1 t2 diff --git a/build/pymake/tests/serial-doublecolon-execution.mk b/build/pymake/tests/serial-doublecolon-execution.mk new file mode 100644 index 0000000000..1871cb13a9 --- /dev/null +++ b/build/pymake/tests/serial-doublecolon-execution.mk @@ -0,0 +1,18 @@ +#T commandline: ['-j3'] + +# Commands of double-colon rules are always executed in order. + +all: dc + cat status + test "$$(cat status)" = "all1:all2:" + @echo TEST-PASS + +dc:: slowt + printf "all1:" >> status + +dc:: + sleep 0.2 + printf "all2:" >> status + +slowt: + sleep 1 diff --git a/build/pymake/tests/serial-rule-execution.mk b/build/pymake/tests/serial-rule-execution.mk new file mode 100644 index 0000000000..da5b177de1 --- /dev/null +++ b/build/pymake/tests/serial-rule-execution.mk @@ -0,0 +1,5 @@ +all:: + touch somefile + +all:: somefile + @echo TEST-PASS diff --git a/build/pymake/tests/serial-rule-execution2.mk b/build/pymake/tests/serial-rule-execution2.mk new file mode 100644 index 0000000000..252a7df831 --- /dev/null +++ b/build/pymake/tests/serial-rule-execution2.mk @@ -0,0 +1,13 @@ +#T returncode: 2 + +# The dependencies of the command rule of a single-colon target are resolved before the rules without commands. + +all: export + +export: + sleep 1 + touch somefile + +all: somefile + test -f somefile + @echo TEST-PASS diff --git a/build/pymake/tests/serial-toparallel.mk b/build/pymake/tests/serial-toparallel.mk new file mode 100644 index 0000000000..a980badc71 --- /dev/null +++ b/build/pymake/tests/serial-toparallel.mk @@ -0,0 +1,5 @@ +all:: + $(MAKE) -j2 -f $(TESTPATH)/parallel-simple.mk + +all:: results + @echo TEST-PASS diff --git a/build/pymake/tests/shellfunc.mk b/build/pymake/tests/shellfunc.mk new file mode 100644 index 0000000000..1e408dbaca --- /dev/null +++ b/build/pymake/tests/shellfunc.mk @@ -0,0 +1,7 @@ +all: testfile + test "$(shell cat $<)" = "Hello world" + test "$(shell printf "\n")" = "" + @echo TEST-PASS + +testfile: + printf "Hello\nworld\n" > $@ diff --git a/build/pymake/tests/simple-makeflags.mk b/build/pymake/tests/simple-makeflags.mk new file mode 100644 index 0000000000..c7c92ec9d6 --- /dev/null +++ b/build/pymake/tests/simple-makeflags.mk @@ -0,0 +1,10 @@ +# There once was a time when MAKEFLAGS=w without any following spaces would +# cause us to treat w as a target, not a flag. Silly! + +MAKEFLAGS=w + +all: + $(MAKE) -f $(TESTPATH)/simple-makeflags.mk subt + @echo TEST-PASS + +subt: diff --git a/build/pymake/tests/sort.mk b/build/pymake/tests/sort.mk new file mode 100644 index 0000000000..e1313ad5ca --- /dev/null +++ b/build/pymake/tests/sort.mk @@ -0,0 +1,4 @@ +# sort should remove duplicates +all: + @test "$(sort x a y b z c a z b x c y)" = "a b c x y z" + @echo "TEST-PASS" diff --git a/build/pymake/tests/specified-target.mk b/build/pymake/tests/specified-target.mk new file mode 100644 index 0000000000..3b23fbf69e --- /dev/null +++ b/build/pymake/tests/specified-target.mk @@ -0,0 +1,7 @@ +#T commandline: ['VAR=all', '$(VAR)'] + +all: + @echo TEST-FAIL: unexpected target 'all' + +$$(VAR): + @echo TEST-PASS: expected target '$$(VAR)' diff --git a/build/pymake/tests/static-pattern.mk b/build/pymake/tests/static-pattern.mk new file mode 100644 index 0000000000..f613b8c9a3 --- /dev/null +++ b/build/pymake/tests/static-pattern.mk @@ -0,0 +1,5 @@ +#T returncode: 2 + +out/host_foo.o: host_%.o: host_%.c out + cp $< $@ + @echo TEST-FAIL diff --git a/build/pymake/tests/static-pattern2.mk b/build/pymake/tests/static-pattern2.mk new file mode 100644 index 0000000000..08ed834fd0 --- /dev/null +++ b/build/pymake/tests/static-pattern2.mk @@ -0,0 +1,10 @@ +all: foo.out + test -f $^ + @echo TEST-PASS + +foo.out: %.out: %.in + test "$*" = "foo" + cp $^ $@ + +foo.in: + touch $@ diff --git a/build/pymake/tests/subdir/delayload.py b/build/pymake/tests/subdir/delayload.py new file mode 100644 index 0000000000..bdd6669dbd --- /dev/null +++ b/build/pymake/tests/subdir/delayload.py @@ -0,0 +1 @@ +# This module exists to test delay importing of modules at run-time. diff --git a/build/pymake/tests/subdir/pymod.py b/build/pymake/tests/subdir/pymod.py new file mode 100644 index 0000000000..1a47d8af26 --- /dev/null +++ b/build/pymake/tests/subdir/pymod.py @@ -0,0 +1,5 @@ +import testmodule + +def writetofile(args): + with open(args[0], 'w') as f: + f.write(' '.join(args[1:])) diff --git a/build/pymake/tests/subdir/testmodule.py b/build/pymake/tests/subdir/testmodule.py new file mode 100644 index 0000000000..05b2f821a5 --- /dev/null +++ b/build/pymake/tests/subdir/testmodule.py @@ -0,0 +1,3 @@ +# This is an empty module. It is imported by pymod.py to test that if a module +# is loaded from the PYCOMMANDPATH, it can import other modules from the same +# directory correctly. diff --git a/build/pymake/tests/submake-path.makefile2 b/build/pymake/tests/submake-path.makefile2 new file mode 100644 index 0000000000..1266db7d1b --- /dev/null +++ b/build/pymake/tests/submake-path.makefile2 @@ -0,0 +1,11 @@ +# -*- Mode: Makefile -*- + +shellresult := $(shell pathtest) +ifneq (2f7cdd0b-7277-48c1-beaf-56cb0dbacb24,$(filter $(shellresult),2f7cdd0b-7277-48c1-beaf-56cb0dbacb24)) +$(error pathtest not found in submake shell function) +endif + +all: + @pathtest + @pathtest | grep -q 2f7cdd0b-7277-48c1-beaf-56cb0dbacb24 + @echo TEST-PASS diff --git a/build/pymake/tests/submake-path.mk b/build/pymake/tests/submake-path.mk new file mode 100644 index 0000000000..b6432276dd --- /dev/null +++ b/build/pymake/tests/submake-path.mk @@ -0,0 +1,16 @@ +#T gmake skip +#T grep-for: "2f7cdd0b-7277-48c1-beaf-56cb0dbacb24" + +ifdef __WIN32__ +PS:=; +else +PS:=: +endif + +export PATH := $(TESTPATH)/pathdir$(PS)$(PATH) + +# This is similar to subprocess-path.mk, except we also check $(shell) +# invocations since they're affected by exported environment variables too, +# but only in submakes! +all: + $(MAKE) -f $(TESTPATH)/submake-path.makefile2 diff --git a/build/pymake/tests/submake.makefile2 b/build/pymake/tests/submake.makefile2 new file mode 100644 index 0000000000..12ce94834f --- /dev/null +++ b/build/pymake/tests/submake.makefile2 @@ -0,0 +1,24 @@ +# -*- Mode: Makefile -*- + +$(info MAKEFLAGS = '$(MAKEFLAGS)') +$(info MAKE = '$(MAKE)') +$(info value MAKE = "$(value MAKE)") + +shellresult := $(shell echo -n $$EVAR) +ifneq ($(shellresult),eval) +$(error EVAR should be eval, is instead $(shellresult)) +endif + +all: + env + test "$(MAKELEVEL)" = "1" + echo "value(MAKE)" '$(value MAKE)' + echo "value(MAKE_COMMAND)" = '$(value MAKE_COMMAND)' + test "$(origin CVAR)" = "command line" + test "$(CVAR)" = "c val=spac\ed" + test "$(origin EVAR)" = "environment" + test "$(EVAR)" = "eval" + test "$(OVAL)" = "cline" + test "$(OVAL2)" = "cline2" + test "$(ALLVAR)" = "allspecific" + @echo TEST-PASS diff --git a/build/pymake/tests/submake.mk b/build/pymake/tests/submake.mk new file mode 100644 index 0000000000..41e47134b4 --- /dev/null +++ b/build/pymake/tests/submake.mk @@ -0,0 +1,16 @@ +#T commandline: ['CVAR=c val=spac\\ed', 'OVAL=cline', 'OVAL2=cline2'] + +export EVAR = eval +override OVAL = makefile + +# exporting an override variable doesn't mean it's an override variable +override OVAL2 = makefile2 +export OVAL2 + +export ALLVAR +ALLVAR = general +all: ALLVAR = allspecific + +all: + test "$(MAKELEVEL)" = "0" + $(MAKE) -f $(TESTPATH)/submake.makefile2 diff --git a/build/pymake/tests/subprocess-path.mk b/build/pymake/tests/subprocess-path.mk new file mode 100644 index 0000000000..f639214141 --- /dev/null +++ b/build/pymake/tests/subprocess-path.mk @@ -0,0 +1,32 @@ +#T gmake skip +#T grep-for: "2f7cdd0b-7277-48c1-beaf-56cb0dbacb24" + +ifdef __WIN32__ +PS:=; +else +PS:=: +endif + +export PATH := $(TESTPATH)/pathdir$(PS)$(PATH) + +# Test two commands. The first one shouldn't go through the shell and the +# second one should. The pathdir subdirectory has a Windows executable called +# pathtest.exe and a shell script called pathtest. We don't care which one is +# run, just that one of the two is (we use a uuid + grep-for to make sure +# that happens). +# +# FAQ: +# Q. Why skip GNU Make? +# A. Because $(TESTPATH) is a Windows-style path, and MSYS make doesn't take +# too kindly to Windows paths in the PATH environment variable. +# +# Q. Why use an exe and not a batch file? +# A. The use cases here were all exe files without the extension. Batch file +# lookup has broken semantics if the .bat extension isn't passed. +# +# Q. Why are the commands silent? +# A. So that we don't pass the grep-for test by mistake. +all: + @pathtest + @pathtest | grep -q 2f7cdd0b-7277-48c1-beaf-56cb0dbacb24 + @echo TEST-PASS diff --git a/build/pymake/tests/tab-intro.mk b/build/pymake/tests/tab-intro.mk new file mode 100644 index 0000000000..1c25ce7478 --- /dev/null +++ b/build/pymake/tests/tab-intro.mk @@ -0,0 +1,16 @@ +# Initial tab characters should be treated well. + + THIS = a value + + ifdef THIS + VAR = conditional value + endif + +all: + test "$(THIS)" = "another value" + test "$(VAR)" = "conditional value" + @echo TEST-PASS + +THAT = makefile syntax + + THIS = another value diff --git a/build/pymake/tests/target-specific.mk b/build/pymake/tests/target-specific.mk new file mode 100644 index 0000000000..217ed155e1 --- /dev/null +++ b/build/pymake/tests/target-specific.mk @@ -0,0 +1,30 @@ +TESTVAR = anonval + +all: target.suffix target.suffix2 dummy host_test.py my.test1 my.test2 + @echo TEST-PASS + +target.suffix: TESTVAR = testval + +%.suffix: + test "$(TESTVAR)" = "testval" + +%.suffix2: TESTVAR = testval2 + +%.suffix2: + test "$(TESTVAR)" = "testval2" + +%my: TESTVAR = dummyval + +dummy: + test "$(TESTVAR)" = "dummyval" + +%.py: TESTVAR = pyval +host_%.py: TESTVAR = hostval + +host_test.py: + test "$(TESTVAR)" = "hostval" + +%.test1 %.test2: TESTVAR = %val + +my.test1 my.test2: + test "$(TESTVAR)" = "%val" diff --git a/build/pymake/tests/unexport.mk b/build/pymake/tests/unexport.mk new file mode 100644 index 0000000000..4244116034 --- /dev/null +++ b/build/pymake/tests/unexport.mk @@ -0,0 +1,15 @@ +#T environment: {'ENVVAR': 'envval'} + +VAR1 = val1 +VAR2 = val2 +VAR3 = val3 + +unexport VAR3 +export VAR1 VAR2 VAR3 +unexport VAR2 ENVVAR +unexport + +all: + test "$(ENVVAR)" = "envval" # unexport.mk + $(MAKE) -f $(TESTPATH)/unexport.submk + @echo TEST-PASS diff --git a/build/pymake/tests/unexport.submk b/build/pymake/tests/unexport.submk new file mode 100644 index 0000000000..8db6163de5 --- /dev/null +++ b/build/pymake/tests/unexport.submk @@ -0,0 +1,15 @@ +# -@- Mode: Makefile -@- + +unexport VAR1 + +all: + env + test "$(VAR1)" = "val1" + test "$(origin VAR1)" = "environment" + test "$(VAR2)" = "" # VAR2 + test "$(VAR3)" = "val3" + test "$(ENVVAR)" = "" + $(MAKE) -f $(TESTPATH)/unexport.submk subt + +subt: + test "$(VAR1)" = "" diff --git a/build/pymake/tests/unterminated-dollar.mk b/build/pymake/tests/unterminated-dollar.mk new file mode 100644 index 0000000000..dee9a207ba --- /dev/null +++ b/build/pymake/tests/unterminated-dollar.mk @@ -0,0 +1,6 @@ +VAR = value$ +VAR2 = other + +all: + test "$(VAR)" = "value" + @echo TEST-PASS diff --git a/build/pymake/tests/var-change-flavor.mk b/build/pymake/tests/var-change-flavor.mk new file mode 100644 index 0000000000..0cccf0bd66 --- /dev/null +++ b/build/pymake/tests/var-change-flavor.mk @@ -0,0 +1,12 @@ +VAR = value1 +VAR := value2 + +VAR2 := val1 +VAR2 = val2 + +default: + test "$(flavor VAR)" = "simple" + test "$(VAR)" = "value2" + test "$(flavor VAR2)" = "recursive" + test "$(VAR2)" = "val2" + @echo "TEST-PASS" diff --git a/build/pymake/tests/var-commandline.mk b/build/pymake/tests/var-commandline.mk new file mode 100644 index 0000000000..e2cdad4572 --- /dev/null +++ b/build/pymake/tests/var-commandline.mk @@ -0,0 +1,8 @@ +#T commandline: ['TESTVAR=$(MAKEVAL)', 'TESTVAR2:=$(MAKEVAL)'] + +MAKEVAL=testvalue + +all: + test "$(TESTVAR)" = "testvalue" + test "$(TESTVAR2)" = "" + @echo "TEST-PASS"
\ No newline at end of file diff --git a/build/pymake/tests/var-overrides.mk b/build/pymake/tests/var-overrides.mk new file mode 100644 index 0000000000..bd0765d19f --- /dev/null +++ b/build/pymake/tests/var-overrides.mk @@ -0,0 +1,21 @@ +#T commandline: ['CLINEVAR=clineval', 'CLINEVAR2=clineval2'] + +# this doesn't actually test overrides yet, because they aren't implemented in pymake, +# but testing origins in general is important + +MVAR = mval +CLINEVAR = deadbeef + +override CLINEVAR2 = mval2 + +all: + test "$(origin NOVAR)" = "undefined" + test "$(CLINEVAR)" = "clineval" + test "$(origin CLINEVAR)" = "command line" + test "$(MVAR)" = "mval" + test "$(origin MVAR)" = "file" + test "$(@)" = "all" + test "$(origin @)" = "automatic" + test "$(origin CLINEVAR2)" = "override" + test "$(CLINEVAR2)" = "mval2" + @echo TEST-PASS diff --git a/build/pymake/tests/var-ref.mk b/build/pymake/tests/var-ref.mk new file mode 100644 index 0000000000..3bc1886f9d --- /dev/null +++ b/build/pymake/tests/var-ref.mk @@ -0,0 +1,19 @@ +VAR = value +VAR2 == value + +VAR5 = $(NULL) $(NULL) +VARC = value # comment + +$(VAR3) + $(VAR4) +$(VAR5) + +VAR6$(VAR5) = val6 + +all: + test "$( VAR)" = "" + test "$(VAR2)" = "= value" + test "${VAR2}" = "= value" + test "$(VAR6 )" = "val6" + test "$(VARC)" = "value " + @echo TEST-PASS diff --git a/build/pymake/tests/var-set.mk b/build/pymake/tests/var-set.mk new file mode 100644 index 0000000000..1603e7a35e --- /dev/null +++ b/build/pymake/tests/var-set.mk @@ -0,0 +1,55 @@ +#T commandline: ['OBASIC=oval'] + +BASIC = val + +TEST = $(TEST) + +TEST2 = $(TES +TEST2 += T) + +TES T = val + +RECVAR = foo +RECVAR += var baz + +IMMVAR := bloo +IMMVAR += $(RECVAR) + +BASIC ?= notval + +all: BASIC = valall +all: RECVAR += $(BASIC) +all: IMMVAR += $(BASIC) +all: UNSET += more +all: OBASIC += allmore + +CHECKLIT = $(NULL) check +all: CHECKLIT += appendliteral + +RECVAR = blimey + +TESTEMPTY = \ + $(NULL) + +all: other + test "$(TEST2)" = "val" + test '$(value TEST2)' = '$$(TES T)' + test "$(RECVAR)" = "blimey valall" + test "$(IMMVAR)" = "bloo foo var baz valall" + test "$(UNSET)" = "more" + test "$(OBASIC)" = "oval" + test "$(CHECKLIT)" = " check appendliteral" + test "$(TESTEMPTY)" = "" + @echo TEST-PASS + +OVAR = oval +OVAR ?= onotval + +other: OVAR ?= ooval +other: LATERVAR ?= lateroverride + +LATERVAR = olater + +other: + test "$(OVAR)" = "oval" + test "$(LATERVAR)" = "lateroverride" diff --git a/build/pymake/tests/var-substitutions.mk b/build/pymake/tests/var-substitutions.mk new file mode 100644 index 0000000000..d5627d7bd2 --- /dev/null +++ b/build/pymake/tests/var-substitutions.mk @@ -0,0 +1,49 @@ +SIMPLEVAR = aabb.cc +SIMPLEPERCENT = test_value%extra + +SIMPLE3SUBSTNAME = SIMPLEVAR:.dd +$(SIMPLE3SUBSTNAME) = weirdval + +PERCENT = dummy + +SIMPLESUBST = $(SIMPLEVAR:.cc=.dd) +SIMPLE2SUBST = $(SIMPLEVAR:.cc) +SIMPLE3SUBST = $(SIMPLEVAR:.dd) +SIMPLE4SUBST = $(SIMPLEVAR:.cc=.dd=.ee) +SIMPLE5SUBST = $(SIMPLEVAR:.cc=%.dd) +PERCENTSUBST = $(SIMPLEVAR:%.cc=%.ee) +PERCENT2SUBST = $(SIMPLEVAR:aa%.cc=ff%.f) +PERCENT3SUBST = $(SIMPLEVAR:aa%.dd=gg%.gg) +PERCENT4SUBST = $(SIMPLEVAR:aa%.cc=gg) +PERCENT5SUBST = $(SIMPLEVAR:aa) +PERCENT6SUBST = $(SIMPLEVAR:%.cc=%.dd=%.ee) +PERCENT7SUBST = $(SIMPLEVAR:$(PERCENT).cc=%.dd) +PERCENT8SUBST = $(SIMPLEVAR:%.cc=$(PERCENT).dd) +PERCENT9SUBST = $(SIMPLEVAR:$(PERCENT).cc=$(PERCENT).dd) +PERCENT10SUBST = $(SIMPLEVAR:%%.bb.cc=zz.bb.cc) +PERCENT11SUBST = $(SIMPLEPERCENT:test%value%extra=other%value%extra) + +SPACEDVAR = $(NULL) ex1.c ex2.c $(NULL) +SPACEDSUBST = $(SPACEDVAR:.c=.o) + +all: + test "$(SIMPLESUBST)" = "aabb.dd" + test "$(SIMPLE2SUBST)" = "" + test "$(SIMPLE3SUBST)" = "weirdval" + test "$(SIMPLE4SUBST)" = "aabb.dd=.ee" + test "$(SIMPLE5SUBST)" = "aabb%.dd" + test "$(PERCENTSUBST)" = "aabb.ee" + test "$(PERCENT2SUBST)" = "ffbb.f" + test "$(PERCENT3SUBST)" = "aabb.cc" + test "$(PERCENT4SUBST)" = "gg" + test "$(PERCENT5SUBST)" = "" + test "$(PERCENT6SUBST)" = "aabb.dd=%.ee" + test "$(PERCENT7SUBST)" = "aabb.dd" + test "$(PERCENT8SUBST)" = "aabb.dd" + test "$(PERCENT9SUBST)" = "aabb.dd" + test "$(PERCENT10SUBST)" = "aabb.cc" + test "$(PERCENT11SUBST)" = "other_value%extra" + test "$(SPACEDSUBST)" = "ex1.o ex2.o" + @echo TEST-PASS + +PERCENT = % diff --git a/build/pymake/tests/vpath-directive-dynamic.mk b/build/pymake/tests/vpath-directive-dynamic.mk new file mode 100644 index 0000000000..9aa1bf956c --- /dev/null +++ b/build/pymake/tests/vpath-directive-dynamic.mk @@ -0,0 +1,12 @@ +$(shell \ +mkdir subd1; \ +touch subd1/test.in; \ +) + +VVAR = %.in subd1 + +vpath $(VVAR) + +all: test.in + test "$<" = "subd1/test.in" + @echo TEST-PASS diff --git a/build/pymake/tests/vpath-directive.mk b/build/pymake/tests/vpath-directive.mk new file mode 100644 index 0000000000..4c7d4bf39a --- /dev/null +++ b/build/pymake/tests/vpath-directive.mk @@ -0,0 +1,31 @@ +# On Windows, MSYS make takes Unix paths but Pymake takes Windows paths +VPSEP := $(if $(and $(__WIN32__),$(.PYMAKE)),;,:) + +$(shell \ +mkdir subd1 subd2 subd3; \ +printf "reallybaddata" >subd1/foo.in; \ +printf "gooddata" >subd2/foo.in; \ +printf "baddata" >subd3/foo.in; \ +touch subd1/foo.in2 subd2/foo.in2 subd3/foo.in2; \ +) + +vpath %.in subd + +vpath +vpath %.in subd2$(VPSEP)subd3 + +vpath %.in2 subd0 +vpath f%.in2 subd1 +vpath %.in2 $(VPSEP)subd2 + +%.out: %.in + test "$<" = "subd2/foo.in" + cp $< $@ + +%.out2: %.in2 + test "$<" = "subd1/foo.in2" + cp $< $@ + +all: foo.out foo.out2 + test "$$(cat foo.out)" = "gooddata" + @echo TEST-PASS diff --git a/build/pymake/tests/vpath.mk b/build/pymake/tests/vpath.mk new file mode 100644 index 0000000000..06f52180ca --- /dev/null +++ b/build/pymake/tests/vpath.mk @@ -0,0 +1,18 @@ +VPATH = foo bar + +$(shell \ +mkdir foo; touch foo/tfile1; \ +mkdir bar; touch bar/tfile2 bar/tfile3 bar/test.objtest; \ +sleep 2; \ +touch bar/test.source; \ +) + +all: tfile1 tfile2 tfile3 test.objtest test.source + test "$^" = "foo/tfile1 bar/tfile2 tfile3 test.objtest bar/test.source" + @echo TEST-PASS + +tfile3: test.objtest + +%.objtest: %.source + test "$<" = bar/test.source + test "$@" = test.objtest diff --git a/build/pymake/tests/vpath2.mk b/build/pymake/tests/vpath2.mk new file mode 100644 index 0000000000..be73ffe5c0 --- /dev/null +++ b/build/pymake/tests/vpath2.mk @@ -0,0 +1,18 @@ +VPATH = foo bar + +$(shell \ +mkdir bar; touch bar/test.source; \ +sleep 2; \ +mkdir foo; touch foo/tfile1; \ +touch bar/tfile2 bar/tfile3 bar/test.objtest; \ +) + +all: tfile1 tfile2 tfile3 test.objtest test.source + test "$^" = "foo/tfile1 bar/tfile2 bar/tfile3 bar/test.objtest bar/test.source" + @echo TEST-PASS + +tfile3: test.objtest + +%.objtest: %.source + test "$<" = bar/test.source + test "$@" = test.objtest diff --git a/build/pymake/tests/wildcards.mk b/build/pymake/tests/wildcards.mk new file mode 100644 index 0000000000..24ff3f14ce --- /dev/null +++ b/build/pymake/tests/wildcards.mk @@ -0,0 +1,22 @@ +$(shell \ +mkdir foo; \ +touch a.c b.c c.out foo/d.c; \ +sleep 2; \ +touch c.in; \ +) + +VPATH = foo + +all: c.out prog + cat $< + test "$$(cat $<)" = "remadec.out" + @echo TEST-PASS + +*.out: %.out: %.in + test "$@" = c.out + test "$<" = c.in + printf "remade$@" >$@ + +prog: *.c + test "$^" = "a.c b.c" + touch $@ diff --git a/build/pymake/tests/windows-paths.mk b/build/pymake/tests/windows-paths.mk new file mode 100644 index 0000000000..5f33a90505 --- /dev/null +++ b/build/pymake/tests/windows-paths.mk @@ -0,0 +1,5 @@ +all: + touch file.in + printf "%s: %s\n\ttrue" '$(CURDIR)/file.out' '$(CURDIR)/file.in' >test.mk + $(MAKE) -f test.mk $(CURDIR)/file.out + @echo TEST-PASS |