diff options
Diffstat (limited to 'tests')
63 files changed, 4551 insertions, 313 deletions
diff --git a/tests/bash/testscript b/tests/bash/testscript index 1e5665c..05f48a1 100644 --- a/tests/bash/testscript +++ b/tests/bash/testscript @@ -119,7 +119,7 @@ if ($test.target == $build.host && $build.host.class != 'windows') } fi - @import sub/foo@ + @import sub.bash/foo@ EOI cat <<EOI >=buildfile; @@ -140,7 +140,7 @@ if ($test.target == $build.host && $build.host.class != 'windows') : { cat <<EOI >=test.bash.in; - @import sub/foo@ + @import sub.bash/foo@ EOI cat <<EOI >=driver.in; diff --git a/tests/build/root.build b/tests/build/root.build index 00fa374..712e73c 100644 --- a/tests/build/root.build +++ b/tests/build/root.build @@ -14,7 +14,15 @@ if ($cxx.target.system == 'win32-msvc') if ($cxx.class == 'msvc') cxx.coptions += /wd4251 /wd4275 /wd4800 elif ($cxx.id == 'gcc') - cxx.coptions += -Wno-maybe-uninitialized -Wno-free-nonheap-object # libbutl +{ + cxx.coptions += -Wno-maybe-uninitialized -Wno-free-nonheap-object \ +-Wno-stringop-overread # libbutl + + if ($cxx.version.major >= 13) + cxx.coptions += -Wno-dangling-reference +} +elif ($cxx.id.type == 'clang' && $cxx.version.major >= 15) + cxx.coptions += -Wno-unqualified-std-cast-call # Setup the build system driver that we are testing (which may not be the same # as our $build.path). We also need to disable importation using the built-in diff --git a/tests/cc/libu/testscript b/tests/cc/libu/testscript index 9db3406..b562157 100644 --- a/tests/cc/libu/testscript +++ b/tests/cc/libu/testscript @@ -2,7 +2,7 @@ # license : MIT; see accompanying LICENSE file crosstest = false -test.arguments = config.cxx=$quote($recall($cxx.path) $cxx.config.mode, true) +test.arguments = config.cxx=$quote($recall($cxx.path) $cxx.config.mode) .include ../../common.testscript diff --git a/tests/cc/modules/common.testscript b/tests/cc/modules/common.testscript index 6f09c62..9883e42 100644 --- a/tests/cc/modules/common.testscript +++ b/tests/cc/modules/common.testscript @@ -2,7 +2,7 @@ # license : MIT; see accompanying LICENSE file crosstest = false -test.arguments = config.cxx=$quote($recall($cxx.path) $cxx.config.mode, true) +test.arguments = config.cxx=$quote($recall($cxx.path) $cxx.config.mode) .include ../../common.testscript @@ -21,7 +21,15 @@ cxx.std = experimental cxx.features.symexport = true # @@ TMP revise -if ($cxx.id == 'gcc') +# +# Note: there are some issues with enabling modules in Apple Clang 15 so +# for now we only test vanilla Clang. +# +if (($cxx.id == 'gcc' && $cxx.version.major >= 11) || \ + ($cxx.id == 'clang' && $cxx.version.major >= 16) || \ + ($cxx.id == 'msvc' && ($cxx.version.major > 19 || \ + ($cxx.version.major == 19 && \ + $cxx.version.minor >= 36)))) cxx.features.modules = true using cxx @@ -38,7 +46,7 @@ if ($cxx.target.class == 'windows') exe{*}: test = true EOI -# Determine if we have modules and header units support. +# Determine if we have named modules and header units support. # +$* noop <<EOI | set modules print $cxx.features.modules @@ -47,3 +55,12 @@ EOI +$* noop <<EOI | set headers print ($cxx.features.modules && $cxx.id == 'gcc') EOI + +# @@ TMP: modules support is broken in MinGW GCC (not just symexport). +# @@ TMP: try modules with Clang on Windows (symexport seems to work). +# +if ($cxx.target.class == 'windows' && \ + ($cxx.id == 'gcc' || $cxx.id.type == 'clang')) + modules = false + headers = false +end diff --git a/tests/cc/modules/modules.testscript b/tests/cc/modules/modules.testscript index 681238a..c286c1f 100644 --- a/tests/cc/modules/modules.testscript +++ b/tests/cc/modules/modules.testscript @@ -205,15 +205,11 @@ $* test clean <<EOI : : Test global module fragment/leading module marker (module;). : -if ($cxx.id != 'msvc') # Disabled for MSVC due to issue 845845. -{ cat <<EOI >=g.hxx; void g (); EOI cat <<EOI >=core.mxx; -#if __cpp_modules >= 201810 module; -#endif #include "g.hxx" EOI @@ -222,7 +218,6 @@ ln -s ../core.cxx ../driver.cxx ./; $* test clean <<EOI exe{test}: cxx{driver} {mxx cxx}{core} EOI -} : re-export : @@ -354,7 +349,7 @@ $* test --verbose 1 <<EOI 2>>EOE; exe{test}: cxx{driver} {mxx}{foo-core} exe{test}: test.arguments = two EOI - c++ cxx{driver} + c++ cxx{driver} -> obje{driver} ld exe{test} test exe{test} EOE @@ -373,20 +368,28 @@ cat <<EOI >=core.mxx; export __symexport int f (int); - __symexport int g_impl (int i) {return i - 1;} + __symexport int g_impl (int i); export __symexport inline int g (int i) {return g_impl (i);} + + export __symexport int v1 = 1; + export __symexport extern int v2; EOI ln -s ../core.cxx core-f.cxx; cat <<EOI >=core-g.cxx; module foo.core; int g_impl (int i) {return i - 1;} + int v = 1; + EOI +cat <<EOI >=core-v.cxx; + module foo.core; + int v2 = -1; EOI cat <<EOI >=driver.cxx; import foo.core; - int main (int argc, char*[]) {return f (argc) + g (argc);} + int main (int argc, char*[]) {return f (argc) + g (argc) + v1 + v2;} EOI $* test clean <<EOI ./: lib{foo} exe{test} # Full build. exe{test}: cxx{driver} lib{foo} - lib{foo}: mxx{core} cxx{core-f} # @@ VC: core-g + lib{foo}: mxx{core} cxx{core-g core-f core-v} EOI diff --git a/tests/cc/preprocessed/testscript b/tests/cc/preprocessed/testscript index 269cafe..53e7755 100644 --- a/tests/cc/preprocessed/testscript +++ b/tests/cc/preprocessed/testscript @@ -2,7 +2,7 @@ # license : MIT; see accompanying LICENSE file crosstest = false -test.arguments = config.cxx=$quote($recall($cxx.path) $cxx.config.mode, true) update +test.arguments = config.cxx=$quote($recall($cxx.path) $cxx.config.mode) update .include ../../common.testscript @@ -10,7 +10,7 @@ test.arguments = config.cxx=$quote($recall($cxx.path) $cxx.config.mode, true) up # # trace: cxx::compile::apply extracting (headers|modules) from: .../obje{(test).o...} # -filter = sed -n -e \ +filter = [cmdline] sed -n -e \ \''s/^trace: cxx::compile_rule::apply: extracting ([^ ]+) from[^{]+\{([^.]+).*/\1 \2/p'\' +cat <<EOI >=build/root.build @@ -98,6 +98,7 @@ $* &test* <<EOI 2>>EOE != 0 exe{test}: cxx{test} EOI error: modules support required by cxx{test} + info: consider enabling modules with cxx.features.modules=true in root.build EOE : all diff --git a/tests/dependency/recipe/testscript b/tests/dependency/recipe/testscript index 09a38ad..a581724 100644 --- a/tests/dependency/recipe/testscript +++ b/tests/dependency/recipe/testscript @@ -406,7 +406,7 @@ alias{x}: echo } EOI -<stdin>:3:1: error: expected recipe block instead of '{' +<stdin>:3:1: error: expected recipe block or 'recipe' instead of '{' EOE : duplicate-action-single @@ -418,7 +418,7 @@ alias{x}: echo }} EOI -<stdin>:2:3: error: duplicate recipe for perform(update) +<stdin>:2:3: error: duplicate perform(update) recipe EOE : duplicate-action-multiple @@ -433,7 +433,25 @@ alias{x}: echo }} EOI -<stdin>:5:3: error: duplicate recipe for perform(update) +<stdin>:5:3: error: duplicate perform(update) recipe +EOE + +: duplicate-action-multipe-decls +: +$* <<EOI 2>>EOE != 0 +alias{y}: +{{ + echo +}} + +alias{x y}: +% perform(update) +{{ + diag echo + echo +}} +EOI +<stdin>:7:3: error: duplicate perform(update) recipe for target alias{y} EOE : if-else @@ -593,18 +611,42 @@ EOE { : weight-0 : - $* <<EOI 2>>EOE != 0 - alias{x}: - {{ - - exit - }} - dump alias{x} - EOI - <stdin>:3:1: error: unable to deduce low-verbosity script diagnostics name - info: consider specifying it explicitly with the 'diag' recipe attribute - info: or provide custom low-verbosity diagnostics with the 'diag' builtin - EOE + { + : single-operation + : + { + $* <<EOI 2>>~%EOE% + alias{x}: + {{ + + exit + }} + dump alias{x} + EOI + %.{2} + % [diag=update] perform(update) + %.{3} + EOE + } + + : multiple-operations + : + { + $* <<EOI 2>>EOE != 0 + alias{x}: + % update clean + {{ + + exit + }} + dump alias{x} + EOI + <stdin>:4:1: error: unable to deduce low-verbosity script diagnostics name + info: consider specifying it explicitly with the 'diag' recipe attribute + info: or provide custom low-verbosity diagnostics with the 'diag' builtin + EOE + } + } : weight-1 : @@ -657,7 +699,7 @@ EOE : process-path-ex : { - config_cxx = config.cxx=$quote($recall($cxx.path) $cxx.config.mode, true) + config_cxx = config.cxx=$quote($recall($cxx.path) $cxx.config.mode) mkdir build; cat <<EOI >=build/bootstrap.build; @@ -673,7 +715,7 @@ EOE EOI $* $config_cxx <<EOI 2>>~%EOE% - c = $cxx.path --version + c = [cmdline] $cxx.path --version alias{x}: {{ $c @@ -711,7 +753,7 @@ EOE $* <<EOI 2>>EOE != 0 alias{x}: {{ - foo = bar + foo = [cmdline] bar $foo }} dump alias{x} @@ -827,8 +869,11 @@ EOE % .+alias\{x\}:% % perform(update) {{ + rm a + echo b | set c diag bar - %.{4} + fo$v + }} EOE } } diff --git a/tests/directive/assert.testscript b/tests/directive/assert.testscript index 2543536..d869863 100644 --- a/tests/directive/assert.testscript +++ b/tests/directive/assert.testscript @@ -23,7 +23,7 @@ EOE : invalid : $* <'assert junk' 2>>EOE != 0 -<stdin>:1:8: error: invalid bool value: 'junk' +<stdin>:1:8: error: invalid bool value 'junk' EOE : null diff --git a/tests/directive/config.testscript b/tests/directive/config.testscript index e84ca0a..ebdd6ac 100644 --- a/tests/directive/config.testscript +++ b/tests/directive/config.testscript @@ -14,7 +14,7 @@ test.arguments = EOI +cat <<EOI >=build/root.build - config [bool] config.test.fancy ?= false + config [bool, null] config.test.fancy ?= false print ($defined(config.test.fancy) ? $config.test.fancy : undefined) EOI @@ -56,6 +56,7 @@ test.arguments = $* noop config.test.fancy=junk 2>>EOE != 0 error: invalid bool value 'junk' in variable config.test.fancy + info: while converting 'junk' EOE } @@ -109,10 +110,10 @@ test.arguments = $* noop config.test.fancy=junk 2>>EOE != 0 error: invalid bool value 'junk' in variable config.test.fancy + info: while converting 'junk' EOE } - : default-none : { @@ -123,7 +124,7 @@ test.arguments = EOI +cat <<EOI >=build/root.build - config [bool] config.test.fancy + config [bool, null] config.test.fancy print ($defined(config.test.fancy) ? $config.test.fancy : undefined) EOI @@ -160,6 +161,38 @@ test.arguments = $* noop config.test.fancy=junk 2>>EOE != 0 error: invalid bool value 'junk' in variable config.test.fancy + info: while converting 'junk' + EOE +} + +: non-nullable +: +{ + .include ../common.testscript + + +cat <<EOI >+build/bootstrap.build + using config + EOI + + +cat <<EOI >=build/root.build + config [bool] config.test.fancy ?= false + print ($defined(config.test.fancy) ? $config.test.fancy : undefined) + EOI + + # This must be a single, serial test since we are sharing config.build. + # + : test + : + cat <<EOI >=buildfile; + ./: + EOI + + $* noop >'false' ; + $* noop config.test.fancy=false >'false' ; + $* noop config.test.fancy=true >'true' ; + + $* noop config.test.fancy=[null] 2>>~/EOE/ != 0 + /.+root.build:1:1: error: null value in non-nullable variable config\.test\.fancy/ EOE } @@ -179,12 +212,14 @@ test.arguments = config [strings, config.report=multiline] config.test.d ?= 1 2 3 config [string, config.report.variable=e] config.test.e ?= abc config [ config.report] f + config [ config.report.variable=g] gg config [bool] config.test.n ?= [null] config [bool] config.test.p config [bool] config.test.p ?= true e = "'$config.test.e'" f = ($config.test.b || $config.test.c) + g = abc EOI @@ -207,6 +242,7 @@ test.arguments = 3 e 'abc' f true + gg abc n [null] p true EOO @@ -229,6 +265,7 @@ test.arguments = 3 e 'xyz' f true + gg abc n true p false EOO diff --git a/tests/directive/parsing.testscript b/tests/directive/parsing.testscript index 04dd054..3f180f0 100644 --- a/tests/directive/parsing.testscript +++ b/tests/directive/parsing.testscript @@ -1,4 +1,4 @@ -# file : tests/directive/assert.testscript +# file : tests/directive/parsing.testscript # license : MIT; see accompanying LICENSE file # Test overall directive parsing. diff --git a/tests/directive/run.testscript b/tests/directive/run.testscript index 199dd5f..ecff0fe 100644 --- a/tests/directive/run.testscript +++ b/tests/directive/run.testscript @@ -25,8 +25,9 @@ EOI : bad-exit : cat <'assert false' >=buildfile; -$* <"$run" 2>>EOE != 0 +$* <"$run" 2>>~/EOE/ != 0 buildfile:1:1: error: assertion failed +/<stdin>:1:5: error: process .+ exited with code 1/ EOE : bad-output diff --git a/tests/eval/qual.testscript b/tests/eval/qual.testscript index 29f6340..88339fd 100644 --- a/tests/eval/qual.testscript +++ b/tests/eval/qual.testscript @@ -5,8 +5,9 @@ .include ../common.testscript -$* <'print (file{foo}: bar)' >'file{foo}:bar' : target -$* <'print (foo/dir{}: bar)' >'dir{foo/}:bar' : scope +$* <'print (file{foo}: bar)' >'bar:file{foo}' : target +$* <'print (file{foo}@./: bar)' >'bar:file{foo}@./' : target-out +$* <'print (foo/dir{}: bar)' >'bar:dir{foo/}' : target-dir : attribute : diff --git a/tests/expansion/escape.testscript b/tests/expansion/escape.testscript new file mode 100644 index 0000000..1140032 --- /dev/null +++ b/tests/expansion/escape.testscript @@ -0,0 +1,17 @@ +# file : tests/expansion/type.testscript +# license : MIT; see accompanying LICENSE file + +# Test escape sequence expansion. + +.include ../common.testscript + +: simple +: +$* <<EOI >>EOO +print "foo$\nbar" +print $size([string] "foo$\0bar") +EOI +foo +bar +7 +EOO diff --git a/tests/expansion/subscript.testscript b/tests/expansion/subscript.testscript index 0c06394..38728d4 100644 --- a/tests/expansion/subscript.testscript +++ b/tests/expansion/subscript.testscript @@ -85,7 +85,7 @@ EOE : invalid-subscript : $* <'print ($x[1a])' 2>>EOE != 0 -<stdin>:1:11: error: invalid value subscript: invalid uint64 value: '1a' +<stdin>:1:11: error: invalid value subscript: invalid uint64 value '1a' <stdin>:1:9: info: use the '\[' escape sequence if this is a wildcard pattern EOE diff --git a/tests/function/builtin/testscript b/tests/function/builtin/testscript index 3d31ca2..04e8bd8 100644 --- a/tests/function/builtin/testscript +++ b/tests/function/builtin/testscript @@ -53,6 +53,34 @@ $* <'print $empty(abc)' >'false' : name $* <'print $empty(abc cxx{foo})' >'false' : names $* <'print $empty([bool] false)' >'false' : bool + $* <'print $empty([json] null)' >'true' : json-null + $* <'print $empty([json] "[]")' >'true' : json-array + $* <'print $empty([json] "{}")' >'true' : json-object +} + +: first-second +: +{ + $* <'print $first(a@1)' >'a' : first + $* <'print $second(a@1)' >'1' : second + + $* <'print $first(@1)' >'{}' : first-empty + $* <'print $second(a@)' >'{}' : second-empty + + $* <'print $first(1)' >'[null]' : first-null + $* <'print $second(a)' >'[null]' : second-null + + $* <'print $first(1, true)' >'1' : first-all + $* <'print $second(a, true)' >'a' : second-all + + $* <'print $first(0 a@1 b@2 c@ 4)' >'a b c' : firsts + $* <'print $second(z a@1 b@2 @3 d)' >'1 2 3' : seconds + + $* <'print $first(0 a@1 b@2 c@ 4, true)' >'0 a b c 4' : firsts-all + $* <'print $second(z a@1 b@2 @3 d, true)' >'z 1 2 3 d' : seconds-all + + $* <'print $first([name_pair] a@1)' >'a' : first-typed + $* <'print $second([name_pair] a@1)' >'1' : second-typed } : identity @@ -86,8 +114,8 @@ : likely is set at the time of login, and on Windows it is set by build2 on : startup. : - : @@ Use a custom variable, when an ability to set environment variables in - : testscript is implemented. + : @@ TMP Use a custom variable, when an ability to set environment variables + : in testscript is implemented. It is now! : { : string diff --git a/tests/function/filesystem/testscript b/tests/function/filesystem/testscript index cf93b8b..c7c08f1 100644 --- a/tests/function/filesystem/testscript +++ b/tests/function/filesystem/testscript @@ -73,3 +73,51 @@ EOE } } + +: file_exists +: +{ + : file + : + touch f; + $* <'print $file_exists(f)' >'true' + + : symlink + : + touch f && ln -s f s; + $* <'print $file_exists([path] s)' >'true' + + : directory + : + mkdir d; + $* <'print $file_exists([dir_path] d)' >'false' + + : testscript + : + touch f; + echo $file_exists(f) >'true' +} + +: directory_exists +: +{ + : directory + : + mkdir d; + $* <'print $directory_exists(d)' >'true' + + : symlink + : + mkdir d && ln -s d s; + $* <'print $directory_exists([dir_path] d)' >'true' + + : file + : + touch f; + $* <'print $directory_exists([path] f)' >'false' + + : testscript + : + mkdir d; + echo $directory_exists(d) >'true' +} diff --git a/tests/function/install/testscript b/tests/function/install/testscript index 12cd506..2c70871 100644 --- a/tests/function/install/testscript +++ b/tests/function/install/testscript @@ -28,6 +28,7 @@ EOI $* <'print $install.resolve([dir_path] foo/a)' 2>>EOE != 0 error: unknown installation directory name 'foo' info: did you forget to specify config.install.foo? + info: specify !config.install.foo=... if installing from multiple projects <stdin>:1:8: info: while calling install.resolve(dir_path) EOE } diff --git a/tests/function/integer/buildfile b/tests/function/integer/buildfile new file mode 100644 index 0000000..308fe09 --- /dev/null +++ b/tests/function/integer/buildfile @@ -0,0 +1,4 @@ +# file : tests/function/integer/buildfile +# license : MIT; see accompanying LICENSE file + +./: testscript $b diff --git a/tests/function/integer/testscript b/tests/function/integer/testscript new file mode 100644 index 0000000..ad2d3bb --- /dev/null +++ b/tests/function/integer/testscript @@ -0,0 +1,41 @@ +# file : tests/function/integer/testscript +# license : MIT; see accompanying LICENSE file + +.include ../../common.testscript + +: integer-sequence +: +{ + $* <'print $integer_sequence(1, 3)' >'1 2' : basics + $* <'print $integer_sequence(1, 0)' >'' : empty + $* <'print $integer_sequence(0, 8, 2)' >'0 2 4 6' : step +} + +: string +: +{ + $* <'print $string([uint64] 0xffff)' >'65535' : uint + $* <'print $string([uint64] 0xffff, 16)' >'0xffff' : uint-hex + $* <'print $string([uint64] 0xffff, 16, 8)' >'0x0000ffff' : uint-hex-width +} + +: sort +: +{ + $* <'print $sort([uint64s] 0 2 1 000)' >'0 0 1 2' : basics + $* <'print $sort([uint64s] 0 2 1 000, dedup)' >'0 1 2' : dedup +} + +: find +: +{ + $* <'print $find([uint64s] 1 2 3, 2)' >'true' : basics-true + $* <'print $find([uint64s] 1 2 3, 0)' >'false' : basics-false +} + +: find_index +: +{ + $* <'print $find_index([int64s] -1 -2 -3, -2)' >'1' : basics-true + $* <'print $find_index([int64s] -1 -2 -3, 0)' >'3' : basics-false +} diff --git a/tests/function/json/buildfile b/tests/function/json/buildfile new file mode 100644 index 0000000..45c60d2 --- /dev/null +++ b/tests/function/json/buildfile @@ -0,0 +1,4 @@ +# file : tests/function/json/buildfile +# license : MIT; see accompanying LICENSE file + +./: testscript $b diff --git a/tests/function/json/testscript b/tests/function/json/testscript new file mode 100644 index 0000000..54e524f --- /dev/null +++ b/tests/function/json/testscript @@ -0,0 +1,257 @@ +# file : tests/function/json/testscript +# license : MIT; see accompanying LICENSE file + +# See also tests in type/json/. + +.include ../../common.testscript + +: type +: +$* <<EOI >>EOO +print $value_type([json] ) +print $value_type([json] null) +print $value_type([json] true) +print $value_type([json] 123) +print $value_type([json] -123) +print $value_type([json] 123, true) +print $value_type([json] -123, true) +print $value_type([json] 1 2 3) +print $value_type([json] one@1 two@2 three@3) + +j = [json] one@1 two@2 three@3 +i = [uint64] 1 +m = ($j[$i]) +print $value_type($j[$i]) +print $value_type($m) +EOI +null +null +boolean +number +number +unsigned number +signed number +array +object +object +object +EOO + +: value-size +: +$* <<EOI >>EOO +print $value_size([json] null) +print $value_size([json] true) +print $value_size([json] 123) +print $value_size([json] abc) +print $size([string] ([json] abc)) # @@ Should be 3 (quoted, type hint). +print $value_size([json] 1 2 3) +print $value_size([json] one@1 two@2 three@3) + +print $array_size([json] 1 2 3) +print $array_size([json] null) +EOI +0 +1 +1 +1 +5 +3 +3 +3 +0 +EOO + +: member +: +$* <<EOI >>EOO +j = [json] one@1 two@2 three@3 +i = [uint64] 1 +m = ($j[$i]) +print $member_name($j[$i]) $member_value($j[$i]) +print $member_name($m) $member_value($m) +for m: $j + print $member_name($m) $member_value($m) +EOI +two 2 +two 2 +one 1 +two 2 +three 3 +EOO + +: names +: +$* <<EOI >>EOO +j = [json] one@1 two@2 three@3 +for n: $object_names($j) + print $n ($j[$n]) + +print $object_names([json] null) +EOI +one 1 +two 2 +three 3 + +EOO + +: find +: +$* <<EOI >>EOO +j = [json] 1 ([json] one@1 two@2) 2 true 3 null 4 abc -5 null ([json] 1 2 3) +print $array_find_index($j, null) +print $array_find_index($j, true) +print $array_find_index($j, 3) +print $array_find_index($j, 0x4) +print $array_find_index($j, -5) +print $array_find_index($j, abc) +print $array_find_index($j, [json] 1 2 3) +print $array_find_index($j, [json] two@2 one@1) +print $array_find_index($j, [json] 1 2) +print $array_find_index($j, [json] one@1) +print $array_find_index($j, [json] one@1 two@2 three@3) +print $array_find_index($j, [json] one@1 TWO@3) +print $array_find_index($j, [json] one@1 two@3) +print $array_find_index([json] null, 1) +EOI +5 +3 +4 +6 +8 +7 +10 +1 +11 +11 +11 +11 +11 +0 +EOO + +: parse +: +{ + : basics + : + $* <<EOI >>EOO + print $json.parse('[123, "abc", {"one":1, "two":2}]') + EOI + [123,"abc",{"one":1,"two":2}] + EOO + + : diagnostics-invalid-input + : + $* <<EOI 2>>EOE != 0 + print $json.parse('{"one":, "two":2}]') + EOI + error: invalid json input: unexpected byte ',' in value + info: line 1, column 8, byte offset 8 + <stdin>:1:8: info: while calling json.parse(<untyped>) + EOE + + : diagnostics-duplicate-input + : + $* <<EOI 2>>EOE != 0 + print $json.parse('{"one":1, "one":2}]') + EOI + error: invalid json input: duplicate object member 'one' + info: line 1, column 11, byte offset 15 + <stdin>:1:8: info: while calling json.parse(<untyped>) + EOE +} + +: serialize +: +{ + : basics + : + $* <<EOI >>EOO + j = [json] 123 abc ([json] one@1 two@2) + print $json.serialize($j) + print $json.serialize($j, 0) + EOI + [ + 123, + "abc", + { + "one": 1, + "two": 2 + } + ] + [123,"abc",{"one":1,"two":2}] + EOO + + : diagnostics + : + if false + { + # This is not easy to trigger normally so we have a normally-disabled + # special hack in the $json.serialize() implementation to trigger this. + # + $* <<EOI 2>>EOE != 0 + print $json.serialize([json] deadbeef) + EOI + error: invalid json value: invalid UTF-8 text + info: while serializing string value + info: offending byte offset 4 + <stdin>:1:8: info: while calling json.serialize(json) + EOE + } + +} + +: load +: +{ + : basics + : + cat <<EOI >=input.json; + { + "str":"abc", + "num":123, + "arr":[1, 2, 3], + "obj":{"one":1, "two":2, "three":3} + } + EOI + $* <<EOI >>EOO + j = $json.load(input.json) + for m: $j + print $member_name($m) $member_value($m) + EOI + str abc + num 123 + arr [1,2,3] + obj {"one":1,"two":2,"three":3} + EOO + + : diagnostics + : + cat <<EOI >=input.json; + { + "str":"abc", + "num":, + "arr":[1, 2, 3], + "obj":{"one":1, "two":2, "three":3} + } + EOI + $* <<EOI 2>>EOE != 0 + j = $json.load(input.json) + EOI + input.json:3:9: error: invalid json input: unexpected byte ',' in value + info: byte offset 26 + <stdin>:1:6: info: while calling json.load(<untyped>) + EOE +} + +: size +: +{ + $* <'print $size([json_set] a b b)' >'2' : json-set + $* <'print $size([json_map] a@1 b@2 b@3)' >'2' : json-map +} + +: keys +: +$* <'print $keys([json_map] 2@([json] a@1 b@2 c@3) 1@([json] 1 2 3))' >'[1,2]' diff --git a/tests/function/name/buildfile b/tests/function/name/buildfile new file mode 100644 index 0000000..48be4c3 --- /dev/null +++ b/tests/function/name/buildfile @@ -0,0 +1,4 @@ +# file : tests/function/name/buildfile +# license : MIT; see accompanying LICENSE file + +./: testscript $b diff --git a/tests/function/name/testscript b/tests/function/name/testscript new file mode 100644 index 0000000..4588e1d --- /dev/null +++ b/tests/function/name/testscript @@ -0,0 +1,68 @@ +# file : tests/function/name/testscript +# license : MIT; see accompanying LICENSE file + +.include ../../common.testscript + +: is_a +: +{ + $* <'print $is_a(file{foo}, path_target)' >'true' : basics-true + $* <'print $is_a(alias{foo}, path_target)' >'false' : basics-false + $* <'print $is_a(file{foo}@./, path_target)' >'true' : out + $* <<EOI >'true' : derived + define txt: file + print $is_a(txt{foo}, path_target) + EOI +} + +: filter +: +{ + $* <<EOI >'file{foo}@./ txt{baz}' : basics + define txt: file + print $filter(file{foo}@./ alias{bar} dir{./} txt{baz}, file) + EOI + + $* <<EOI >'file{foo}@./ txt{baz}' : basics-out + define txt: file + print $filter_out(file{foo}@./ alias{bar} dir{./} txt{baz}, alias) + EOI + + $* <<EOI >'file{foo}@./ dir{./} txt{baz}' : multiple + define txt: file + print $filter(file{foo}@./ alias{bar} dir{./} txt{baz}, file dir) + EOI + + $* <<EOI >'file{foo}@./ alias{bar}' : multiple-out + define txt: file + print $filter_out(file{foo}@./ alias{bar} dir{./} txt{baz}, txt dir) + EOI +} + +: size +: +{ + $* <'print $size(a b c@./)' >'3' : basics + $* <'print $type($size(a))' >'uint64' : type +} + +: sort +: +{ + $* <'print $sort(d/t{a} t{c b} d/t{a})' >'t{b} t{c} d/t{a} d/t{a}' : basics + $* <'print $sort(d/t{a} t{c b} d/t{a}, dedup)' >'t{b} t{c} d/t{a}' : dedup +} + +: find +: +{ + $* <'print $find([names] d/t{a} t{a b}, t{a})' >'true' : basics-true + $* <'print $find([names] d/t{a} t{a b}, d/t{b})' >'false' : basics-false +} + +: find_index +: +{ + $* <'print $find_index([names] d/t{a} t{a b}, t{a})' >'1' : basics-true + $* <'print $find_index([names] d/t{a} t{a b}, d/t{b})' >'3' : basics-false +} diff --git a/tests/function/path/testscript b/tests/function/path/testscript index ad76513..6321b3d 100644 --- a/tests/function/path/testscript +++ b/tests/function/path/testscript @@ -3,40 +3,112 @@ .include ../../common.testscript -posix = ($cxx.target.class != 'windows') +windows = ($cxx.target.class == 'windows') +posix = (!$windows) s = ($posix ? '/' : '\') -: canonicalize +: posix-string : { - $* <'print $canonicalize([path] a/b)' >"a$(s)b" : path - $* <'print $canonicalize([paths] a/b a/c)' >"a$(s)b a$(s)c" : paths - $* <'print $canonicalize([dir_path] a/b)' >"a$(s)b$s" : dir-path - $* <'print $canonicalize([dir_paths] a/b a/c/)' >"a$(s)b$s a$(s)c$s" : dir-paths - $* <'print $path.canonicalize(a/b)' >"a$(s)b" : untyped - $* <'print $path.canonicalize(a/b/ a/c)' >"a$(s)b$s a$(s)c" : mixed + : relative + : + { + s = ($posix ? '/' : '\\') + + $* <"print \$posix_string\([path] a$(s)b)" >'a/b' : path + $* <"print \$posix_string\([paths] a$(s)b a$(s)c$(s))" >'a/b a/c' : paths + $* <"print \$posix_string\([dir_path] a$(s)b)" >'a/b' : dir-path + $* <"print \$posix_string\([dir_paths] a$(s)b a$(s)c$(s))" >'a/b a/c' : dir-paths + $* <"print \$path.posix_string\(a$(s)b a$(s)c$(s))" >'a/b a/c' : untyped + } + + : absolute + : + { + if $posix + { + $* <'print $posix_string([paths] /a/b /a/c/)' >'/a/b /a/c' : paths + $* <'print $posix_string([dir_paths] /a/b /a/c/)' >'/a/b /a/c' : dir-paths + $* <'print $posix_string([dir_path] /)' >'/' : root-dir + $* <'print $path.posix_string(/a/b /a/c/)' >'/a/b /a/c' : untyped + } + else + { + $* <'print $posix_string([paths] "c:\\a\\b" "C:\\a\\c\\")' >'c:/a/b C:/a/c' : paths + $* <'print $posix_string([dir_paths] "c:\\a\\b" "C:\\a\\c\\")' >'c:/a/b C:/a/c' : dir-paths + $* <'print $posix_string([dir_paths] "c:\\" "C:")' >'c:/ C:/' : root-dir + $* <'print $path.posix_string("c:\\a\\b" "C:\\a\\c\\")' >'c:/a/b C:/a/c' : untyped + $* <'print $path.posix_string("c:\\" "C:")' >'c:/ C:/' : untyped-root + } + } } -: normalize +: posix-representation : { - $* <'print $normalize([path] a/../b)' >"b" : path - $* <'print $normalize([paths] a/../b a/../c)' >"b c" : paths - $* <'print $normalize([dir_path] a/../b)' >"b$s" : dir-path - $* <'print $normalize([dir_paths] a/../b a/../c/)' >"b$s c$s" : dir-paths - $* <'print $path.normalize(a/../b)' >"b" : untyped - $* <'print $path.normalize(a/../b/ a/../c)' >"b$s c" : mixed + : relative + : + { + s = ($posix ? '/' : '\\') + + $* <"print \$posix_representation\([path] a$(s)b)" >'a/b' : path + $* <"print \$posix_representation\([paths] a$(s)b a$(s)c$(s))" >'a/b a/c/' : paths + $* <"print \$posix_representation\([dir_path] a$(s)b)" >'a/b/' : dir-path + $* <"print \$posix_representation\([dir_paths] a$(s)b a$(s)c$(s))" >'a/b/ a/c/' : dir-paths + $* <"print \$path.posix_representation\(a$(s)b a$(s)c$(s))" >'a/b a/c/' : untyped + } + + : absolute + : + { + if $posix + { + $* <'print $posix_representation([paths] /a/b /a/c/)' >'/a/b /a/c/' : paths + $* <'print $posix_representation([dir_paths] /a/b /a/c/)' >'/a/b/ /a/c/' : dir-paths + $* <'print $posix_representation([dir_path] /)' >'/' : root-dir + $* <'print $path.posix_representation(/a/b /a/c/)' >'/a/b /a/c/' : untyped + } + else + { + $* <'print $posix_representation([paths] "c:\\a\\b" "C:\\a\\c\\")' >'c:/a/b C:/a/c/' : paths + $* <'print $posix_representation([dir_paths] "c:\\a\\b" "C:\\a\\c\\")' >'c:/a/b/ C:/a/c/' : dir-paths + $* <'print $posix_representation([dir_paths] "c:\\" "C:")' >'c:/ C:/' : root-dir + $* <'print $path.posix_representation("c:\\a\\b" "C:\\a\\c\\")' >'c:/a/b C:/a/c/' : untyped + $* <'print $path.posix_representation("c:\\" "C:")' >'c:/ C:/' : untyped-root + } + } } -: actualize +: absolute : -if! $posix { - mkdir Foo; - $* <'print $path.actualize($out_base/foo)' >~'/.+\\Foo/' + $* <'print $absolute($src_root)' >"true" : true + $* <'print $path.absolute(a/b)' >"false" : false +} + +: simple +: +{ + $* <'print $simple([path] a)' >"true" : true + $* <'print $path.simple(a/b)' >"false" : false +} + +: sub_path +: +{ + $* <'print $sub_path($src_base, $src_root)' >"true" : true-absolute + $* <'print $path.sub_path(a/b/c, a/b)' >"true" : true-relative + $* <'print $path.sub_path(a/b/c, a/d)' >"false" : false } +: super_path +: +{ + $* <'print $super_path($src_base, true-absolute)' >"true" : true-absolute + $* <'print $path.super_path(a/b/c, b/c)' >"true" : true-relative + $* <'print $path.super_path(a/b/c, c/a)' >"false" : false +} : directory : @@ -48,6 +120,28 @@ if! $posix $* <'print $path.directory(a/b c/d/)' >"a/ c/" : dir-names } +: root_directory +: +{ + : posix + : + if $posix + { + $* <'print $root_directory([path] /a/b)' >'/' : basics + $* <'print $root_directory([path] /)' >'/' : root + } + + : windows + : + if $windows + { + $* <'print $root_directory([path] "c:\\a\\b")' >'c:\' : basics + $* <'print $root_directory([path] "c:")' >'c:\' : root + } + + $* <'print $root_directory([path] a/b)' >'' : relative +} + : base : { @@ -78,6 +172,12 @@ if! $posix EOE } +: relative +: +{ + $* <'print $relative([path] a/b/c, [dir_path] a/x/y)' >"..$s..$(s)b/c" : basics +} + : extension : { @@ -104,6 +204,92 @@ if! $posix EOO } +: complete +: +{ + $* <'print $complete([path] a)' >"$~$(s)a" : path + $* <'print $complete([dir_path] a)' >"$~$(s)a$(s)" : dir-path + $* <'print $path.complete(a)' >"$~$(s)a" : untyped + + echo $path.complete(a) > "$~$(s)a" : testscript +} + +: canonicalize +: +{ + $* <'print $canonicalize([path] a/b)' >"a$(s)b" : path + $* <'print $canonicalize([paths] a/b a/c)' >"a$(s)b a$(s)c" : paths + $* <'print $canonicalize([dir_path] a/b)' >"a$(s)b$s" : dir-path + $* <'print $canonicalize([dir_paths] a/b a/c/)' >"a$(s)b$s a$(s)c$s" : dir-paths + $* <'print $path.canonicalize(a/b)' >"a$(s)b" : untyped + $* <'print $path.canonicalize(a/b/ a/c)' >"a$(s)b$s a$(s)c" : mixed +} + +: normalize +: +{ + $* <'print $normalize([path] a/../b)' >"b" : path + $* <'print $normalize([paths] a/../b a/../c)' >"b c" : paths + $* <'print $normalize([dir_path] a/../b)' >"b$s" : dir-path + $* <'print $normalize([dir_paths] a/../b a/../c/)' >"b$s c$s" : dir-paths + $* <'print $path.normalize(a/../b)' >"b" : untyped + $* <'print $path.normalize(a/../b/ a/../c)' >"b$s c" : mixed +} + +: try_normalize +: +{ + $* <'print $try_normalize([path] a/../b)' >"b" : valid + $* <'print $path.try_normalize($root_directory($src_root)/..)' >"[null]" : invalid +} + +: actualize +: +if! $posix +{ + mkdir Foo; + $* <'print $path.actualize($out_base/foo)' >~'/.+\\Foo/' +} + +: sort +: +{ + $* <'print $sort([paths] a c b a)' >'a a b c' : basics + $* <'print $sort([paths] a c b a, dedup)' >'a b c' : dedup + + : icase + : + if $windows + { + $* <'print $sort([paths] a C B a)' >'a a B C' + } +} + +: size +: +{ + $* <'print $size([path] abc)' >'3' : basics + $* <'print $size([path] )' >'0' : zero + + $* <'print $size([dir_path] abc)' >'3' : dir-basics + $* <'print $size([dir_path] abc/)' >'3' : dir-separator + $* <'print $size([dir_path] )' >'0' : dir-zero +} + +: find +: +{ + $* <'print $find([paths] x y z, y)' >'true' : basics-true + $* <'print $find([paths] x y z, a)' >'false' : basics-false +} + +: find_index +: +{ + $* <'print $find_index([dir_paths] x y z, y)' >'1' : basics-true + $* <'print $find_index([dir_paths] x y z, a)' >'3' : basics-false +} + : invalid-path : p = ($posix ? /../foo : 'c:/../foo'); diff --git a/tests/function/regex/testscript b/tests/function/regex/testscript index 5167390..538bdab 100644 --- a/tests/function/regex/testscript +++ b/tests/function/regex/testscript @@ -478,6 +478,64 @@ } } +: filter-match +: +{ + : match + : + { + : string + : + $* <<EOI >'-O2 -O3' + print $regex.filter_match(-g -O2 -O3, [string] '-O[23]') + EOI + + : untyped + : + $* <<EOI >'-O2 -O3' + print $regex.filter_match(-g -O2 -O3, '-O[23]') + EOI + + : strings + : + $* <<EOI >'-O2 -O3' + print $regex.filter_match([strings] -g -O2 -O3, '-O[23]') + EOI + + : nomatch + : + $* <<EOI >'' + print $regex.filter_match(-g -O1, '-O[23]') + EOI + } + + : filter-out + : + { + : untyped + : + $* <<EOI >'-g' + print $regex.filter_out_match(-g -O2 -O3, '-O[23]') + EOI + + : all-match + : + $* <<EOI >'' + print $regex.filter_out_match(-O2 -O3, '-O[23]') + EOI + } + + : flags + : + { + : icase + : + $* <<EOI >'Foo.cxx' + print $regex.filter_match(Foo.cxx, 'f[^.]+.*', icase) + EOI + } +} + : find-search : { @@ -520,6 +578,64 @@ } } +: filter-search +: +{ + : match + : + { + : string + : + $* <<EOI >'-O2 -O3' + print $regex.filter_search(-g -O2 -O3, [string] '-O') + EOI + + : untyped + : + $* <<EOI >'-O2 -O3' + print $regex.filter_search(-g -O2 -O3, '-O') + EOI + + : strings + : + $* <<EOI >'-O2 -O3' + print $regex.filter_search([strings] -g -O2 -O3, '-O') + EOI + + : nomatch + : + $* <<EOI >'' + print $regex.filter_search(-g, '-O') + EOI + } + + : filter-out + : + { + : untyped + : + $* <<EOI >'-g' + print $regex.filter_out_search(-g -O2 -O3, '-O') + EOI + + : all-match + : + $* <<EOI >'' + print $regex.filter_out_search(-O2 -O3, '-O') + EOI + } + + : flags + : + { + : icase + : + $* <<EOI >'Foo.cxx' + print $regex.filter_search(Foo.cxx, 'f', icase) + EOI + } +} + : merge : { diff --git a/tests/function/string/testscript b/tests/function/string/testscript index 9275fe5..8eb5760 100644 --- a/tests/function/string/testscript +++ b/tests/function/string/testscript @@ -25,9 +25,154 @@ } } +: contains +: +{ + : basics + : + { + $* <'print $string.contains( abcd, bc)' >'true' : true + $* <'print $string.contains( abcd, ac)' >'false' : false + $* <'print $contains([string] abcd, cd)' >'true' : typed + } + + : icase + : + { + $* <'print $string.contains(aBcD, bC, icase)' >'true' : true + } + + : once + : + { + $* <'print $string.contains(abcdabcd, da, once)' >'true' : true + $* <'print $string.contains(abcdabcd, bc, once)' >'false' : false + } +} + +: starts_with +: +{ + : basics + : + { + $* <'print $string.starts_with( abcd, ab)' >'true' : true + $* <'print $string.starts_with( abcd, bc)' >'false' : false + $* <'print $starts_with([string] abcd, abcd)' >'true' : typed + } + + : icase + : + { + $* <'print $string.starts_with(aBcD, Ab, icase)' >'true' : true + } +} + +: ends_with +: +{ + : basics + : + { + $* <'print $string.ends_with( abcd, cd)' >'true' : true + $* <'print $string.ends_with( abcd, bc)' >'false' : false + $* <'print $ends_with([string] abcd, abcd)' >'true' : typed + } + + : icase + : + { + $* <'print $string.ends_with(aBcD, Cd, icase)' >'true' : true + } +} + +: replace +: +{ + : basics + : + { + $* <'print $string.replace( abcb, b, BB)' >'aBBcBB' : expand + $* <'print $string.replace( aabbccbb, bb, B)' >'aaBccB' : shrink + $* <'print $replace([string] abc, b, B)' >'aBc' : typed + $* <'print $replace([string] "", b, B)' >'' : empty + $* <'print $replace([string] bbb, b, "")' >'' : to-empty + $* <'print $replace([string] bb, b, Bb)' >'BbBb' : no-recursion + } + + : icase + : + { + $* <'print $string.replace(abcB, b, X, icase)' >'aXcX' + } + + : first + : + { + $* <'print $string.replace(babc, b, B, first_only)' >'Babc' : first + $* <'print $string.replace(abcb, b, B, first_only)' >'aBcb' : middle + $* <'print $string.replace(b, b, B, first_only)' >'B' : only + } + + : last + : + { + $* <'print $string.replace(babc, b, B, last_only)' >'baBc' : middle + $* <'print $string.replace(abcb, b, B, last_only)' >'abcB' : last + $* <'print $string.replace(b, b, B, last_only)' >'B' : only + } + + : first-and-last + : + { + $* <'print $string.replace(ac, b, B, first_only last_only)' >'ac' : zero + $* <'print $string.replace(abc, b, B, first_only last_only)' >'aBc' : one + $* <'print $string.replace(abcb, b, B, first_only last_only)' >'abcb' : two + $* <'print $string.replace(b, b, B, first_only last_only)' >'B' : only + } +} + : trim : { $* <'print $trim([string] " a ")' >'a' : string $* <'print $string.trim( " a ")' >'a' : untyped } + +: sort +: +{ + $* <'print $sort([strings] a c b a)' >'a a b c' : basics + $* <'print $sort([strings] a c b a, dedup)' >'a b c' : dedup + $* <'print $sort([strings] a C B a, icase)' >'a a B C' : icase +} + +: size +: +{ + $* <'print $size([string] abc)' >'3' : basics + $* <'print $size([string] )' >'0' : zero + $* <'print $size([strings] a b c)' >'3' : strings + $* <'print $size([string_set] a b b)' >'2' : string-set + $* <'print $size([string_map] a@1 b@2 b@3)' >'2' : string-map +} + +: find +: +{ + $* <'print $find([strings] x y z, y)' >'true' : basics-true + $* <'print $find([strings] x y z, Y)' >'false' : basics-false + $* <'print $find([strings] x y z, Y, icase)' >'true' : icase +} + +: find_index +: +{ + $* <'print $find_index([strings] x y z, y)' >'1' : basics-true + $* <'print $find_index([strings] x y z, Y)' >'3' : basics-false + $* <'print $find_index([strings] x y z, Y, icase)' >'1' : icase +} + +: keys +: +$* <'print $keys([string_map] a@1 b@2 c@3)' >'a b c' diff --git a/tests/in/testscript b/tests/in/testscript index 0d5be48..5dce1d3 100644 --- a/tests/in/testscript +++ b/tests/in/testscript @@ -17,7 +17,9 @@ cat <<EOI >=test.in; EOI cat <<EOI >=buildfile; file{test}: in{test} - file{test}: foo = FOO + { + foo = FOO + } EOI $* <<<buildfile; cat test >>EOO; @@ -25,6 +27,27 @@ cat test >>EOO; EOO $* clean <<<buildfile +: substitution-map +: +cat <<EOI >=test.in; + foo = $_foo$ + bar = $bar$ + EOI +cat <<EOI >=buildfile; + file{test}: in{test} + { + in.substitutions = _foo@FOO + in.substitutions += bar@BAR + bar = wrong + } + EOI +$* <<<buildfile; +cat test >>EOO; + foo = FOO + bar = BAR + EOO +$* clean <<<buildfile + : lax : cat <<EOI >=test.in; @@ -33,7 +56,9 @@ cat <<EOI >=test.in; EOI $* <<EOI &test &test.d; file{test}: in{test} - file{test}: in.substitution = lax + { + in.mode = lax + } EOI cat test >>EOO $10 diff --git a/tests/libbuild2/driver.cxx b/tests/libbuild2/driver.cxx index 1c4554a..6201a6c 100644 --- a/tests/libbuild2/driver.cxx +++ b/tests/libbuild2/driver.cxx @@ -4,18 +4,26 @@ #include <libbuild2/types.hxx> #include <libbuild2/utility.hxx> +#include <libbuild2/module.hxx> #include <libbuild2/context.hxx> #include <libbuild2/scheduler.hxx> #include <libbuild2/file-cache.hxx> +#include <libbuild2/dist/init.hxx> +#include <libbuild2/test/init.hxx> +#include <libbuild2/config/init.hxx> +#include <libbuild2/install/init.hxx> + #include <libbuild2/in/init.hxx> #include <libbuild2/bin/init.hxx> #include <libbuild2/c/init.hxx> #include <libbuild2/cc/init.hxx> #include <libbuild2/cxx/init.hxx> -#include <libbuild2/bash/init.hxx> #include <libbuild2/version/init.hxx> +#undef NDEBUG +#include <cassert> + using namespace build2; int @@ -24,21 +32,25 @@ main (int, char* argv[]) // Fake build system driver, default verbosity. // init_diag (1); - init (nullptr, argv[0]); + init (nullptr, argv[0], true); + + load_builtin_module (&config::build2_config_load); + load_builtin_module (&dist::build2_dist_load); + load_builtin_module (&test::build2_test_load); + load_builtin_module (&install::build2_install_load); - bin::build2_bin_load (); - cc::build2_cc_load (); - c::build2_c_load (); - cxx::build2_cxx_load (); - version::build2_version_load (); - in::build2_in_load (); - bash::build2_bash_load (); + load_builtin_module (&bin::build2_bin_load); + load_builtin_module (&cc::build2_cc_load); + load_builtin_module (&c::build2_c_load); + load_builtin_module (&cxx::build2_cxx_load); + load_builtin_module (&version::build2_version_load); + load_builtin_module (&in::build2_in_load); // Serial execution. // scheduler sched (1); global_mutexes mutexes (1); - file_cache fcache; + file_cache fcache (true); context ctx (sched, mutexes, fcache); return 0; diff --git a/tests/loop/for.testscript b/tests/loop/for.testscript index 5376029..e043ec0 100644 --- a/tests/loop/for.testscript +++ b/tests/loop/for.testscript @@ -116,3 +116,17 @@ a@1 b@2 c@3 EOO + +: elem-attribute +: +$* <<EOI >>EOO +for i [uint64]: 0 1 2 +{ + i += 1 + print $i +} +EOI +1 +2 +3 +EOO diff --git a/tests/name/extension.testscript b/tests/name/extension.testscript index 1583109..6a542fe 100644 --- a/tests/name/extension.testscript +++ b/tests/name/extension.testscript @@ -131,7 +131,7 @@ EOI EOI f.oo - txt{f.oo.} + EOO : default-extension diff --git a/tests/name/pattern.testscript b/tests/name/pattern.testscript index 91fb98d..c1a4ce4 100644 --- a/tests/name/pattern.testscript +++ b/tests/name/pattern.testscript @@ -18,6 +18,35 @@ pat = '*' print "$(pat).txt" EOI +: typed-concat +: +{ + : dir-path + : + touch foo.txt; + $* <'print {$src_base/*.txt}' >/~'%.+/foo\.txt%' + + : path + : + touch foo.txt; + $* <<EOI >/~'%.+/foo\.txt%' + p = [path] $src_base + print {$p/*.txt} + EOI + + : string + : + touch foo.txt; + $* <<EOI >~'%.+/\*\.txt%' + p = [string] "$src_base" + print {$p/*.txt} + EOI + + : not-pattern + : + $* <'print {$src_base/foo.txt}' >/~'%.+/foo\.txt%' +} + : detect : : Test pattern_mode parsing logic. @@ -332,13 +361,13 @@ EOI : { mkdir dir; - $* <'print $d' 'd=*/' >/'dir/' : dir + $* <'print $p.d' 'p.d=*/' >/'dir/' : dir mkdir dir; - $* <'print $d' 'd=dir{*}' >/'dir{dir/}' : dir-type + $* <'print $p.d' 'p.d=dir{*}' >/'dir{dir/}' : dir-type touch foo.txt; - $* <'print $f' 'f=*.txt' >'foo.txt' : feil + $* <'print $p.f' 'p.f=*.txt' >'foo.txt' : feil } : buildspec diff --git a/tests/recipe/buildscript/testscript b/tests/recipe/buildscript/testscript index 14036dd..cded5ea 100644 --- a/tests/recipe/buildscript/testscript +++ b/tests/recipe/buildscript/testscript @@ -31,7 +31,7 @@ posix = ($cxx.target.class != 'windows') }} EOI - $* 2>'cp file{foo}'; + $* 2>'cp file{bar} -> file{foo}'; cat <<<foo >'bar'; @@ -65,9 +65,9 @@ posix = ($cxx.target.class != 'windows') EOI $* 2>>~%EOE% != 0; - concat file{bar.} + concat file{bar} %cat: unable to print '.+bar.baz': .+% - buildfile:10:3: error: cat exited with code 1 + buildfile:10:3: error: builtin cat exited with code 1 %.+ EOE @@ -75,7 +75,7 @@ posix = ($cxx.target.class != 'windows') echo 'baz' >=bar.baz; - $* 2>'concat file{bar.}'; + $* 2>'concat file{bar}'; cat <<<foo >>EOO; bar @@ -100,7 +100,7 @@ posix = ($cxx.target.class != 'windows') EOI $* 2>>~%EOE% != 0; - cp file{foo} + cp file{bar} -> file{foo} buildfile:4:3: error: stdout and stderr redirected to each other %.+ EOE @@ -108,7 +108,7 @@ posix = ($cxx.target.class != 'windows') $* clean 2>- } - : untracked-var + : computed-var : { cat <<EOI >=buildfile; @@ -121,9 +121,29 @@ posix = ($cxx.target.class != 'windows') }} EOI + $* 2>>EOE != 0 + buildfile:6:10: error: expansion of computed variable is only allowed in depdb preamble + info: consider using 'depdb' builtin to track its value changes + EOE + } + + : untracked-var + : + { + cat <<EOI >=buildfile; + a = a + b = b + foo: + {{ + x = true + y = $($x ? a : b) + depdb env BOGUS + echo $y >$path($>) + }} + EOI + $* 2>>~%EOE% != 0; - echo file{foo} - buildfile:6:10: error: use of untracked variable 'a' + buildfile:6:8: error: use of untracked variable 'a' info: use the 'depdb' builtin to manually track it %.+ EOE @@ -155,13 +175,32 @@ posix = ($cxx.target.class != 'windows') EOI $* test 2>>EOE; - cp exe{foo} - test exe{foo.} + cp file{bar} -> exe{foo} + test exe{foo} EOE $* clean 2>- } + : diag + : + { + cat <<EOI >=buildfile; + foo: + {{ + v1 = foo + echo bar | set v2 + diag echo "$v1 $v2" -> $> + echo "$v1 $v2" >$path($>) + }} + EOI + + $* 2>'echo foo bar -> file{foo}'; + cat <<<foo >'foo bar'; + + $* clean 2>- + } + : depdb : { @@ -201,17 +240,19 @@ posix = ($cxx.target.class != 'windows') a = $process.run(cat baz) foo: bar {{ + x = true + y = $($x ? a : b) depdb hash "$a" + diag compose $> cp $path($<) $path($>) - x = true - echo "$($x ? a : b)" >>$path($>) + echo $y >>$path($>) }} EOI - $* 2>'compose file{foo.}'; + $* 2>'compose file{foo}'; cat <<<foo >>EOO; bar @@ -227,7 +268,7 @@ posix = ($cxx.target.class != 'windows') echo 'BAR' >=bar; - $* 2>'compose file{foo.}'; + $* 2>'compose file{foo}'; cat <<<foo >>EOO; BAR @@ -238,7 +279,7 @@ posix = ($cxx.target.class != 'windows') echo 'BAZ' >=baz; - $* 2>'compose file{foo.}'; + $* 2>'compose file{foo}'; cat <<<foo >>EOO; BAR @@ -250,6 +291,97 @@ posix = ($cxx.target.class != 'windows') $* clean 2>- } + : preamble + : + { + : valid + : + { + echo 'bar' >=bar; + + cat <<EOI >=buildfile; + s = $process.run(cat bar) + foo: + {{ + depdb clear + + s1 = 'abc' + s2 = 'xyz' + + if echo "$s" >>>? 'bar' + v = "$s1" + else + echo "$s2" | set v + end + + depdb string "$v" + + echo "$v" >$path($>) + }} + EOI + + $* 2>'echo file{foo}'; + cat <<<foo >'abc'; + + $* 2>/'info: dir{./} is up to date'; + + echo 'baz' >=bar; + $* 2>'echo file{foo}'; + cat <<<foo >'xyz'; + + $* clean 2>- + } + + : invalid + : + { + cat <<EOI >=buildfile; + foo: + {{ + v = 'abc' + echo "$v" >$path($>) + depdb string "$v" + }} + EOI + + $* 2>>~%EOE% != 0; + buildfile:4:3: error: disallowed command in depdb preamble + info: only variable assignments are allowed in depdb preamble + buildfile:5:3: info: depdb preamble ends here + %.+ + EOE + + $* clean 2>- + } + + : temp-dir + : + { + cat <<EOI >=buildfile; + foo: + {{ + touch $~/f | set dummy + + if test -f $~/f + v = "yes" + else + v = "no" + end + + depdb string "$v" + diag echo $> + + test -f $~/f + echo "$v" >$path($>) + }} + EOI + + $* 2>'echo file{foo}'; + + $* clean 2>- + } + } + : string : { @@ -306,92 +438,158 @@ posix = ($cxx.target.class != 'windows') $* clean 2>- } - : preamble + : env : { - : valid + : invalid : { - echo 'bar' >=bar; - cat <<EOI >=buildfile; - s = $process.run(cat bar) foo: {{ + s = $getenv(FOO) + depdb clear + depdb env FOO=bar + echo "$s" >$path($>) + }} + EOI - s1 = 'abc' - s2 = 'xyz' + $* 2>>/EOE != 0; + buildfile:6:3: error: invalid 'depdb env' argument: invalid variable name 'FOO=bar': contains '=' + info: while updating file{foo} + info: while updating dir{./} + info: failed to update dir{./} + EOE - if echo "$s" >>>? 'bar' - v = "$s1" - else - echo "$s2" | set v - end + $* clean 2>- + } - depdb string "$v" + : valid + : + { + cat <<EOI >=buildfile; + foo: + {{ + s = $getenv(FOO) - echo "$v" >$path($>) + depdb clear + depdb env FOO + echo "$s" >$path($>) }} EOI + export FOO=foo; + $* 2>'echo file{foo}'; - cat <<<foo >'abc'; + cat <<<foo >'foo'; $* 2>/'info: dir{./} is up to date'; - echo 'baz' >=bar; + export FOO=bar; + $* 2>'echo file{foo}'; - cat <<<foo >'xyz'; + cat <<<foo >'bar'; + + export -u FOO; + + $* 2>'echo file{foo}'; + cat <<<foo >''; $* clean 2>- } + } - : invalid + : dyndep + : + { + : normal : { + cat <<EOI >=bar.h; + bar + EOI + cat <<EOI >=buildfile; - foo: + define h: file + h{*}: extension = h + + ./: h{foo baz} + + h{foo}: {{ - v = 'abc' - echo "$v" >$path($>) - depdb string "$v" + # Note that strictly speaking we should return $out_base/baz.h + # on the second invocation (since it now exists). But our dyndep + # machinery skips the entry which it has already seen, so this + # works for now. + # + depdb dyndep "-I$out_base" --what=header --default-type=h -- \ + echo "$out_base/foo.h: $src_base/bar.h baz.h" + + diag gen $> + + cat $path($<) >$path($>) + }} + + h{baz}: + {{ + diag gen $> + echo baz >$path($>) }} EOI - $* 2>>~%EOE% != 0; - buildfile:4:3: error: disallowed command in depdb preamble - info: only variable assignments are allowed in depdb preamble - buildfile:5:3: info: depdb preamble ends here - %.+ + $* 2>>EOE; + gen h{baz} + gen h{foo} EOE + cat foo.h >>EOO; + bar + baz + EOO + $* clean 2>- } - : temp-dir + : byproduct : { + cat <<EOI >=bar.h; + bar + EOI + cat <<EOI >=buildfile; - foo: + define h: file + h{*}: extension = h + + h{foo}: h{baz} {{ - touch $~/f | set dummy + o = $path($>) + t = $path($>).t - if test -f $~/f - v = "yes" - else - v = "no" - end + depdb dyndep --byproduct --what=header --default-type=h --file $t - depdb string "$v" - diag echo $> + diag gen $> + cat $src_base/bar.h $out_base/baz.h >$o + echo "$out_base/foo.h: $src_base/bar.h $out_base/baz.h" >$t + }} - test -f $~/f - echo "$v" >$path($>) + h{baz}: + {{ + diag gen $> + echo baz >$path($>) }} EOI - $* 2>'echo file{foo.}'; + $* 2>>EOE; + gen h{baz} + gen h{foo} + EOE + + cat foo.h >>EOO; + bar + baz + EOO $* clean 2>- } @@ -444,7 +642,7 @@ posix = ($cxx.target.class != 'windows') EOI $* test 2>>EOE; - cp file{foo} + cp file{bar} -> file{foo} test file{foo} EOE @@ -506,7 +704,7 @@ posix = ($cxx.target.class != 'windows') EOI $* test 2>>EOE; - cp file{foo} + cp file{bar} -> file{foo} test file{foo} bar EOE @@ -543,6 +741,30 @@ posix = ($cxx.target.class != 'windows') $* clean 2>- } +: canned-cmdline +: +{ + cat <<EOI >=buildfile; + ./: + {{ + x = echo >| + y = [cmdline] echo >| + diag update $> + $x foo + $y bar + ([cmdline] $x) baz + }} + EOI + + $* >> EOO 2>>/EOE + bar + baz + EOO + update dir{./} + >| foo + EOE +} + : timeout : if $posix @@ -566,8 +788,9 @@ if $posix EOI $* 2>>~%EOE% != 0; - update file{foo} - buildfile:6:3: error: ^sleep terminated: execution timeout expired + update file{bar} -> file{foo} + buildfile:6:3: error: process ^sleep terminated: execution timeout expired + info: command line: sleep 5 info: while updating file{foo} %.+ EOE @@ -591,7 +814,7 @@ if $posix EOI $* 2>>EOE; - update file{foo} + update file{bar} -> file{foo} EOE $* clean 2>- @@ -618,16 +841,18 @@ if $posix EOI $* test config.test.timeout=1 2>>~%EOE% != 0; - cp file{foo} + cp file{bar} -> file{foo} test file{foo} - buildfile:7:3: error: ^sleep terminated: execution timeout expired + buildfile:7:3: error: process ^sleep terminated: execution timeout expired + info: command line: sleep 5 info: while testing file{foo} %.+ EOE $* test config.test.timeout=/1 2>>~%EOE% != 0; test file{foo} - buildfile:7:3: error: ^sleep terminated: execution timeout expired + buildfile:7:3: error: process ^sleep terminated: execution timeout expired + info: command line: sleep 5 info: while testing file{foo} %.+ EOE @@ -654,7 +879,7 @@ if $posix EOI $* test config.test.timeout=3 2>>EOE; - cp file{foo} + cp file{bar} -> file{foo} test file{foo} EOE @@ -662,3 +887,945 @@ if $posix } } } + +# @@ TODO: test $1 when implemented. +# +: rule +: +{ + cat <<EOI >=buildfile; + alias{far}: alias{bar} + alias{bar}: + + alias{~'/f(.+)/'}: alias{~'/b\1/'} + {{ + diag frob $< -> $> + }} + EOI + + $* 2>>EOE + frob alias{bar} -> alias{far} + EOE +} + +: loop +: +{ + : while + : + { + : basics + : + { + echo 'bar' >=bar; + + cat <<EOI >=buildfile; + foo: bar + {{ + p = $path($>) + while test -f $p != 0 + cp $path($<) $p + end + }} + EOI + + $* 2>'cp file{bar} -> file{foo}'; + + cat <<<foo >'bar'; + + $* clean 2>- + } + + : exit + : + { + echo 'bar' >=bar; + + cat <<EOI >=buildfile; + foo: bar + {{ + diag gen ($>) + + p = $path($>) + while test -f $p != 0 + touch $p + exit + cp $path($<) $p + end + }} + EOI + + $* 2>'gen file{foo}'; + + cat <<<foo >:''; + + $* clean 2>- + } + + : error + : + { + echo 'bar' >=bar; + + cat <<EOI >=buildfile; + foo: bar + {{ + diag gen ($>) + + p = $path($>) + while test -f $p != 0 + touch $p + exit 'fed up' + cp $path($<) $p + end + }} + EOI + + $* 2>>~%EOE% != 0; + gen file{foo} + buildfile:8:5: error: fed up + %.{3} + EOE + + $* clean 2>- + } + + : depdb + : + { + : inside + : + { + echo 'bar' >=bar; + + cat <<EOI >=buildfile; + foo: bar + {{ + p = $path($>) + while test -f $p != 0 + depdb hash $p + cp $path($<) $p + end + }} + EOI + + $* 2>>EOE != 0 + buildfile:5:5: error: 'depdb' call inside flow control construct + EOE + } + + : after-commands + : + { + echo 'bar' >=bar; + + cat <<EOI >=buildfile; + foo: bar + {{ + p = $path($>) + while test -f $p != 0 + cp $path($<) $p + end + + depdb hash $p + }} + EOI + + $* 2>>~%EOE% != 0; + buildfile:5:5: error: disallowed command in depdb preamble + info: only variable assignments are allowed in depdb preamble + buildfile:8:3: info: depdb preamble ends here + %.{3} + EOE + + $* clean 2>- + } + + : after-vars + : + { + echo 'bar' >=bar; + + cat <<EOI >=buildfile; + foo: bar + {{ + p = $path($<) + + h = + while test -f $p != 0 + h += $p + end + + depdb hash $p + + cat $p >$path($>) + }} + EOI + + $* 2>'cat file{bar} -> file{foo}'; + $* clean 2>- + } + } + } + + : for + : + { + : form-1 + : + : for x: ... + : + { + : basics + : + { + echo 'bar' >=bar; + echo 'baz' >=baz; + + cat <<EOI >=buildfile; + foo: bar baz + {{ + p = $path($>) + rm -f $p + + for f: $< + cat $path($f) >>$p + end + }} + EOI + + $* 2>'cat file{bar} -> file{foo}'; + + cat <<<foo >>EOO; + bar + baz + EOO + + $* clean 2>- + } + + : pair + : + { + mkdir -p src/build; + echo 'bar' >=src/bar; + echo 'baz' >=src/baz; + + echo 'project =' >=src/build/bootstrap.build; + + cat <<EOI >=src/buildfile; + foo: file{bar}@./ file{baz}@./ + {{ + p = $path($>) + rm -f $p + + for f: $< + cat $path($f) >>$p + end + }} + EOI + + $* src/@out/ 2>>/EOE; + mkdir fsdir{out/} + cat src/file{bar} -> out/file{foo} + EOE + + cat <<<out/foo >>EOO; + bar + baz + EOO + + $* 'clean:' src/@out/ 2>- + } + + : special-var + : + { + echo 'bar' >=bar; + echo 'baz' >=baz; + + cat <<EOI >=buildfile; + foo: bar + {{ + p = $path($>) + rm -f $p + + for ~: $< + cat $path($f) >>$p + end + }} + EOI + + $* 2>>EOE != 0 + buildfile:6:7: error: attempt to set '~' special variable + EOE + } + + : exit + : + { + echo 'bar' >=bar; + echo 'baz' >=baz; + + cat <<EOI >=buildfile; + foo: bar + {{ + p = $path($>) + rm -f $p + + for f: $< + cat $path($f) >>$p + exit + end + }} + EOI + + $* 2>'cat file{bar} -> file{foo}'; + + cat <<<foo >>EOO; + bar + EOO + + $* clean 2>- + } + + : error + : + { + echo 'bar' >=bar; + echo 'baz' >=baz; + + cat <<EOI >=buildfile; + foo: bar + {{ + p = $path($>) + rm -f $p + + for f: $< + cat $path($f) >>$p + exit 'fed up' + end + }} + EOI + + $* 2>>~%EOE% != 0; + cat file{bar} -> file{foo} + buildfile:8:5: error: fed up + %.{3} + EOE + + $* clean 2>- + } + + : depdb + : + { + : inside + : + { + echo 'bar' >=bar; + + cat <<EOI >=buildfile; + foo: bar + {{ + for f: $< + depdb hash $f + end + + p = $path($>) + rm -f $p + + for f: $< + cat $path($f) >>$p + end + }} + EOI + + $* 2>>EOE != 0 + buildfile:4:5: error: 'depdb' call inside flow control construct + EOE + } + + : after-commands + : + { + echo 'bar' >=bar; + + cat <<EOI >=buildfile; + foo: bar + {{ + for f: $< + echo $path($f) >- + end + + depdb hash a + }} + EOI + + $* 2>>~%EOE% != 0; + buildfile:4:5: error: disallowed command in depdb preamble + info: only variable assignments are allowed in depdb preamble + buildfile:7:3: info: depdb preamble ends here + %.{3} + EOE + + $* clean 2>- + } + + : after-vars + : + { + echo 'bar' >=bar; + + cat <<EOI >=buildfile; + foo: bar + {{ + h = + for f: $< + h += $path($f) + end + + depdb hash $h + + p = $path($>) + rm -f $p + + for f: $< + cat $path($f) >>$p + end + }} + EOI + + $* 2>'cat file{bar} -> file{foo}'; + $* clean 2>- + } + } + } + + : form-2 + : + : ... | for x + : + { + : basics + : + { + echo 'bar' >=bar; + echo 'baz' >=baz; + + cat <<EOI >=buildfile; + foo: bar baz + {{ + diag gen ($>) + + p = $path($>) + rm -f $p + + echo $path($<) | for -w f + cat $f >>$p + end + }} + EOI + + $* 2>'gen file{foo}'; + + cat <<<foo >>EOO; + bar + baz + EOO + + $* clean 2>- + } + + : special-var + : + { + echo 'bar' >=bar; + echo 'baz' >=baz; + + cat <<EOI >=buildfile; + foo: bar + {{ + diag gen ($>) + + p = $path($>) + rm -f $p + + echo $path($<) | for ~ + cat $f >>$p + end + }} + EOI + + $* 2>>~%EOE% != 0; + gen file{foo} + buildfile:8:3: error: attempt to set '~' special variable + %.{3} + EOE + + $* clean 2>- + } + + : misuse + : + { + : after-var + { + echo 'bar' >=bar; + echo 'baz' >=baz; + + cat <<EOI >=buildfile; + foo: bar + {{ + diag gen ($>) + + p = $path($>) + rm -f $p + + echo $path($<) | for x: + cat $f >>$p + end + }} + EOI + + $* 2>>~%EOE% != 0; + gen file{foo} + buildfile:8:3: error: for: ':' after variable name + %.+ + EOE + + $* clean 2>- + } + + : after-attrs + { + echo 'bar' >=bar; + echo 'baz' >=baz; + + cat <<EOI >=buildfile; + foo: bar + {{ + diag gen ($>) + + p = $path($>) + rm -f $p + + echo $path($<) | for x [path]: + cat $f >>$p + end + }} + EOI + + $* 2>>~%EOE% != 0; + gen file{foo} + <attributes>:1:7: error: whitespace required after attributes + <attributes>:1:1: info: use the '\[' escape sequence if this is a wildcard pattern + buildfile:8:3: info: while parsing attributes '[path]:' + %.+ + EOE + + $* clean 2>- + } + } + + : exit + : + { + echo 'bar' >=bar; + echo 'baz' >=baz; + + cat <<EOI >=buildfile; + foo: bar + {{ + diag gen ($>) + + p = $path($>) + rm -f $p + + echo $path($<) | for -w f + cat $f >>$p + exit + end + }} + EOI + + $* 2>'gen file{foo}'; + + cat <<<foo >>EOO; + bar + EOO + + $* clean 2>- + } + + : error + : + { + echo 'bar' >=bar; + echo 'baz' >=baz; + + cat <<EOI >=buildfile; + foo: bar + {{ + diag gen ($>) + + p = $path($>) + rm -f $p + + echo $path($<) | for -w f + cat $f >>$p + exit 'fed up' + end + }} + EOI + + $* 2>>~%EOE% != 0; + gen file{foo} + buildfile:10:5: error: fed up + %.{3} + EOE + + $* clean 2>- + } + + : depdb + : + { + : inside + : + { + echo 'bar' >=bar; + + cat <<EOI >=buildfile; + foo: bar + {{ + echo $path($<) | for -w f + depdb hash $f + end + + p = $path($>) + rm -f $p + + echo $path($<) | for -w f + cat $f >>$p + end + }} + EOI + + $* 2>>EOE != 0 + buildfile:4:5: error: 'depdb' call inside flow control construct + EOE + } + + : after-commands + : + { + echo 'bar' >=bar; + + cat <<EOI >=buildfile; + foo: bar + {{ + echo $path($<) | for -w f + echo $f >- + end + + depdb hash $p + }} + EOI + + $* 2>>~%EOE% != 0; + buildfile:4:5: error: disallowed command in depdb preamble + info: only variable assignments are allowed in depdb preamble + buildfile:7:3: info: depdb preamble ends here + %.{3} + EOE + + $* clean 2>- + } + + : after-vars + : + { + echo 'bar' >=bar; + + cat <<EOI >=buildfile; + foo: bar + {{ + h = + echo $path($<) | for -w f + h += $f + end + + depdb hash $h + + diag gen ($>) + + p = $path($>) + rm -f $p + + for f: $< + cat $path($f) >>$p + end + }} + EOI + + $* 2>'gen file{foo}'; + $* clean 2>- + } + } + } + + : form-3 + : + : for x <... + : + { + : basics + : + { + echo 'bar' >=bar; + echo 'baz' >=baz; + + cat <<EOI >=buildfile; + foo: bar baz + {{ + diag gen ($>) + + p = $path($>) + rm -f $p + + for -w f <<"EOF" + $path($<) + EOF + cat $f >>$p + end + + for <<"EOF" -w f + $path($<) + EOF + cat $f >>$p + end + }} + EOI + + $* 2>'gen file{foo}'; + + cat <<<foo >>EOO; + bar + baz + bar + baz + EOO + + $* clean 2>- + } + + : quoting + : + { + echo 'bar' >=bar; + echo 'baz' >=baz; + + cat <<EOI >=buildfile; + foo: bar baz + {{ + n = 'gen' + diag "($n)" ($>) + + p = $path($>) + rm -f $p + + o = -w + for "$o" f <<"EOF" + $path($<) + EOF + cat $f >>$p + end + + o = -n + for "($o)" f <<"EOF" + $path($<) + EOF + echo $f >>$p + end + }} + EOI + + $* 2>'gen file{foo}'; + + cat <<<foo >>~%EOO%; + bar + baz + %.+bar .+baz% + EOO + + $* clean 2>- + } + + : special-var + : + { + echo 'bar' >=bar; + echo 'baz' >=baz; + + cat <<EOI >=buildfile; + foo: bar + {{ + p = $path($>) + rm -f $p + + for ~ <<<$path($<) + cat $f >>$p + end + }} + EOI + + $* 2>>EOE != 0 + buildfile:6:6: error: attempt to set '~' special variable + EOE + } + + : exit + : + { + echo 'bar' >=bar; + echo 'baz' >=baz; + + cat <<EOI >=buildfile; + foo: bar + {{ + p = $path($>) + rm -f $p + + for f <<<$path($<) + cat $f >>$p + exit + end + }} + EOI + + $* 2>'cat file{bar} -> file{foo}'; + + cat <<<foo >>EOO; + bar + EOO + + $* clean 2>- + } + + : error + : + { + echo 'bar' >=bar; + echo 'baz' >=baz; + + cat <<EOI >=buildfile; + foo: bar + {{ + p = $path($>) + rm -f $p + + for f <<<$path($<) + cat $f >>$p + exit 'fed up' + end + }} + EOI + + $* 2>>~%EOE% != 0; + cat file{bar} -> file{foo} + buildfile:8:5: error: fed up + %.{3} + EOE + + $* clean 2>- + } + + : depdb + : + { + : inside + : + { + echo 'bar' >=bar; + + cat <<EOI >=buildfile; + foo: bar + {{ + for -w f <<<$path($<) + depdb hash $f + end + + p = $path($>) + rm -f $p + + echo $path($<) | for -w f + cat $f >>$p + end + }} + EOI + + $* 2>>EOE != 0 + buildfile:4:5: error: 'depdb' call inside flow control construct + EOE + } + + : after-commands + : + { + echo 'bar' >=bar; + + cat <<EOI >=buildfile; + foo: bar + {{ + for -w f <<<$path($<) + echo $f >- + end + + depdb hash a + }} + EOI + + $* 2>>~%EOE% != 0; + buildfile:4:5: error: disallowed command in depdb preamble + info: only variable assignments are allowed in depdb preamble + buildfile:7:3: info: depdb preamble ends here + %.{3} + EOE + + $* clean 2>- + } + + : after-vars + : + { + echo 'bar' >=bar; + + cat <<EOI >=buildfile; + foo: bar + {{ + h = + for -w f <<<$path($<) + h += $f + end + + depdb hash $h + + diag gen ($>) + + p = $path($>) + rm -f $p + + for f: $< + cat $path($f) >>$p + end + }} + EOI + + $* 2>'gen file{foo}'; + $* clean 2>- + } + } + } + } +} diff --git a/tests/recipe/cxx/testscript b/tests/recipe/cxx/testscript index 323e049..323d671 100644 --- a/tests/recipe/cxx/testscript +++ b/tests/recipe/cxx/testscript @@ -81,7 +81,7 @@ if (!$static && $test.target == $build.host) return r; if (verb == 1) - text << "cp " << t; + print_diag ("cp", s, t); else if (verb >= 2) text << "cp " << sp << ' ' << tp; @@ -93,7 +93,7 @@ if (!$static && $test.target == $build.host) $* 2>>~%EOE%; %^(c\+\+|ld).*%+ - cp file{foo} + cp file{bar} -> file{foo} EOE cat <<<foo >'bar'; @@ -141,7 +141,7 @@ if (!$static && $test.target == $build.host) const path& tp (t.path ()); if (verb == 1) - text << "test " << t; + print_diag ("test", t); else if (verb >= 2) text << "cat " << tp; @@ -157,7 +157,7 @@ if (!$static && $test.target == $build.host) $* test 2>>~%EOE%; %^(c\+\+|ld).*%+ - cp file{foo} + cp file{bar} -> file{foo} test file{foo} bar EOE @@ -165,6 +165,46 @@ if (!$static && $test.target == $build.host) $* clean 2>- } + : rule + : + { + cat <<EOI >=buildfile; + alias{far}: alias{bar} + alias{bar}: + + alias{~'/f(.+)/'}: alias{~'/b\1/'} + {{ c++ 1 -- + + #include <iostream> + + -- + + recipe + apply (action a, target& t) const override + { + const auto& mrs (t.data<regex_match_results> (a)); + + return [this, mr = mrs.str (1)] (action a, const target& t) + { + return perform_update (a, t, mr); + }; + } + + target_state + perform_update (action, const target&, const string& mr) const + { + text << pattern->rule_name << ": " << mr; + return target_state::changed; + } + }} + EOI + + $* 2>>~%EOE% + %^(c\+\+|ld).*%+ + <ad hoc pattern rule #1>: ar + EOE + } + # Clean recipe builds if the testscript is enabled (see above for details). # -$* clean 2>- diff --git a/tests/test/config-test/driver.cxx b/tests/test/config-test/driver.cxx index 5902854..7ea10e7 100644 --- a/tests/test/config-test/driver.cxx +++ b/tests/test/config-test/driver.cxx @@ -3,6 +3,9 @@ #include <iostream> +#undef NDEBUG +#include <cassert> + using namespace std; int diff --git a/tests/test/script/builtin/sleep.testscript b/tests/test/script/builtin/sleep.testscript index e1410ac..c044027 100644 --- a/tests/test/script/builtin/sleep.testscript +++ b/tests/test/script/builtin/sleep.testscript @@ -13,7 +13,7 @@ $c <'sleep 1' && $b : failure : $c <'env -t 1 -- sleep 86400' && $b 2>>~%EOE% != 0 - %testscript:.*: error: sleep terminated: execution timeout expired% + %testscript:.*: error: builtin sleep terminated: execution timeout expired% %. EOE diff --git a/tests/test/script/common.testscript b/tests/test/script/common.testscript index 4469d1c..651e056 100644 --- a/tests/test/script/common.testscript +++ b/tests/test/script/common.testscript @@ -31,7 +31,7 @@ end # Note that the buildfile is clever hack that relies on the first target # automatically becoming dir{./}'s prerequisite. # -c = cat >=testscript -b = $0 --no-default-options --serial-stop --quiet --buildfile - test \ +c = [cmdline] cat >=testscript +b = [cmdline] $0 --no-default-options --serial-stop --quiet --buildfile - test \ <"'testscript{testscript}: \$target'" \ &?test/*** diff --git a/tests/test/script/runner/driver.cxx b/tests/test/script/runner/driver.cxx index f081714..b84f167 100644 --- a/tests/test/script/runner/driver.cxx +++ b/tests/test/script/runner/driver.cxx @@ -11,16 +11,19 @@ #include <limits> // numeric_limits #include <string> #include <cstdlib> // abort() -#include <cassert> #include <ostream> // endl, *bit #include <istream> // istream::traits_type::eof() #include <iostream> #include <exception> -#include <libbutl/path.mxx> -#include <libbutl/optional.mxx> -#include <libbutl/fdstream.mxx> -#include <libbutl/filesystem.mxx> +#include <libbutl/path.hxx> +#include <libbutl/path-io.hxx> +#include <libbutl/optional.hxx> +#include <libbutl/fdstream.hxx> +#include <libbutl/filesystem.hxx> + +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; @@ -43,8 +46,8 @@ main (int argc, char* argv[]) // Usage: driver [-i <int>] (-o <string>)* (-e <string>)* (-f <file>)* // (-d <dir>)* (-v <name>)* [(-t (a|m|s|z)) | (-s <int>)] // - // Execute actions specified by -i, -o, -e, -f, -d, -v, and -l options in - // the order as they appear on the command line. After that terminate + // Execute actions specified by -i, -o, -e, -f, -d, -w, -v, and -l options + // in the order as they appear on the command line. After that terminate // abnormally if -t option is provided, otherwise exit normally with the // status specified by -s option (0 by default). // @@ -65,6 +68,9 @@ main (int argc, char* argv[]) // Create a directory with the path specified. Create parent directories // if required. // + // -w + // Print CWD to stdout. + // // -v <name> // If the specified variable is set then print its value to stdout and // the string '<none>' otherwise. @@ -93,10 +99,7 @@ main (int argc, char* argv[]) for (int i (1); i < argc; ++i) { - string o (argv[i++]); - assert (i < argc); - - string v (argv[i]); + string o (argv[i]); auto toi = [] (const string& s) -> int { @@ -116,69 +119,80 @@ main (int argc, char* argv[]) return r; }; - if (o == "-i") + if (o == "-w") { - assert (ifd == 3); // Make sure is not set yet. - - ifd = toi (v); - assert (ifd >= 0 && ifd < 3); + cout << dir_path::current_directory () << endl; + } + else // Handle options other than flags. + { + ++i; + assert (i < argc); + string v (argv[i]); - if (ifd == 0) - cin.ignore (numeric_limits<streamsize>::max ()); - else if (cin.peek () != istream::traits_type::eof ()) + if (o == "-i") { - ostream& o (ifd == 1 ? cout : cerr); - o << cin.rdbuf (); - o.flush (); + assert (ifd == 3); // Make sure is not set yet. + + ifd = toi (v); + assert (ifd >= 0 && ifd < 3); + + if (ifd == 0) + cin.ignore (numeric_limits<streamsize>::max ()); + else if (cin.peek () != istream::traits_type::eof ()) + { + ostream& o (ifd == 1 ? cout : cerr); + o << cin.rdbuf (); + o.flush (); + } } - } - else if (o == "-o") - { - cout << v << endl; - } - else if (o == "-e") - { - cerr << v << endl; - } - else if (o == "-f") - { - ofdstream os (v); - os.close (); - } - else if (o == "-d") - { - try_mkdir_p (dir_path (v)); - } - else if (o == "-v") - { - optional<string> var (getenv (v)); - cout << (var ? *var : "<none>") << endl; - } - else if (o == "-l") - { - size_t t (toi (v)); + else if (o == "-o") + { + cout << v << endl; + } + else if (o == "-e") + { + cerr << v << endl; + } + else if (o == "-f") + { + ofdstream os (v); + os.close (); + } + else if (o == "-d") + { + try_mkdir_p (dir_path (v)); + } + else if (o == "-v") + { + optional<string> var (getenv (v)); + cout << (var ? *var : "<none>") << endl; + } + else if (o == "-l") + { + size_t t (toi (v)); - // MinGW GCC 4.9 doesn't implement this_thread so use Win32 Sleep(). - // + // MinGW GCC 4.9 doesn't implement this_thread so use Win32 Sleep(). + // #ifndef _WIN32 - this_thread::sleep_for (chrono::seconds (t)); + this_thread::sleep_for (chrono::seconds (t)); #else - Sleep (static_cast<DWORD> (t * 1000)); + Sleep (static_cast<DWORD> (t * 1000)); #endif + } + else if (o == "-t") + { + assert (aterm == '\0' && !status); // Make sure exit method is not set. + assert (v.size () == 1 && v.find_first_of ("amsz") != string::npos); + aterm = v[0]; + } + else if (o == "-s") + { + assert (!status && aterm == '\0'); // Make sure exit method is not set. + status = toi (v); + } + else + assert (false); } - else if (o == "-t") - { - assert (aterm == '\0' && !status); // Make sure exit method is not set. - assert (v.size () == 1 && v.find_first_of ("amsz") != string::npos); - aterm = v[0]; - } - else if (o == "-s") - { - assert (!status && aterm == '\0'); // Make sure exit method is not set. - status = toi (v); - } - else - assert (false); } switch (aterm) diff --git a/tests/test/script/runner/env.testscript b/tests/test/script/runner/env.testscript index ef90c3b..512139a 100644 --- a/tests/test/script/runner/env.testscript +++ b/tests/test/script/runner/env.testscript @@ -3,6 +3,40 @@ .include ../common.testscript +: cwd +: +{ + : not-exist + : + $c <'env -c a -- $* -w' && $b 2>>/~%EOE% != 0 + %testscript:1:1: error: specified working directory .+/a/ does not exist% + info: test id: 1 + EOE + + : process + : + $c <<EOI && $b + mkdir a; + env -c a -- $* -w >/~%.+/a% + EOI + + : builtin + : + $c <<EOI && $b + mkdir a; + env -c a -- touch b; + test -f a/b + EOI + + : absolute + : + $c <<EOI && $b + mkdir a; + env -c $~/a -- touch b; + test -f a/b + EOI +} + : variables : { diff --git a/tests/test/script/runner/expr.testscript b/tests/test/script/runner/expr.testscript index 98e495f..95d4bed 100644 --- a/tests/test/script/runner/expr.testscript +++ b/tests/test/script/runner/expr.testscript @@ -20,7 +20,7 @@ true = '$* >| -o' false = '$* -s 1 >| -o' - bf = $b 2>- + bf = [cmdline] $b 2>- : true : diff --git a/tests/test/script/runner/for.testscript b/tests/test/script/runner/for.testscript new file mode 100644 index 0000000..f43fcc2 --- /dev/null +++ b/tests/test/script/runner/for.testscript @@ -0,0 +1,502 @@ +# File : tests/test/script/runner/for.testscript +# license : MIT; see accompanying LICENSE file + +.include ../common.testscript + +: form-1 +: +: for x: ... +: +{ + : basics + : + $c <<EOI && $b >>EOO + for x: a b + echo "$x" >| + end + EOI + a + b + EOO + + : test-options + : + $c <<EOI && $b >>~%EOO% + for test.options: -a -b + echo $* >| + end + EOI + %.+ -a% + %.+ -b% + EOO + + : special-var + : + $c <<EOI && $b 2>>EOE != 0 + for ~: -a -b + echo $~ >| + end + EOI + testscript:1:5: error: attempt to set '~' variable directly + EOE + + : exit + : + $c <<EOI && $b >>EOO + for x: a b + echo "$x" >| + exit + end + EOI + a + EOO + + : error + : + $c <<EOI && $b >>EOO 2>>EOE != 0 + for x: a b + echo "$x" >| + exit 'fed up' + end + EOI + a + EOO + testscript:3:3: error: fed up + info: test id: 1 + EOE +} + +: form-2 +: +: ... | for x +: +{ + : whitespace-split + : + $c <<EOI && $b >>EOO + echo " a b " | for -w x + echo "'$x'" >| + end + EOI + 'a' + 'b' + EOO + + : newline-split + : + $c <<EOI && $b >>EOO + cat <<EOF | for -n x + + + a + + + b + + EOF + echo "'$x'" >| + end + EOI + '' + '' + 'a' + '' + '' + 'b' + '' + EOO + + : typed + : + $c <<EOI && $b >>/EOO + echo "a b" | for -w x [dir_path] + echo $x >| + end + EOI + a/ + b/ + EOO + + : nested + : + $c <<EOI && $b >>EOO + echo "a b" | for -w x + echo "x y" | for -w y + echo "'$x $y'" >| + end + end + EOI + 'a x' + 'a y' + 'b x' + 'b y' + EOO + + : nested-diag + : + $c <<EOI && $b 2>>/~%EOE% != 0 + echo "a b" | for -w x + echo "x y" | for -w y + echo "'$x $y'" >"'a x'" + end + end + EOI + testscript:3:5: error: echo stdout doesn't match expected + info: stdout: test/1/stdout-i1-i2-n3 + info: expected stdout: test/1/stdout-i1-i2-n3.orig + info: stdout diff: test/1/stdout-i1-i2-n3.diff + %.+ + EOE + + : nested-diag-test-id + : + $c <<EOI && $b 2>>EOE != 0 + echo "a b" | for -w x + echo "x y" | for -w y + test -f $x$y + end + end + EOI + testscript:3:5: error: builtin test exited with code 1 + info: test id: 1 + EOE + + : var-value + : + $c <<EOI && $b >>EOO + x = 'x'; + echo "a b" | for -w x + end; + echo $x >| + EOI + b + EOO + + : both-sep-options + : + $c <<EOI && $b 2>>/~%EOE% != 0 + echo "a b" | for -n -w x + echo $x >| + end + EOI + testscript:1:1: error: for: both -n|--newline and -w|--whitespace specified + %.+ + EOE + + : invalid-option + : + $c <<EOI && $b 2>>/~%EOE% != 0 + echo "a b" | for -a x + echo $x >| + end + EOI + testscript:1:1: error: for: unknown option '-a' + %.+ + EOE + + : no-variable + : + $c <<EOI && $b 2>>/~%EOE% != 0 + echo "a b" | for -w + echo $x >| + end + EOI + testscript:1:1: error: for: missing variable name + %.+ + EOE + + : special-var + : + $c <<EOI && $b 2>>EOE != 0 + echo "a b" | for -w ~ + echo $* >| + end + EOI + testscript:1:1: error: attempt to set '~' variable directly + info: test id: 1 + EOE + + : unsep-attrs + : + $c <<EOI && $b 2>>EOE != 0 + echo "a b" | for -w x[string] + echo $x >| + end + EOI + testscript:1:1: error: for: expected variable name instead of x[string] + info: test id: 1 + EOE + + : misuse + : + { + : after-var + : + $c <<EOI && $b 2>>EOE != 0 + echo "a b" | for v: + echo $v >| + end + EOI + testscript:1:19: error: expected newline instead of ':' + EOE + + : after-attrs + : + $c <<EOI && $b 2>>EOE != 0 + echo "a b" | for v [string]: + echo $v >| + end + EOI + testscript:1:28: error: expected newline instead of ':' + EOE + } + + : exit + : + $c <<EOI && $b >>EOO + echo "a b" | for x + echo "$x" >| + exit + end + EOI + a + EOO + + : error + : + $c <<EOI && $b >>EOO 2>>EOE != 0 + echo "a b" | for x + echo "$x" >| + exit 'fed up' + end + EOI + a + EOO + testscript:3:3: error: fed up + info: test id: 1 + EOE +} + +: form-3 +: +: for x <... +: +{ + : whitespace-split + : + $c <<EOI && $b >>EOO + for -w x <" a b " + echo "'$x'" >| + end + EOI + 'a' + 'b' + EOO + + : quoted-opt + : + $c <<EOI && $b >>EOO + o = -n + for "$o" x <<EOF + a + b + EOF + echo "'$x'" >| + end; + for "($o)" x <<EOF + c + d + EOF + echo "'$x'" >| + end + EOI + 'a' + 'b' + 'c' + 'd' + EOO + + : newline-split + : + $c <<EOI && $b >>EOO + for -n x <<EOF + + + a + + + b + + EOF + echo "'$x'" >| + end + EOI + '' + '' + 'a' + '' + '' + 'b' + '' + EOO + + : string-before-var + : + $c <<EOI && $b >>EOO + for <"a b" -w x + echo "'$x'" >| + end + EOI + 'a' + 'b' + EOO + + : here-doc-before-var + : + $c <<EOI && $b >>EOO + for <<EOF -n x + a + b + EOF + echo "'$x'" >| + end + EOI + 'a' + 'b' + EOO + + : typed + : + $c <<EOI && $b >>/EOO + for -w x [dir_path] <"a b" + echo $x >| + end + EOI + a/ + b/ + EOO + + : typed-no-ops + : + $c <<EOI && $b >>/EOO + for x [dir_path] <"a b" + echo $x >| + end + EOI + a/ + b/ + EOO + + : nested + : + $c <<EOI && $b >>EOO + for -w x <"a b" + for -w y <"x y" + echo "'$x $y'" >| + end + end + EOI + 'a x' + 'a y' + 'b x' + 'b y' + EOO + + : nested-diag + : + $c <<EOI && $b 2>>/~%EOE% != 0 + for -w x <"a b" + for -w y <"x y" + echo "'$x $y'" >"'a x'" + end + end + EOI + testscript:3:5: error: echo stdout doesn't match expected + info: stdout: test/1/stdout-i1-i2-n3 + info: expected stdout: test/1/stdout-i1-i2-n3.orig + info: stdout diff: test/1/stdout-i1-i2-n3.diff + %.+ + EOE + + : nested-diag-test-id + : + $c <<EOI && $b 2>>EOE != 0 + for -w x <"a b" + for -w y <"x y" + test -f $x$y + end + end + EOI + testscript:3:5: error: builtin test exited with code 1 + info: test id: 1 + EOE + + : var-value + : + $c <<EOI && $b >>EOO + x = 'x'; + for -w x <"a b" + end; + echo $x >| + EOI + b + EOO + + : invalid-option + : + $c <<EOI && $b 2>>/~%EOE% != 0 + for -a x <"a b" + echo $x >| + end + EOI + testscript:1:1: error: for: unknown option '-a' + %. + EOE + + + : no-variable + : + $c <<EOI && $b 2>>/~%EOE% != 0 + for -w <"a b" + echo $x >| + end + EOI + testscript:1:1: error: for: missing variable name + %. + EOE + + : special-var + : + $c <<EOI && $b 2>>EOE != 0 + for ~ <"a b" + echo $~ >| + end + EOI + testscript:1:5: error: attempt to set '~' variable directly + EOE + + : exit + : + $c <<EOI && $b >>EOO + for x <"a b" + echo "$x" >| + exit + end + EOI + a + EOO + + : error + : + $c <<EOI && $b >>EOO 2>>EOE != 0 + for x <"a b" + echo "$x" >| + exit 'fed up' + end + EOI + a + EOO + testscript:3:3: error: fed up + info: test id: 1 + EOE +} diff --git a/tests/test/script/runner/pipe.testscript b/tests/test/script/runner/pipe.testscript index 205fd55..cdd30a6 100644 --- a/tests/test/script/runner/pipe.testscript +++ b/tests/test/script/runner/pipe.testscript @@ -6,7 +6,6 @@ $c <'cat <foo | $* -i 1 >foo' && $b : builtin-to-process $c <'$* -o foo | cat >foo' && $b : process-to-builtin - : failure : : Note that while both commands for the pipe are faulty the diagnostics for @@ -15,19 +14,28 @@ $c <'$* -o foo | cat >foo' && $b : process-to-builtin { : exit-code : - $c <'$* -o foo -s 1 | $* -i 1 >foo -s 2' && $b 2>>/~%EOE% != 0 - %testscript:1:1: error: .+ exited with code 2% - info: stdout: test/1/stdout-2 + : Also verify that the command line is printed. + : + $c <'$* -o foo -s 1 | $* -i 1 -s 2 >foo' && $b --verbose 1 2>>/~%EOE% != 0 + %. + %testscript:1:1: error: process .+ exited with code 1% + % info: command line: .+driver.* -o foo -s 1% + info: test id: 1 + %. + %testscript:1:1: error: process .+ exited with code 2% + % info: command line: .+driver.* -i 1 -s 2% + info: stdout: test/1/stdout-c2 info: test id: 1 + %.{2} EOE : stderr : $c <'$* -o foo -e foo 2>bar | $* -i 2 2>baz' && $b 2>>/~%EOE% != 0 %testscript:1:1: error: .+ stderr doesn't match expected% - info: stderr: test/1/stderr-2 - info: expected stderr: test/1/stderr-2.orig - info: stderr diff: test/1/stderr-2.diff + info: stderr: test/1/stderr-c2 + info: expected stderr: test/1/stderr-c2.orig + info: stderr diff: test/1/stderr-c2.diff %.{3} -baz +foo diff --git a/tests/test/script/runner/redirect.testscript b/tests/test/script/runner/redirect.testscript index 0fe3aa3..209c4ce 100644 --- a/tests/test/script/runner/redirect.testscript +++ b/tests/test/script/runner/redirect.testscript @@ -654,9 +654,9 @@ psr = ($cxx.target.class != 'windows' ? '/' : '\\') # Path separator in regex. $* -o bar >?out EOI %testscript:2: error: ../../../../../driver(.exe)? stdout doesn't match expected% - info: stdout: test/1/stdout-2 + info: stdout: test/1/stdout-n2 info: expected stdout: test/1/out - info: stdout diff: test/1/stdout-2.diff + info: stdout diff: test/1/stdout-n2.diff %--- \.*% %\+\+\+ \.*% %@@ \.*% diff --git a/tests/test/script/runner/set.testscript b/tests/test/script/runner/set.testscript index b2944a3..1800a7d 100644 --- a/tests/test/script/runner/set.testscript +++ b/tests/test/script/runner/set.testscript @@ -76,7 +76,7 @@ : empty-attrs : - $c <"set '' baz" && $b 2>>EOE != 0 + $c <"set baz ''" && $b 2>>EOE != 0 testscript:1:1: error: set: empty variable attributes info: test id: 1 EOE @@ -300,7 +300,7 @@ $c <<EOI && $b 2>>~%EOE% != 0 $* -o 'foo' -l 10 | env -t 1 -- set bar EOI - %testscript:.*: error: set terminated: execution timeout expired% + %testscript:.*: error: .+driver.* terminated: execution timeout expired% %. EOE @@ -326,23 +326,218 @@ echo "$s" >=f; $* -o 'foo' -l 10 | cat f - | env -t 2 -- set bar EOI - %testscript:.*: error: set terminated: execution timeout expired% + %testscript:.*: error: process .+driver.* terminated: execution timeout expired% + %. + %testscript:.*: error: builtin cat terminated: execution timeout expired% %. EOE : success : - : Note that the cat builtin ends up with the 'broken pipe' diagnostics or - : similar. - : $c <<EOI && $b echo "$s" >=f; timeout --success 2; - $* -o 'foo' -l 10 | cat f - 2>>~%EOE% | set bar - %cat: .+% - EOE + + # Suppress cat's 'broken pipe' diagnostics. + # + $* -o 'foo' -l 10 | cat f - 2>- | set bar EOI } + + : split + : + : Test various splitting modes as above, but now reading the stream in the + : non-blocking mode. + : + { + : whitespace-separated-list + : + { + : non-exact + : + { + : non-empty + : + $c <<EOI && $b + timeout 10; + set -w baz <' foo bar '; + echo $regex.apply($baz, '^(.*)$', '"\1"') >'"foo" "bar"' + EOI + + : empty + : + $c <<EOI && $b + timeout 10; + set -w baz <:''; + echo $regex.apply($baz, '^(.*)$', '"\1"') >'' + EOI + + : spaces + : + $c <<EOI && $b + timeout 10; + set -w baz <' '; + echo $regex.apply($baz, '^(.*)$', '"\1"') >'' + EOI + } + + : exact + : + { + : trailing-ws + : + $c <<EOI && $b + timeout 10; + set --exact --whitespace baz <' foo bar '; + echo $regex.apply($baz, '^(.*)$', '"\1"') >'"foo" "bar" ""' + EOI + + : no-trailing-ws + : + : Note that we need to strip the default trailing newline as well with the + : ':' modifier. + : + $c <<EOI && $b + timeout 10; + set -e -w baz <:' foo bar'; + echo $regex.apply($baz, '^(.*)$', '"\1"') >'"foo" "bar"' + EOI + + : empty + : + $c <<EOI && $b + timeout 10; + set -e -w baz <:''; + echo $regex.apply($baz, '^(.*)$', '"\1"') >'' + EOI + + : spaces + : + $c <<EOI && $b + timeout 10; + set -e -w baz <' '; + echo $regex.apply($baz, '^(.*)$', '"\1"') >'""' + EOI + } + } + + : newline-separated-list + : + { + : non-exact + : + $c <<EOI && $b + timeout 10; + set -n baz <<EOF; + + foo + + bar + + EOF + echo $regex.apply($baz, '^(.*)$', '"\1"') >'"" "foo" "" "bar" ""' + EOI + + : exact + : + { + : trailing-newline + : + $c <<EOI && $b + timeout 10; + set --exact --newline baz <<EOF; + + foo + + bar + + EOF + echo $regex.apply($baz, '^(.*)$', '"\1"') >'"" "foo" "" "bar" "" ""' + EOI + + : no-trailing-newline + : + $c <<EOI && $b + timeout 10; + set --exact --newline baz <<:EOF; + + foo + + bar + EOF + echo $regex.apply($baz, '^(.*)$', '"\1"') >'"" "foo" "" "bar"' + EOI + } + } + + : string + : + { + : non-exact + : + $c <<EOI && $b + timeout 10; + set baz <<EOF; + + foo + + bar + + EOF + echo ($baz[0]) >>EOO + + foo + + bar + + EOO + EOI + + : exact + : + : Note that echo adds the trailing newline, so EOF and EOO here-documents + : differ by this newline. + : + { + : trailing-newline + : + $c <<EOI && $b + timeout 10; + set -e baz <<EOF; + + foo + + bar + EOF + echo ($baz[0]) >>EOO + + foo + + bar + + EOO + EOI + + : no-trailing-newline + : + $c <<EOI && $b + timeout 10; + set -e baz <<:EOF; + + foo + + bar + EOF + echo ($baz[0]) >>EOO + + foo + + bar + EOO + EOI + } + } + } } : attributes @@ -351,14 +546,14 @@ : dir_path : $c <<EOI && $b - set [dir_path] bar <'foo'; + set bar [dir_path] <'foo'; echo $bar >/'foo/' EOI : null : $c <<EOI && $b - set [null] foo <-; + set foo [null] <-; echo $foo >'' EOI @@ -376,7 +571,7 @@ : empty-brackets : $c <<EOI && $b 2>>EOE != 0 - set -w '[]' baz <'foo bar'; + set -w baz '[]' <'foo bar'; echo "$baz" EOI testscript:2:8: error: concatenating variable expansion contains multiple values @@ -385,7 +580,7 @@ : no-left-bracket : $c <<EOI && $b 2>>EOE != 0 - set -w x baz + set -w baz x EOI <attributes>:1:1: error: expected '[' instead of 'x' testscript:1:1: info: while parsing attributes 'x' @@ -395,7 +590,7 @@ : unknown : $c <<EOI && $b 2>>EOE != 0 - set -w [x] baz + set -w baz [x] EOI <attributes>:1:1: error: unknown value attribute x testscript:1:1: info: while parsing attributes '[x]' @@ -405,7 +600,7 @@ : junk : $c <<EOI && $b 2>>EOE != 0 - set -w '[string] x' baz + set -w baz '[string] x' EOI <attributes>:1:10: error: trailing junk after ']' testscript:1:1: info: while parsing attributes '[string] x' diff --git a/tests/test/script/runner/status.testscript b/tests/test/script/runner/status.testscript index e4586d9..461fd5c 100644 --- a/tests/test/script/runner/status.testscript +++ b/tests/test/script/runner/status.testscript @@ -15,7 +15,7 @@ b += --no-column : false : $c <'$* -s 1 == 0' && $b 2>>/~%EOE%d != 0 - %testscript:1: error: ../../../../driver(.exe)? exit code 1 != 0% + %testscript:1: error: process ../../../../driver(.exe)? exit code 1 != 0% info: test id: 1 EOE } @@ -30,7 +30,7 @@ b += --no-column : false : $c <'$* -s 1 != 1' && $b 2>>/~%EOE% != 0 - %testscript:1: error: ../../../../driver(.exe)? exit code 1 == 1% + %testscript:1: error: process ../../../../driver(.exe)? exit code 1 == 1% info: test id: 1 EOE } @@ -38,7 +38,7 @@ b += --no-column : error : $c <'$* -s 1 -e "Error"' && $b 2>>/~%EOE% != 0 -%testscript:1: error: ../../../driver(.exe)? exited with code 1% +%testscript:1: error: process ../../../driver(.exe)? exited with code 1% info: stderr: test/1/stderr Error info: test id: 1 @@ -47,7 +47,7 @@ EOE : error-check : $c <'$* -s 1 -e "Error" == 0' && $b 2>>/~%EOE% != 0 -%testscript:1: error: ../../../driver(.exe)? exit code 1 != 0% +%testscript:1: error: process ../../../driver(.exe)? exit code 1 != 0% info: stderr: test/1/stderr Error info: test id: 1 diff --git a/tests/test/script/runner/timeout.testscript b/tests/test/script/runner/timeout.testscript index 5f87d39..f9b6ec7 100644 --- a/tests/test/script/runner/timeout.testscript +++ b/tests/test/script/runner/timeout.testscript @@ -424,7 +424,9 @@ $c <<EOI && $b 2>>~%EOE% != 0 env -t 1 -- $* -l 86400 -o 'foo' | touch $~/foo/bar EOI - %testscript:.*: error: touch exited with code 1% + %testscript:.*: error: process .+driver.* terminated: execution timeout expired% + %. + %testscript:.*: error: builtin touch exited with code 1% %.+ EOE } @@ -435,42 +437,54 @@ : prog-tm-prog : $c <'$* -l 10 | env -t 1 -- $* -i 0' && $b 2>>~%EOE% != 0 - %testscript:.*: error: .+driver.* terminated: execution timeout expired% + %testscript:.*: error: process .+driver.* terminated: execution timeout expired% + %. + %testscript:.*: error: process .+driver.* terminated: execution timeout expired% %. EOE : tm-prog-prog : $c <'env -t 1 -- $* -l 10 | $* -i 0' && $b 2>>~%EOE% != 0 - %testscript:.*: error: .+driver.* terminated: execution timeout expired% + %testscript:.*: error: process .+driver.* terminated: execution timeout expired% + %. + %testscript:.*: error: process .+driver.* terminated: execution timeout expired% %. EOE : tm-cat-prog : - $c <'env -t 1 -- cat <"test" | $* -l 10' && $b 2>>~%EOE% != 0 - %testscript:.*: error: cat terminated: execution timeout expired% + $c <'env -t 3 -- cat <"test" | $* -l 10' && $b 2>>~%EOE% != 0 + %testscript:.*: error: builtin cat terminated: execution timeout expired% + %. + %testscript:.*: error: process .+driver.* terminated: execution timeout expired% %. EOE : cat-tm-prog : $c <'cat <"test" | env -t 1 -- $* -l 10' && $b 2>>~%EOE% != 0 - %testscript:.*: error: .+driver.* terminated: execution timeout expired% + %testscript:.*: error: builtin cat terminated: execution timeout expired% + %. + %testscript:.*: error: process .+driver.* terminated: execution timeout expired% %. EOE : tm-prog-cat : $c <'env -t 1 -- $* -l 10 | cat >-' && $b 2>>~%EOE% != 0 - %testscript:.*: error: .+driver.* terminated: execution timeout expired% + %testscript:.*: error: process .+driver.* terminated: execution timeout expired% + %. + %testscript:.*: error: builtin cat terminated: execution timeout expired% %. EOE : tm-echo-prog : - $c <'env -t 1 -- echo "test" | $* -l 10' && $b 2>>~%EOE% != 0 - %testscript:.*: error: echo terminated: execution timeout expired% + $c <'env -t 3 -- echo "test" | $* -l 10' && $b 2>>~%EOE% != 0 + %testscript:.*: error: builtin echo terminated: execution timeout expired% + %. + %testscript:.*: error: process .+driver.* terminated: execution timeout expired% %. EOE diff --git a/tests/test/script/runner/while.testscript b/tests/test/script/runner/while.testscript new file mode 100644 index 0000000..1c58827 --- /dev/null +++ b/tests/test/script/runner/while.testscript @@ -0,0 +1,16 @@ +# file : tests/test/script/runner/while.testscript +# license : MIT; see accompanying LICENSE file + +.include ../common.testscript + +: basics +: +$c <<EOI && $b >>EOO + while ($v != "aa") + echo "$v" >| + v = "$(v)a" + end + EOI + + a + EOO diff --git a/tests/test/simple/generated/driver.cxx b/tests/test/simple/generated/driver.cxx index 18fd0ae..ca6dfcb 100644 --- a/tests/test/simple/generated/driver.cxx +++ b/tests/test/simple/generated/driver.cxx @@ -12,6 +12,9 @@ #include <fstream> #include <iostream> +#undef NDEBUG +#include <cassert> + using namespace std; // If the -s option is specified, then also sleep for 5 seconds. @@ -46,13 +49,23 @@ main (int argc, char* argv[]) } else { - ifstream ifs (argv[i]); + istream* is; + ifstream ifs; + + if (argv[i] != string ("-")) + { + ifs.open (argv[i]); - if (!ifs.is_open ()) - cerr << "unable to open " << argv[1] << endl; + if (!ifs.is_open ()) + cerr << "unable to open " << argv[1] << endl; + + is = &ifs; + } + else + is = &cin; string s; - r = getline (ifs, s) && s == "1.2.3" ? 0 : 1; + r = getline (*is, s) && s == "1.2.3" ? 0 : 1; } return r; diff --git a/tests/test/simple/generated/testscript b/tests/test/simple/generated/testscript index 9ce40ba..49ddbbd 100644 --- a/tests/test/simple/generated/testscript +++ b/tests/test/simple/generated/testscript @@ -43,6 +43,123 @@ driver = $src_root/../exe{driver} file{output}: in{output} $src_root/manifest #@@ in module EOI +: output-mismatch +: +{ + # Get rid of --serial-stop --quiet. + # + test.options = $regex.apply($test.options, '^(--serial-stop|--quiet)$', '') + + : verbose-0 + : + { + echo '1.2.3' >=input; + echo '3.4.5' >=output; + $* -q <<EOI 2>>/~%EOE% != 0 + driver = $src_root/../exe{driver} + ./: test = $driver + ./: $driver + ./: test.arguments = '-' + ./: file{input}: test.stdin = true + ./: file{output}: test.stdout = true + EOI + %.+ + -3.4.5 + error: test dir{./} failed + error: process diff exited with code 1 + EOE + } + + : verbose-1 + : + { + echo '1.2.3' >=input; + echo '3.4.5' >=output; + $* <<EOI 2>>/~%EOE% != 0 + driver = $src_root/../exe{driver} + ./: test = $driver + ./: $driver + ./: test.arguments = '-' + ./: file{input}: test.stdin = true + ./: file{output}: test.stdout = true + EOI + test dir{./} + %.+ + -3.4.5 + error: test dir{./} failed + error: process diff exited with code 1 + % info: test command line: cat .+/input \| .+/driver.* - \| diff -u .+% + info: while testing dir{./} + info: failed to test dir{./} + EOE + } + + : verbose-2 + : + { + echo '1.2.3' >=input; + echo '3.4.5' >=output; + $* --verbose 2 <<EOI 2>>/~%EOE% != 0 + driver = $src_root/../exe{driver} + ./: test = $driver + ./: $driver + ./: test.arguments = '-' + ./: file{input}: test.stdin = true + ./: file{output}: test.stdout = true + EOI + %cat .+/input \| .+/driver.* - \| diff -u .+% + %.+ + -3.4.5 + error: test dir{./} failed + error: process diff exited with code 1 + info: while testing dir{./} + info: failed to test dir{./} + EOE + } + + : verbose-3 + : + { + echo '1.2.3' >=input; + echo '3.4.5' >=output; + $* --verbose 3 <<EOI 2>>/~%EOE% != 0 + driver = $src_root/../exe{driver} + ./: test = $driver + ./: $driver + ./: test.arguments = '-' + ./: file{input}: test.stdin = true + ./: file{output}: test.stdout = true + EOI + %cat .+/input \| .+/driver.* - \| diff -u .+% + %.+ + -3.4.5 + %error: test .+dir\{.+\} failed% + error: process diff exited with code 1 + % info: while testing .+dir\{.+\}% + %info: failed to test .+dir\{.+\}% + EOE + } + + : input-not-found + : + { + echo '1.2.3' >=input; + echo '3.4.5' >=output; + $* -q <<EOI 2>>/~%EOE% != 0 + driver = $src_root/../exe{driver} + ./: test = $driver + ./: $driver + ./: test.arguments = 'foo' + ./: file{input}: test.stdin = true + ./: file{output}: test.stdout = true + EOI + unable to open foo + error: test dir{./} failed + % error: process .+/driver.* exited with code 1% + EOE + } +} + : timeout : { @@ -59,25 +176,30 @@ EOI ./: $driver EOI error: test dir{./} failed - % error: .+ -s terminated: execution timeout expired% - % info: test command line: .+% + % error: process .+driver.* terminated: execution timeout expired% EOE - : output + : stdin-stdout : + ln -s $src_base/input.in ./; ln -s $src_base/output.in ./; - $* config.test.timeout=1 &output &output.d <<EOI 2>>/~%EOE% != 0 + $* config.test.timeout=1 --verbose 1 &input &input.d &output &output.d <<EOI 2>>/~%EOE% != 0 driver = $src_root/../exe{driver} ./: test = $driver ./: test.options = -s ./: $driver + ./: file{input}: test.stdin = true ./: file{output}: test.stdout = true + file{input}: in{input} $src_root/manifest #@@ in module file{output}: in{output} $src_root/manifest #@@ in module EOI + %version in\{.+\} -> .+%{2} + test dir{./} error: test dir{./} failed - % error: diff .+ terminated: execution timeout expired% - % error: .+ -s terminated: execution timeout expired% - % info: test command line: .+% + % error: process .+driver.* terminated: execution timeout expired% + % info: test command line: cat .+/input \| .+driver.* -s \| diff -u .+% + info: while testing dir{./} + info: failed to test dir{./} EOE } @@ -94,8 +216,7 @@ EOI ./: $driver EOI error: test dir{./} failed - % error: .+ -s terminated: execution timeout expired% - % info: test command line: .+% + % error: process .+driver.* terminated: execution timeout expired% EOE } } diff --git a/tests/type/json/buildfile b/tests/type/json/buildfile new file mode 100644 index 0000000..5bc6bf2 --- /dev/null +++ b/tests/type/json/buildfile @@ -0,0 +1,4 @@ +# file : tests/type/json/buildfile +# license : MIT; see accompanying LICENSE file + +./: testscript $b diff --git a/tests/type/json/testscript b/tests/type/json/testscript new file mode 100644 index 0000000..36287b7 --- /dev/null +++ b/tests/type/json/testscript @@ -0,0 +1,504 @@ +# file : tests/type/json/testscript +# license : MIT; see accompanying LICENSE file + +# See also tests in function/json/. + +.include ../../common.testscript + +: basics +: +{ + : empty-null + : + $* <<EOI >>EOO + print ([json, null] ) + print ([json] null) + print ([json] ) + print ([json] "") + print ([json_array] ) + print ([json_object] ) + print ([json] one@null) + print ([json] one@) # @@ Would be more consistent if were null (type hints?) + print ([json] one@"") + EOI + [null] + + + "" + [] + {} + {"one":null} + {"one":""} + {"one":""} + EOO + + : reverse + : + $* <<EOI >>EOO + print ([json] null) + print ([json] true) + print ([json] 123) + print ([json] -123) + print ([json] 0xdecaf) + print ([json] abc) # @@ Ideally we would like this to be reversed unquoted. + print ([json] '"abc"') # @@ Ditto. + print (([json] abc)[0]) # @@ Workaround. + print ([json] dir/{file1 file2}) + print ([json] ' ["dir/file1", "dir/file2"] ') + print ([json] zero@null one@1 two@abc three@([json] x@123 y@-123) four@([json] null true)) + print ([json] '{"zero":null,"one":1,"two":"abc","three":{"x":123,"y":-123},"four":[null,true]}') + EOI + + true + 123 + -123 + 0xdecaf + "abc" + "abc" + abc + ["dir/file1","dir/file2"] + ["dir/file1","dir/file2"] + {"zero":null,"one":1,"two":"abc","three":{"x":123,"y":-123},"four":[null,true]} + {"zero":null,"one":1,"two":"abc","three":{"x":123,"y":-123},"four":[null,true]} + EOO + + + : hex + : + $* <<EOI >>EOO + print ([json] 0xffffFFFF) + + # These should be in the hexadecimal notation once we switch to JSON5. + # + print ([json] 0x0 0x01 0xff 0xFFFF) + print ([json] ff@0xff FFFF@0xFFFF) + + # @@ This should start working once we switch to type hints in subscript. + # + #j = [json] ff@0xff + #print $value_type($j[ff], true) + print 'hexadecimal number' + EOI + 0xffffffff + [0,1,255,65535] + {"ff":255,"FFFF":65535} + hexadecimal number + EOO + + : diagnostics-reverse-invalid + : + $* <<EOI 2>>EOE != 0 + o = [json] '{"one":1, "two":}' + EOI + error: invalid json value in variable o: invalid json input: unexpected byte '}' in value + <stdin>:1:5: info: variable o value is assigned here + EOE + + : diagnostics-duplicate-member + : + $* <<EOI 2>>EOE != 0 + o = [json] one@1 one@2 + EOI + error: invalid json value in variable o: duplicate json object member 'one' + <stdin>:1:5: info: variable o value is assigned here + EOE +} + +: compare +: +{ + : type + : + $* <<EOI >>EOO + print (([json] null) < ([json] true)) + print (([json] true) < ([json] 0)) + print (([json] 123) < ([json] '"0"')) + print (([json] abc) < ([json] xxx yyy)) + print (([json] xxx yyy) < ([json] xxx@null yyy@null)) + EOI + true + true + true + true + true + EOO + + : simple + : + $* <<EOI >>EOO + print (([json] false) == ([json] false)) + print (([json] false) < ([json] true)) + + print (([json] 123) == ([json] 123)) + print (([json] -123) == ([json] -123)) + print (([json] 0xff) == ([json] 255)) + print (([json] 0) == ([json] -0)) + print (([json] -1) < ([json] 0)) + print (([json] 123) < ([json] 234)) + print (([json] -234) < ([json] -123)) + + print (([json] abc) == ([json] abc)) + print (([json] abc) < ([json] abz)) + print (([json] abc) < ([json] abcd)) + EOI + true + true + true + true + true + true + true + true + true + true + true + true + EOO + + : array + : + $* <<EOI >>EOO + print (([json] 1 2 3) == ([json] 1 2 3)) + print (([json] 1 2 3) < ([json] 1 2 4)) + print (([json] 1 2 3) < ([json] 1 2 3 4)) + EOI + true + true + true + EOO + + : object + : + $* <<EOI >>EOO + print (([json] one@1 two@2 three@3) == ([json] three@3 one@1 two@2)) + print (([json] one@1 two@2 three@3) < ([json] three@3 one@1 two@4)) + print (([json] one@1 three@3) < ([json] three@3 one@1 two@2)) + EOI + true + true + true + EOO +} + +: append-prepend +: +{ + : array + : + $* <<EOI >'[0,1,2,3,4,5,6,7,8]' + a = [json] 2 3 + a += 4 + a += 5 6 + a += [json] 7 8 + a =+ [json] 0 1 + print $a + EOI + + : array-type + : + $* <<EOI >'[1,2,3,4,5]' + [json_array] a = + a += 1 + a += 2 3 + a += [json_array] 4 5 # @@ Should be possible to use json. + print $a + EOI + + : object + : + $* <<EOI >'{"zero":0,"one":6,"two":8,"three":3,"four":4,"five":5,"seven":7}' + o = [json] one@1 two@2 three@3 + o += four@4 + o += five@5 one@6 + o += [json] seven@7 two@8 + o =+ [json] zero@0 three@9 + print $o + EOI + + : object-type + : + $* <<EOI >'{"one":1,"two":2,"three":3,"four":4,"five":5}' + [json_object] o = + o += one@1 + o += two@2 three@3 + o += [json_object] four@4 five@5 # @@ Should be possible to use json. + print $o + EOI + + : boolean + : + $* <<EOI >>EOO + b = [json] false + b += [json] true + print $b + EOI + true + EOO + + : number + : + $* <<EOI >>EOO + n = [json] -2 + print $value_type($n, true) $n + n += 1 + print $value_type($n, true) $n + n += 1 + print $value_type($n, true) $n + n += 1 + print $value_type($n, true) $n + n += [json] -1 + print $value_type($n, true) $n + n += [json] -1 + print $value_type($n, true) $n + EOI + signed number -2 + signed number -1 + unsigned number 0 + unsigned number 1 + unsigned number 0 + signed number -1 + EOO + + : string + : + $* <<EOI >>EOO + s = [json] yyy + s += [json] zzz + s =+ [json] xxx + print $s + EOI + "xxxyyyzzz" + EOO + + : invalid + : + $* <<EOI 2>>EOE != 0 + a = [json] 1 2 3 + s = [json] str + s += $a + print $s + EOI + error: invalid json value in variable s: unable to append array to string + <stdin>:3:6: info: variable s value is assigned here + EOE +} + +: subscript +: +{ + : null + : + $* <<EOI >>EOO + j = [json] null + print ($j[0]) + print ($j[one]) + EOI + [null] + [null] + EOO + + : array + : + $* <<EOI >>EOO + j = [json] 1 2 3 null + print ($j[1]) + print ($j[3]) + print ($j[4]) + EOI + 2 + [null] + [null] + EOO + + : object-name + : + $* <<EOI >>EOO + j = [json] one@1 two@2 three@3 four@null + print ($j[two]) + print ($j[four]) + print ($j[five]) + EOI + 2 + [null] + [null] + EOO + + : object-index + : + $* <<EOI >>EOO + j = [json] one@1 two@2 three@3 + print ($j[([uint64] 1)]) + EOI + {"two":2} + EOO + + : nested + : + $* <<EOI >>EOO + o = [json] one@([json] 1 2 ([json] a@3 b@4) null) two@([json] x@x y@([json] 5 6)) + print ($o[one][1]) + print ($o[one][2][b]) + print ($o[two][y][1]) + print ($o[two][bogus][junk]) + print ($o[two][bogus][junk][garbage]) + print ($o[one][3][junk]) # JSON null + print ($o[one][3][junk][garbage]) + + a = [json] ([json] one@1 two@([json] 2 3)) ([json] 4 5) null + print ($a[0][one]) + print ($a[0][two][1]) + print ($a[1][1]) + print ($a[1][123][junk]) + print ($a[1][123][junk][garbage]) + print ($a[2][junk]) # JSON null + print ($a[2][junk][garbage]) + EOI + 2 + 4 + 6 + [null] + [null] + [null] + [null] + 1 + 3 + 5 + [null] + [null] + [null] + [null] + EOO + + : reverse + : + $* <<EOI >>EOO + print (([json] one@null)[one]) + print (([json] one@true)[one]) + print (([json] one@123)[one]) + print (([json] one@-123)[one]) + print (([json] one@0xdecaf)[one]) + print (([json] one@abc)[one]) + EOI + [null] + true + 123 + -123 + 912559 + abc + EOO + + : diagnostics-not-object + : + $* <<EOI 2>>EOE != 0 + j = [json] 1 2 3 + print ($j[one]) + EOI + <stdin>:2:11: error: invalid json value subscript: invalid uint64 value 'one' + info: json value type is array + <stdin>:2:9: info: use the '\[' escape sequence if this is a wildcard pattern + EOE +} + +: iteration +: +{ + : null + : + $* <<EOI + for v: ([json] null) + print $v + EOI + + : simple + : + $* <<EOI >>EOO + for v: ([json] 123) + print $v + EOI + 123 + EOO + + : array + : + $* <<EOI >>EOO + for v: ([json] 1 2 3) + print $v + EOI + 1 + 2 + 3 + EOO + + : object + : + $* <<EOI >>EOO + for v: ([json] one@1 two@2 three@3) + print $v + EOI + {"one":1} + {"two":2} + {"three":3} + EOO + + : reverse + : + $* <<EOI >>EOO + for v: ([json] null true 123 -123 0xdecaf abc) + print $v + EOI + [null] + true + 123 + -123 + 912559 + abc + EOO +} + +: json-map +: +{ + : basics + : + $* <<EOI >>EOO + m = [json_map] 2@([json] a@1 b@2) 1@([json] 1 2) 0@([json] null) -1@null + print $m + for p: $m + print $first($p) $second($p) + print ($m[1]) + print $type($m[1]) + print ($m[2][b]) + print ($m[0]) + print ($m[-1]) + EOI + -1@null 0@null 1@[1,2] 2@{"a":1,"b":2} + -1 null + 0 null + 1 [1,2] + 2 {"a":1,"b":2} + [1,2] + json + 2 + + + EOO +} + +: json-set +: +{ + : basics + : + $* <<EOI >>EOO + s = [json_set] ([json] x@1 y@2) ([json] a@1 b@2) + print $s + for v: $s + print $type($v) $v + print ($s[([json] y@2 x@1)]) + EOI + {"a":1,"b":2} {"x":1,"y":2} + json {"a":1,"b":2} + json {"x":1,"y":2} + true + EOO +} diff --git a/tests/type/map/buildfile b/tests/type/map/buildfile new file mode 100644 index 0000000..7f2cdcf --- /dev/null +++ b/tests/type/map/buildfile @@ -0,0 +1,4 @@ +# file : tests/type/map/buildfile +# license : MIT; see accompanying LICENSE file + +./: testscript $b diff --git a/tests/type/map/testscript b/tests/type/map/testscript new file mode 100644 index 0000000..29f5ed4 --- /dev/null +++ b/tests/type/map/testscript @@ -0,0 +1,70 @@ +# file : tests/type/map/testscript +# license : MIT; see accompanying LICENSE file + +# See also tests in function/*/ (size(), keys()), type/json/ (json_map). + +.include ../../common.testscript + +: basics +: +$* <<EOI >>EOO +m = [string_map] a@0 b@2 a@1 +print $m +m += c@3 b@0 +print $m +m =+ d@4 b@1 +print $m +EOI +a@1 b@2 +a@1 b@0 c@3 +a@1 b@0 c@3 d@4 +EOO + +: type +: +$* <<EOI >>EOO +m = [string_map] +print $type($m) +EOI +string_map +EOO + +: subscript +: +$* <<EOI >>EOO +m = [string_map] a@1 b@2 c@3 +print ($m[b]) +print $type($m[b]) +print ($m[z]) +EOI +2 +string +[null] +EOO + +: iteration +: +$* <<EOI >>EOO +for p: [string_map] a@1 b@2 c@3 + print $first($p) $second($p) + +for p: [string_map, null] + fail bad +EOI +a 1 +b 2 +c 3 +EOO + +: iteration-index +: +$* <<EOI >>EOO +m = [string_map] a@1 b@2 c@3 +k = $keys($m) +for i: $integer_sequence(0, $size($k)) + print $i ($k[$i]) ($m[($k[$i])]) # @@ TMP: nested subscript +EOI +0 a 1 +1 b 2 +2 c 3 +EOO diff --git a/tests/type/set/buildfile b/tests/type/set/buildfile new file mode 100644 index 0000000..55b37bb --- /dev/null +++ b/tests/type/set/buildfile @@ -0,0 +1,4 @@ +# file : tests/type/set/buildfile +# license : MIT; see accompanying LICENSE file + +./: testscript $b diff --git a/tests/type/set/testscript b/tests/type/set/testscript new file mode 100644 index 0000000..aca4c2d --- /dev/null +++ b/tests/type/set/testscript @@ -0,0 +1,55 @@ +# file : tests/type/set/testscript +# license : MIT; see accompanying LICENSE file + +# See also tests in function/*/ (size()), type/json/ (json_set). + +.include ../../common.testscript + +: basics +: +$* <<EOI >>EOO +s = [string_set] a b a +print $s +s += c b +print $s +s =+ d b +print $s +EOI +a b +a b c +a b c d +EOO + +: type +: +$* <<EOI >>EOO +s = [string_set] +print $type($s) +EOI +string_set +EOO + +: subscript +: +$* <<EOI >>EOO +s = [string_set] a b c +print ($s[b]) +print ($s[z]) +EOI +true +false +EOO + +: iteration +: +$* <<EOI >>EOO +for s: [string_set] a b c + print $type($s) $s + +for s: [string_set, null] + fail bad +EOI +string a +string b +string c +EOO diff --git a/tests/type/vector/buildfile b/tests/type/vector/buildfile new file mode 100644 index 0000000..5b2aa0e --- /dev/null +++ b/tests/type/vector/buildfile @@ -0,0 +1,4 @@ +# file : tests/type/vector/buildfile +# license : MIT; see accompanying LICENSE file + +./: testscript $b diff --git a/tests/type/vector/testscript b/tests/type/vector/testscript new file mode 100644 index 0000000..9b3aaba --- /dev/null +++ b/tests/type/vector/testscript @@ -0,0 +1,57 @@ +# file : tests/type/vector/testscript +# license : MIT; see accompanying LICENSE file + +# See also tests in function/*/ (size(), find(), etc). + +.include ../../common.testscript + +: basics +: +$* <<EOI >>EOO +v = [strings] b c +print $v +v += d +print $v +v =+ a +print $v +EOI +b c +b c d +a b c d +EOO + +: type +: +$* <<EOI >>EOO +v = [strings] +print $type($v) +EOI +strings +EOO + +: subscript +: +$* <<EOI >>EOO +v = [strings] a b c +print ($v[1]) +print $type($v[1]) +print ($v[3]) +EOI +b +string +[null] +EOO + +: iteration +: +$* <<EOI >>EOO +for s: [strings] a b c + print $type($s) $s + +for s: [strings, null] + fail bad +EOI +string a +string b +string c +EOO diff --git a/tests/value/concat.testscript b/tests/value/concat.testscript index 97391c4..69ec9fc 100644 --- a/tests/value/concat.testscript +++ b/tests/value/concat.testscript @@ -3,6 +3,48 @@ .include ../common.testscript +: null +: +{ + : untyped + : + $* <<EOI >>/EOO + x = [null] + + print y "$x x" + print "x $x" y + + print $x"x" + print "x"$x + print $x$x + EOI + y x + x y + x + x + {} + EOO + + : string + : + $* <<EOI >>/EOO + x = [string,null] + + print y "$x x" + print "x $x" y + + print $x"x" + print "x"$x + print $x$x + EOI + y x + x y + x + x + {} + EOO +} + : dir_path : { diff --git a/tests/value/reverse.testscript b/tests/value/reverse.testscript index 9f73981..921d14b 100644 --- a/tests/value/reverse.testscript +++ b/tests/value/reverse.testscript @@ -89,3 +89,58 @@ EOO } } + +: reduce +: +: Test empty simple value reduction heuristics. +: +{ + : typed + : + $* <<EOI >>"EOO" + x = [string] + n = [string,null] + y = [strings] $x + y += $x + y += $n + print $size($y) + + file{*}: y += $x + file{x}: + print $size($(file{x}: y)) + + for i: $x + print iteration + + print $null($x[0]) + EOI + 2 + 3 + iteration + false + EOO + + : untyped + : + $* <<EOI >>"EOO" + x = + n = [null] + y = $x + y += $x + y += $n + print $size($y) + + file{*}: y += $x + file{x}: + print $size($(file{x}: y)) + + for i: $x + print iteration + + print $null($x[0]) + EOI + 0 + 0 + true + EOO +} diff --git a/tests/variable/override/testscript b/tests/variable/override/testscript index 0c8ef5b..7b973c0 100644 --- a/tests/variable/override/testscript +++ b/tests/variable/override/testscript @@ -8,18 +8,18 @@ { : value-version : - $* x+=01 y+=01 <<EOI >>EOO - x = [string] 0 - print $x + $* p.x+=01 p.y+=01 <<EOI >>EOO + p.x = [string] 0 + print $p.x - x = [uint64] 1 - print $x + p.x = [uint64] 1 + print $p.x - y = 0 - print $y + p.y = 0 + print $p.y - [uint64] y = [null] - print $y + [uint64] p.y = [null] + print $p.y EOI 001 2 @@ -29,21 +29,21 @@ : value-position : - $* x+=01 <<EOI >>EOO - x = [string] 0 + $* p.x+=01 <<EOI >>EOO + p.x = [string] 0 - print $x + print $p.x dir/ { - print $x + print $p.x } - dir/ x = [uint64] 1 + dir/ p.x = [uint64] 1 - print $x + print $p.x dir/ { - print $x + print $p.x } EOI @@ -59,17 +59,19 @@ : Test overriding cached target type/pattern-specific prepend/append : { - $* x+=X <<EOI >>EOO - x = 0 - file{*}: x += a + $* p.x+=X <<EOI >>EOO + p.x = 0 + file{*}: p.x += a - print $(file{foo}:x) + file{foo}: - x = 1 # Should invalidate both caches. - print $(file{foo}:x) + print $(file{foo}:p.x) - file{*}: x += b # Should invalidate both caches. - print $(file{foo}:x) + p.x = 1 # Should invalidate both caches. + print $(file{foo}:p.x) + + file{*}: p.x += b # Should invalidate both caches. + print $(file{foo}:p.x) EOI 0 a X 1 a X @@ -82,24 +84,24 @@ { : after : - $* x=1 x+=2 x=+0 <<EOI >>EOO - print $x + $* p.x=1 p.x+=2 p.x=+0 <<EOI >>EOO + print $p.x EOI 0 1 2 EOO : before : - $* x+=2 x=+0 x=1 <<EOI >>EOO - print $x + $* p.x+=2 p.x=+0 p.x=1 <<EOI >>EOO + print $p.x EOI 1 EOO : both : - $* x=+0 x=1 x+=2 <<EOI >>EOO - print $x + $* p.x=+0 p.x=1 p.x+=2 <<EOI >>EOO + print $p.x EOI 1 2 EOO @@ -110,9 +112,9 @@ { : assign : - $* x=0 !y=0 x=1 !y=1 <<EOI >>EOO - print $x - print $y + $* p.x=0 !p.y=0 p.x=1 !p.y=1 <<EOI >>EOO + print $p.x + print $p.y EOI 1 1 @@ -120,16 +122,16 @@ : append : - $* x=0 x+=1 x+=2 <<EOI >>EOO - print $x + $* p.x=0 p.x+=1 p.x+=2 <<EOI >>EOO + print $p.x EOI 0 1 2 EOO : prepend : - $* x=2 x=+1 x=+0 <<EOI >>EOO - print $x + $* p.x=2 p.x=+1 p.x=+0 <<EOI >>EOO + print $p.x EOI 0 1 2 EOO diff --git a/tests/variable/private/buildfile b/tests/variable/private/buildfile new file mode 100644 index 0000000..3b0d20c --- /dev/null +++ b/tests/variable/private/buildfile @@ -0,0 +1,4 @@ +# file : tests/variable/private/buildfile +# license : MIT; see accompanying LICENSE file + +./: testscript $b diff --git a/tests/variable/private/testscript b/tests/variable/private/testscript new file mode 100644 index 0000000..ddb78fd --- /dev/null +++ b/tests/variable/private/testscript @@ -0,0 +1,46 @@ +# file : tests/variable/private/testscript +# license : MIT; see accompanying LICENSE file + +# Test public/private variable mode. + +buildfile = true +test.arguments = 'noop(../)' + +.include ../../common.testscript + ++cat <<EOI >=build/bootstrap.build +project = test +amalgamation = +subprojects = subproj + +using install +EOI ++cat <<EOI >=buildfile +[string] foo = abc +print $type($foo) $foo + +subproj/: install = false +print $type($(subproj/: install)) $(subproj/: install) + +include subproj/ +EOI + +: subproj +: +mkdir build; +cat <<EOI >=build/bootstrap.build; +project = subporj +EOI +cat <<EOI >=buildfile; +[uint64] foo = 0123 +print $type($foo) $foo + +[bool] install = true +print $type($install) $install +EOI +$* >>EOO +string abc +path false +uint64 123 +bool true +EOO diff --git a/tests/variable/target-specific/testscript b/tests/variable/target-specific/testscript index 627d8ab..c52712b 100644 --- a/tests/variable/target-specific/testscript +++ b/tests/variable/target-specific/testscript @@ -65,13 +65,15 @@ print (foo: bar) print (foo : bar) print (foo/: bar) print (foo/file{fox}: bar) +print (file{fox}@./: bar) EOI -foo:bar -foo:bar -foo:bar -foo:bar -foo/:bar -foo/file{fox}:bar +bar:foo +bar:foo +bar:foo +bar:foo +bar:foo/ +bar:foo/file{fox} +bar:file{fox}@./ EOO : eval-qual-name-expected diff --git a/tests/variable/target-type-pattern-specific/testscript b/tests/variable/target-type-pattern-specific/testscript index 1a3e98a..9c600ca 100644 --- a/tests/variable/target-type-pattern-specific/testscript +++ b/tests/variable/target-type-pattern-specific/testscript @@ -12,6 +12,9 @@ x = x y = y dir{*}: x = X dir{*}: y += Y + +./: + print $(./: x) print $(./: y) EOI @@ -19,6 +22,67 @@ X y Y EOO +: old-tests-type-pattern +: +$* <<EOI >>EOO +dir{*}: x = y + +x = z +dir{*-foo}: x = $x # 'z' +bar-foo/: +print $(bar-foo/: x) + +x = G +file{*-foo}: x = x +file{xfoo}: x = $x # 'G' +print $(file{xfoo}: x) +file{-foo}: x = $x # 'x' +print $(file{-foo}: x) +file{x-foo}: x = $x # 'x' +print $(file{x-foo}: x) +file{bar-*-foo}: x = X +file{bar-x}: x = $x # 'G' +print $(file{bar-x}: x) +file{bar--foo}: x = $x # 'X' +print $(file{bar--foo}: x) +file{bar-x-foo}: x = $x # 'X' +print $(file{bar-x-foo}: x) + +file{*-fox}: x = 1 +file{fox-*}: x = 2 +file{fox-fox}: x = $x # '2' +print $(file{fox-fox}: x) +file{*-fox}: x = 3 +file{fox-x-fox}: x = $x # still '2'! +print $(file{fox-fox}: x) + +*-foz: x = z # any target +file{x-foz}: x = $x # 'z' +print $(file{x-foz}: x) + +*: x1 = X1 +{*}: x2 = X2 +target{*}: x3 = X3 +file{x}: +print $(file{x}: x1) +print $(file{x}: x2) +print $(file{x}: x3) +EOI +z +G +x +x +G +X +X +2 +2 +z +X1 +X2 +X3 +EOO + : block : $* <<EOI >>EOO @@ -30,6 +94,9 @@ dir{*}: y += Y z = $x # Note: from scope. } + +./: + print $(./: x) print $(./: y) print $(./: z) @@ -49,9 +116,88 @@ file{f*} file{b*}: x = X y += Y } + +file{foo bar}: + print $(file{foo}: x) print $(file{bar}: y) EOI X y Y EOO + +: regex +: +{ + : flag-icase + : + $* <<EOI >>EOO + file{~/'.+\.txt'/i}: x = 1 + + file{foo.txt foo.TXT}: + + print $(file{foo.txt}: x) + print $(file{foo.TXT}: x) + EOI + 1 + 1 + EOO + + : flag-match-ext + : + $* <<EOI >>EOO + define txt: file + + txt{*}: x = 0 + txt{~/'[^.]+'/}: x = 1 + txt{~/'.+\.tx'/e}: x = 2 + txt{~/'.+\.txt'/e}: x = 3 + + txt{foo.x foo.tx foo.txt foo.bar...}: + + print $(txt{foo.x}: x) + print $(txt{foo.tx}: x) + print $(txt{foo.txt}: x) + print $(txt{foo.bar...}: x) + EOI + 1 + 2 + 3 + 0 + EOO + + : backref + : + $* <<EOI >>EOO + x = 0 + file{~/'(.+)-\1'/}: x = 1 + + file{foo-foo foo-bar}: + + print $(file{foo-foo}: x) + print $(file{foo-bar}: x) + EOI + 1 + 0 + EOO + + : dir + : + $* <<EOI >>EOO + foo/dir{~/b.+/}: x = 1 + + foo/dir{bar}: + + print $(foo/dir{bar}: x) + EOI + 1 + EOO + + : invalid + : + $* <<EOI 2>>~/EOE/ != 0 + file{~/'(.+'/}: x = 1 + EOI + /<stdin>:1:1: error: invalid regex pattern .+/ + EOE +} |