aboutsummaryrefslogtreecommitdiffstats
path: root/meson/test cases/common/14 configure file
diff options
context:
space:
mode:
Diffstat (limited to 'meson/test cases/common/14 configure file')
-rw-r--r--meson/test cases/common/14 configure file/basename.py28
-rw-r--r--meson/test cases/common/14 configure file/check_file.py34
-rw-r--r--meson/test cases/common/14 configure file/check_inputs.py14
-rw-r--r--meson/test cases/common/14 configure file/config.h1
-rw-r--r--meson/test cases/common/14 configure file/config.h.in5
-rw-r--r--meson/test cases/common/14 configure file/config4a.h.in2
-rw-r--r--meson/test cases/common/14 configure file/config4b.h.in2
-rw-r--r--meson/test cases/common/14 configure file/config5.h.in1
-rw-r--r--meson/test cases/common/14 configure file/config6.h.in19
-rw-r--r--meson/test cases/common/14 configure file/config7.h.in16
-rw-r--r--meson/test cases/common/14 configure file/config8.h.in3
-rw-r--r--meson/test cases/common/14 configure file/depfile0
-rw-r--r--meson/test cases/common/14 configure file/differentafterbasename1.in0
-rw-r--r--meson/test cases/common/14 configure file/differentafterbasename2.in0
-rw-r--r--meson/test cases/common/14 configure file/dummy.dat0
-rw-r--r--meson/test cases/common/14 configure file/dumpprog.c52
-rw-r--r--meson/test cases/common/14 configure file/file_contains.py22
-rwxr-xr-xmeson/test cases/common/14 configure file/generator-deps.py19
-rwxr-xr-xmeson/test cases/common/14 configure file/generator-without-input-file.py14
-rwxr-xr-xmeson/test cases/common/14 configure file/generator.py17
-rw-r--r--meson/test cases/common/14 configure file/invalid-utf8.bin.inbin0 -> 10 bytes
-rw-r--r--meson/test cases/common/14 configure file/meson.build309
-rw-r--r--meson/test cases/common/14 configure file/nosubst-nocopy1.txt.in1
-rw-r--r--meson/test cases/common/14 configure file/nosubst-nocopy2.txt.in1
-rw-r--r--meson/test cases/common/14 configure file/prog.c17
-rw-r--r--meson/test cases/common/14 configure file/prog2.c5
-rw-r--r--meson/test cases/common/14 configure file/prog4.c6
-rw-r--r--meson/test cases/common/14 configure file/prog5.c6
-rw-r--r--meson/test cases/common/14 configure file/prog6.c11
-rw-r--r--meson/test cases/common/14 configure file/prog7.c10
-rw-r--r--meson/test cases/common/14 configure file/prog9.c18
-rw-r--r--meson/test cases/common/14 configure file/sameafterbasename.in0
-rw-r--r--meson/test cases/common/14 configure file/sameafterbasename.in20
-rw-r--r--meson/test cases/common/14 configure file/subdir/meson.build38
-rw-r--r--meson/test cases/common/14 configure file/test.json8
-rw-r--r--meson/test cases/common/14 configure file/test.py.in4
-rw-r--r--meson/test cases/common/14 configure file/touch.py16
37 files changed, 699 insertions, 0 deletions
diff --git a/meson/test cases/common/14 configure file/basename.py b/meson/test cases/common/14 configure file/basename.py
new file mode 100644
index 000000000..d2c866216
--- /dev/null
+++ b/meson/test cases/common/14 configure file/basename.py
@@ -0,0 +1,28 @@
+#!/usr/bin/env python3
+
+import sys
+import argparse
+import os
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('text', nargs='*', type=str)
+ args = parser.parse_args()
+
+ text = args.text if isinstance(args.text, list) else [args.text]
+
+ output = ''
+ for t in text:
+ t = os.path.basename(t)
+
+ if not output:
+ output += t
+ else:
+ output += ' ' + t
+
+ output += '\n'
+
+ sys.stdout.write(output)
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/meson/test cases/common/14 configure file/check_file.py b/meson/test cases/common/14 configure file/check_file.py
new file mode 100644
index 000000000..a96614702
--- /dev/null
+++ b/meson/test cases/common/14 configure file/check_file.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python3
+
+import os
+import sys
+
+def permit_osx_workaround(m1, m2):
+ import platform
+ if platform.system().lower() != 'darwin':
+ return False
+ if m2 % 10000 != 0:
+ return False
+ if m1//10000 != m2//10000:
+ return False
+ return True
+
+if len(sys.argv) == 2:
+ assert(os.path.exists(sys.argv[1]))
+elif len(sys.argv) == 3:
+ f1 = sys.argv[1]
+ f2 = sys.argv[2]
+ m1 = os.stat(f1).st_mtime_ns
+ m2 = os.stat(f2).st_mtime_ns
+ # Compare only os.stat()
+ if m1 != m2:
+ # Under macOS the lower four digits sometimes get assigned
+ # zero, even though shutil.copy2 should preserve metadata.
+ # Just have to accept it, I guess.
+ if not permit_osx_workaround(m1, m2):
+ raise RuntimeError(f'mtime of {f1!r} ({m1!r}) != mtime of {f2!r} ({m2!r})')
+ import filecmp
+ if not filecmp.cmp(f1, f2):
+ raise RuntimeError(f'{f1!r} != {f2!r}')
+else:
+ raise AssertionError
diff --git a/meson/test cases/common/14 configure file/check_inputs.py b/meson/test cases/common/14 configure file/check_inputs.py
new file mode 100644
index 000000000..1faa8ba05
--- /dev/null
+++ b/meson/test cases/common/14 configure file/check_inputs.py
@@ -0,0 +1,14 @@
+#!/usr/bin/env python3
+
+import sys
+from pathlib import Path
+
+files = [Path(f) for f in sys.argv[1:]]
+names = [f.name for f in files]
+
+assert names == ['check_inputs.txt', 'prog.c', 'prog.c', 'prog2.c', 'prog4.c', 'prog5.c']
+for f in files[1:]:
+ assert f.exists()
+
+with files[0].open('w') as ofile:
+ ofile.write("#define ZERO_RESULT 0\n")
diff --git a/meson/test cases/common/14 configure file/config.h b/meson/test cases/common/14 configure file/config.h
new file mode 100644
index 000000000..e85b634b5
--- /dev/null
+++ b/meson/test cases/common/14 configure file/config.h
@@ -0,0 +1 @@
+#error "This file should not be included. Build dir must become before source dir in search order"
diff --git a/meson/test cases/common/14 configure file/config.h.in b/meson/test cases/common/14 configure file/config.h.in
new file mode 100644
index 000000000..14a155874
--- /dev/null
+++ b/meson/test cases/common/14 configure file/config.h.in
@@ -0,0 +1,5 @@
+#define MESSAGE "@var@"
+#define OTHER "@other@" "@second@" "@empty@"
+
+#mesondefine BE_TRUE
+#mesondefine SHOULD_BE_UNDEF
diff --git a/meson/test cases/common/14 configure file/config4a.h.in b/meson/test cases/common/14 configure file/config4a.h.in
new file mode 100644
index 000000000..aafd195c2
--- /dev/null
+++ b/meson/test cases/common/14 configure file/config4a.h.in
@@ -0,0 +1,2 @@
+/* Dummy file */
+#define RESULTA @ZERO@
diff --git a/meson/test cases/common/14 configure file/config4b.h.in b/meson/test cases/common/14 configure file/config4b.h.in
new file mode 100644
index 000000000..3408bab6f
--- /dev/null
+++ b/meson/test cases/common/14 configure file/config4b.h.in
@@ -0,0 +1,2 @@
+/* Dummy file */
+#define RESULTB @ZERO@
diff --git a/meson/test cases/common/14 configure file/config5.h.in b/meson/test cases/common/14 configure file/config5.h.in
new file mode 100644
index 000000000..323bec64a
--- /dev/null
+++ b/meson/test cases/common/14 configure file/config5.h.in
@@ -0,0 +1 @@
+#define MESSAGE "@var@"
diff --git a/meson/test cases/common/14 configure file/config6.h.in b/meson/test cases/common/14 configure file/config6.h.in
new file mode 100644
index 000000000..9719f8715
--- /dev/null
+++ b/meson/test cases/common/14 configure file/config6.h.in
@@ -0,0 +1,19 @@
+/* No escape */
+#define MESSAGE1 "@var1@"
+
+/* Single escape means no replace */
+#define MESSAGE2 "\@var1@"
+
+/* Replace pairs of escapes before '@' or '\@' with escape characters
+ * (note we have to double number of pairs due to C string escaping)
+ */
+#define MESSAGE3 "\\\\@var1@"
+
+/* Pairs of escapes and then single escape to avoid replace */
+#define MESSAGE4 "\\\\\@var1@"
+
+/* Check escaped variable does not overlap following variable */
+#define MESSAGE5 "\@var1@var2@"
+
+/* Check escape character outside variables */
+#define MESSAGE6 "\\ @ \@ \\\\@ \\\\\@"
diff --git a/meson/test cases/common/14 configure file/config7.h.in b/meson/test cases/common/14 configure file/config7.h.in
new file mode 100644
index 000000000..edd0bb3fe
--- /dev/null
+++ b/meson/test cases/common/14 configure file/config7.h.in
@@ -0,0 +1,16 @@
+/* No escape */
+#define MESSAGE1 "${var1}"
+
+/* Single escape means no replace */
+#define MESSAGE2 "\${var1}"
+
+/* Replace pairs of escapes before '@' or '\@' with escape characters
+ * (note we have to double number of pairs due to C string escaping)
+ */
+#define MESSAGE3 "\\\\${var1}"
+
+/* Pairs of escapes and then single escape to avoid replace */
+#define MESSAGE4 "\\\\\${var1}"
+
+/* Check escape character outside variables */
+#define MESSAGE5 "\\ ${ \${ \\\\${ \\\\\${"
diff --git a/meson/test cases/common/14 configure file/config8.h.in b/meson/test cases/common/14 configure file/config8.h.in
new file mode 100644
index 000000000..b854ea04e
--- /dev/null
+++ b/meson/test cases/common/14 configure file/config8.h.in
@@ -0,0 +1,3 @@
+#define MESSAGE "@var@"
+
+#define "non isolatin1 char Ä fails decode with utf-8"
diff --git a/meson/test cases/common/14 configure file/depfile b/meson/test cases/common/14 configure file/depfile
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/meson/test cases/common/14 configure file/depfile
diff --git a/meson/test cases/common/14 configure file/differentafterbasename1.in b/meson/test cases/common/14 configure file/differentafterbasename1.in
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/meson/test cases/common/14 configure file/differentafterbasename1.in
diff --git a/meson/test cases/common/14 configure file/differentafterbasename2.in b/meson/test cases/common/14 configure file/differentafterbasename2.in
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/meson/test cases/common/14 configure file/differentafterbasename2.in
diff --git a/meson/test cases/common/14 configure file/dummy.dat b/meson/test cases/common/14 configure file/dummy.dat
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/meson/test cases/common/14 configure file/dummy.dat
diff --git a/meson/test cases/common/14 configure file/dumpprog.c b/meson/test cases/common/14 configure file/dumpprog.c
new file mode 100644
index 000000000..9f63b23b9
--- /dev/null
+++ b/meson/test cases/common/14 configure file/dumpprog.c
@@ -0,0 +1,52 @@
+#define SHOULD_BE_UNDEFINED 1
+
+#include"config3.h"
+#include<string.h>
+#include<stdio.h>
+
+#ifdef SHOULD_BE_UNDEFINED
+#error Token did not get undefined.
+#endif
+
+#ifndef SHOULD_BE_DEFINED
+#error Token did not get defined
+#endif
+
+#define stringify(s) str(s)
+#define str(s) #s
+
+int main(void) {
+#if !(SHOULD_BE_UNQUOTED_STRING == string)
+ printf("String token (unquoted) defined wrong.\n");
+ return 1;
+#endif
+ if(strcmp(SHOULD_BE_STRING, "string") != 0) {
+ printf("String token defined wrong.\n");
+ return 1;
+ }
+ if(strcmp(SHOULD_BE_STRING2, "A \"B\" C") != 0) {
+ printf("String token 2 defined wrong.\n");
+ return 1;
+ }
+ if(strcmp(SHOULD_BE_STRING3, "A \"\" C") != 0) {
+ printf("String token 3 defined wrong.\n");
+ return 1;
+ }
+ if(strcmp(SHOULD_BE_STRING4, "A \" C") != 0) {
+ printf("String token 4 defined wrong.\n");
+ return 1;
+ }
+ if(SHOULD_BE_ONE != 1) {
+ printf("One defined incorrectly.\n");
+ return 1;
+ }
+ if(SHOULD_BE_ZERO != 0) {
+ printf("Zero defined incorrectly.\n");
+ return 1;
+ }
+ if(strcmp(SHOULD_BE_QUOTED_ONE, "1") != 0) {
+ printf("Quoted number defined incorrectly.\n");
+ return 1;
+ }
+ SHOULD_BE_RETURN 0;
+}
diff --git a/meson/test cases/common/14 configure file/file_contains.py b/meson/test cases/common/14 configure file/file_contains.py
new file mode 100644
index 000000000..409f09c65
--- /dev/null
+++ b/meson/test cases/common/14 configure file/file_contains.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python3
+
+import sys
+import argparse
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('file', nargs=1, type=str)
+ parser.add_argument('text', nargs=1, type=str)
+ args = parser.parse_args()
+
+ text = args.text[0]
+
+ with open(args.file[0], encoding='utf-8') as f:
+ for line in f:
+ if line.strip() == text:
+ return 0
+
+ return 1
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/meson/test cases/common/14 configure file/generator-deps.py b/meson/test cases/common/14 configure file/generator-deps.py
new file mode 100755
index 000000000..cca253cca
--- /dev/null
+++ b/meson/test cases/common/14 configure file/generator-deps.py
@@ -0,0 +1,19 @@
+#!/usr/bin/env python3
+
+import sys, os
+from pathlib import Path
+
+if len(sys.argv) != 3:
+ print("Wrong amount of parameters.")
+
+build_dir = Path(os.environ['MESON_BUILD_ROOT'])
+subdir = Path(os.environ['MESON_SUBDIR'])
+outputf = Path(sys.argv[1])
+
+with outputf.open('w') as ofile:
+ ofile.write("#define ZERO_RESULT 0\n")
+
+depf = Path(sys.argv[2])
+if not depf.exists():
+ with depf.open('w') as ofile:
+ ofile.write(f"{outputf.name}: depfile\n")
diff --git a/meson/test cases/common/14 configure file/generator-without-input-file.py b/meson/test cases/common/14 configure file/generator-without-input-file.py
new file mode 100755
index 000000000..2ee059ee2
--- /dev/null
+++ b/meson/test cases/common/14 configure file/generator-without-input-file.py
@@ -0,0 +1,14 @@
+#!/usr/bin/env python3
+
+import sys, os
+from pathlib import Path
+
+if len(sys.argv) != 2:
+ print("Wrong amount of parameters.")
+
+build_dir = Path(os.environ['MESON_BUILD_ROOT'])
+subdir = Path(os.environ['MESON_SUBDIR'])
+outputf = Path(sys.argv[1])
+
+with outputf.open('w') as ofile:
+ ofile.write("#define ZERO_RESULT 0\n")
diff --git a/meson/test cases/common/14 configure file/generator.py b/meson/test cases/common/14 configure file/generator.py
new file mode 100755
index 000000000..e3cc88101
--- /dev/null
+++ b/meson/test cases/common/14 configure file/generator.py
@@ -0,0 +1,17 @@
+#!/usr/bin/env python3
+
+import sys, os
+from pathlib import Path
+
+if len(sys.argv) != 3:
+ print("Wrong amount of parameters.")
+
+build_dir = Path(os.environ['MESON_BUILD_ROOT'])
+subdir = Path(os.environ['MESON_SUBDIR'])
+inputf = Path(sys.argv[1])
+outputf = Path(sys.argv[2])
+
+assert(inputf.exists())
+
+with outputf.open('w') as ofile:
+ ofile.write("#define ZERO_RESULT 0\n")
diff --git a/meson/test cases/common/14 configure file/invalid-utf8.bin.in b/meson/test cases/common/14 configure file/invalid-utf8.bin.in
new file mode 100644
index 000000000..98e9ed9a9
--- /dev/null
+++ b/meson/test cases/common/14 configure file/invalid-utf8.bin.in
Binary files differ
diff --git a/meson/test cases/common/14 configure file/meson.build b/meson/test cases/common/14 configure file/meson.build
new file mode 100644
index 000000000..f7e0eeba6
--- /dev/null
+++ b/meson/test cases/common/14 configure file/meson.build
@@ -0,0 +1,309 @@
+project('configure file test', 'c')
+
+conf = configuration_data()
+
+conf.set('var', 'mystring')
+conf.set('other', 'string 2')
+conf.set('second', ' bonus')
+conf.set('BE_TRUE', true)
+
+assert(conf.get('var') == 'mystring', 'Get function is not working.')
+assert(conf.get('var', 'default') == 'mystring', 'Get function is not working.')
+assert(conf.get('notthere', 'default') == 'default', 'Default value getting is not working.')
+assert(conf.keys() == ['BE_TRUE', 'other', 'second', 'var'], 'Keys function is not working')
+
+cfile = configure_file(input : 'config.h.in',
+ output : 'config.h',
+ configuration : conf)
+
+e = executable('inctest', 'prog.c',
+# Note that you should NOT do this. Don't add generated headers here
+# This tests that we do the right thing even if people add in conf files
+# to their sources.
+ cfile)
+test('inctest', e)
+
+# Test if we can also pass files() as input
+configure_file(input : files('config.h.in'),
+ output : 'config2.h',
+ configuration : conf)
+
+# Now generate a header file with an external script.
+genprog = import('python3').find_python()
+scriptfile = '@0@/generator.py'.format(meson.current_source_dir())
+ifile = '@0@/dummy.dat'.format(meson.current_source_dir())
+ofile = '@0@/config2.h'.format(meson.current_build_dir())
+
+check_file = find_program('check_file.py')
+# Configure in source root with command and absolute paths
+outf = configure_file(input : 'dummy.dat',
+ output : 'config2.h',
+ command : [genprog, scriptfile, ifile, ofile],
+ install_dir : 'share/appdir')
+ret = run_command(check_file, outf)
+if ret.returncode() != 0
+ error('Error running command: @0@\n@1@'.format(ret.stdout(), ret.stderr()))
+endif
+
+# Same again as before, but an input file should not be required in
+# this case where we use a command/script to generate the output file.
+genscript2b = '@0@/generator-without-input-file.py'.format(meson.current_source_dir())
+ofile2b = '@0@/config2b.h'.format(meson.current_build_dir())
+outf = configure_file(
+ output : 'config2b.h',
+ command : [genprog, genscript2b, ofile2b],
+ install_dir : 'share/appdir')
+ret = run_command(check_file, outf)
+if ret.returncode() != 0
+ error('Error running command: @0@\n@1@'.format(ret.stdout(), ret.stderr()))
+endif
+
+genscript2deps = '@0@/generator-deps.py'.format(meson.current_source_dir())
+ofile2deps = '@0@/config2deps.h'.format(meson.current_build_dir())
+outf = configure_file(
+ output : 'config2deps.h',
+ depfile : 'depfile.d',
+ command : [genprog, genscript2deps, ofile2deps, '@DEPFILE@'])
+ret = run_command(check_file, outf)
+if ret.returncode() != 0
+ error('Error running command: @0@\n@1@'.format(ret.stdout(), ret.stderr()))
+endif
+
+found_script = find_program('generator.py')
+# More configure_file tests in here
+subdir('subdir')
+
+test('inctest2', executable('prog2', 'prog2.c'))
+
+# Generate a conf file without an input file.
+
+dump = configuration_data()
+dump.set_quoted('SHOULD_BE_STRING', 'string', description : 'A string')
+dump.set_quoted('SHOULD_BE_STRING2', 'A "B" C')
+dump.set_quoted('SHOULD_BE_STRING3', 'A "" C')
+dump.set_quoted('SHOULD_BE_STRING4', 'A " C')
+dump.set('SHOULD_BE_RETURN', 'return')
+dump.set('SHOULD_BE_DEFINED', true)
+dump.set('SHOULD_BE_UNDEFINED', false)
+dump.set('SHOULD_BE_ONE', 1)
+dump.set('SHOULD_BE_ZERO', 0, description : 'Absolutely zero')
+dump.set('SHOULD_BE_QUOTED_ONE', '"1"')
+
+dump.set_quoted('INTEGER_AS_STRING', '12')
+if dump.get_unquoted('INTEGER_AS_STRING').to_int() == 12
+ dump.set('SHOULD_BE_UNQUOTED_STRING', dump.get_unquoted('SHOULD_BE_STRING'))
+endif
+
+configure_file(output : 'config3.h',
+ configuration : dump)
+
+test('Configless.', executable('dumpprog', 'dumpprog.c'))
+
+
+# Config file generation in a loop with @BASENAME@ substitution
+dump = configuration_data()
+dump.set('ZERO', 0)
+config_templates = files(['config4a.h.in', 'config4b.h.in'])
+foreach config_template : config_templates
+ configure_file(input : config_template, output : '@BASENAME@', configuration : dump)
+endforeach
+
+test('Substituted', executable('prog4', 'prog4.c'))
+
+# Test `capture` keyword
+
+basename_py = find_program('basename.py')
+file_contains_py = find_program('file_contains.py')
+test_string = 'hello world'
+test_input_file = join_paths(meson.current_build_dir(), test_string)
+run_command(find_program('touch.py'), test_input_file)
+configs = [
+ # no input
+ configure_file(command: [ basename_py, test_string ], capture: true, output: 'capture test 1'),
+ # with input
+ configure_file(input: test_input_file, command: [ basename_py, '@INPUT@' ], capture: true, output: 'capture test 2'),
+]
+foreach c : configs
+ test('@0@'.format(c), file_contains_py, args: [ c, test_string ])
+endforeach
+
+# Test variable is substituted only once
+conf5 = configuration_data()
+conf5.set('var', '@var2@')
+conf5.set('var2', 'error')
+configure_file(
+ input : 'config5.h.in',
+ output : '@BASENAME@',
+ configuration : conf5)
+test('test5', executable('prog5', 'prog5.c'))
+
+# Test escaping
+conf6 = configuration_data()
+conf6.set('var1', 'foo')
+conf6.set('var2', 'bar')
+configure_file(
+ input : 'config6.h.in',
+ output : '@BASENAME@',
+ configuration : conf6)
+test('test6', executable('prog6', 'prog6.c'))
+
+# test empty install dir string
+cfile = configure_file(input : 'config.h.in',
+ output : 'do_not_get_installed.h',
+ install_dir : '',
+ configuration : conf)
+
+# test install_dir : false (deprecated)
+cfile = configure_file(input : 'config.h.in',
+ output : 'do_not_get_installed_please.h',
+ install_dir : false,
+ configuration : conf)
+
+# test intsall_dir with install: false
+cfile = configure_file(input : 'config.h.in',
+ output : 'do_not_get_installed_in_install_dir.h',
+ install : false,
+ install_dir : 'share/appdir',
+ configuration : conf)
+
+# Test escaping with cmake format
+conf7 = configuration_data()
+conf7.set('var1', 'foo')
+conf7.set('var2', 'bar')
+configure_file(
+ input : 'config7.h.in',
+ output : '@BASENAME@',
+ format : 'cmake',
+ configuration : conf7)
+test('test7', executable('prog7', 'prog7.c'))
+
+# Test copying of an empty configuration data object
+inf = 'invalid-utf8.bin.in'
+outf = configure_file(input : inf,
+ output : 'invalid-utf8.bin',
+ copy: true)
+ret = run_command(check_file, inf, outf)
+if ret.returncode() != 0
+ error('Error running command: @0@\n@1@'.format(ret.stdout(), ret.stderr()))
+endif
+# Now the same, but using a File object as an argument.
+inf2 = files('invalid-utf8.bin.in')[0]
+ret = run_command(check_file, inf2, outf)
+if ret.returncode() != 0
+ error('Error running command: @0@\n@1@'.format(ret.stdout(), ret.stderr()))
+endif
+
+# Test copy of a binary file
+outf = configure_file(input : inf,
+ output : 'somebinary.bin',
+ copy : true)
+ret = run_command(check_file, inf, outf)
+if ret.returncode() != 0
+ error('Error running command: @0@\n@1@'.format(ret.stdout(), ret.stderr()))
+endif
+
+# Test non isolatin1 encoded input file which fails to decode with utf-8
+conf8 = configuration_data()
+conf8.set('var', 'foo')
+configure_file(
+ input : 'config8.h.in',
+ output : '@BASENAME@',
+ encoding : 'koi8-r',
+ configuration : conf8)
+
+# Test that passing an empty configuration_data() object to a file with
+# #mesondefine substitutions does not print the warning.
+configure_file(
+ input: 'nosubst-nocopy1.txt.in',
+ output: 'nosubst-nocopy1.txt',
+ configuration : configuration_data())
+
+# test that passing an empty configuration_data() object to a file with
+# @foo@ substitutions does not print the warning.
+configure_file(
+ input: 'nosubst-nocopy2.txt.in',
+ output: 'nosubst-nocopy2.txt',
+ configuration : configuration_data())
+
+# test that passing a configured file object to test() works, and that passing
+# an empty configuration_data() object to a file that leads to no substitutions
+# prints a warning (see unit tests)
+test_file = configure_file(
+ input: 'test.py.in',
+ output: 'test.py',
+ configuration: configuration_data())
+
+# Test that overwriting an existing file creates a warning.
+configure_file(
+ input: 'test.py.in',
+ output: 'double_output.txt',
+ configuration: conf)
+configure_file(
+ input: 'test.py.in',
+ output: 'double_output.txt',
+ configuration: conf)
+
+# Test that the same file name in a different subdir will not create a warning
+configure_file(
+ input: 'test.py.in',
+ output: 'no_write_conflict.txt',
+ configuration: conf)
+
+# Test that @BASENAME@ is substituted before checking and does not create a warning.
+configure_file(
+ input: 'differentafterbasename1.in',
+ output: '@BASENAME@',
+ configuration: conf
+)
+configure_file(
+ input: 'differentafterbasename2.in',
+ output: '@BASENAME@',
+ configuration: conf
+)
+
+# Test that @BASENAME@ is substituted before checking and does create a warning on conflict.
+configure_file(
+ input: 'sameafterbasename.in',
+ output: '@BASENAME@',
+ configuration: conf
+)
+configure_file(
+ input: 'sameafterbasename.in2',
+ output: '@BASENAME@',
+ configuration: conf
+)
+
+test('configure-file', test_file)
+
+cdata = configuration_data()
+cdata.set('invalid_value', ['array'])
+
+# Dictionaries
+
+cdata = configuration_data({
+ 'A_STRING' : '"foo"',
+ 'A_INT' : 42,
+ 'A_DEFINED' : true,
+ 'A_UNDEFINED' : false,
+})
+
+configure_file(output : 'config9a.h',
+ configuration : cdata,
+)
+
+configure_file(output : 'config9b.h',
+ configuration : {
+ 'B_STRING' : '"foo"',
+ 'B_INT' : 42,
+ 'B_DEFINED' : true,
+ 'B_UNDEFINED' : false,
+ }
+)
+
+test('test9', executable('prog9', 'prog9.c'))
+
+check_inputs = find_program('check_inputs.py')
+configure_file(output : 'check_inputs.txt',
+ input : ['prog.c', files('prog2.c', 'prog4.c')],
+ command : [check_inputs, '@OUTPUT@', '@INPUT0@', '@INPUT@', files('prog5.c')]
+)
diff --git a/meson/test cases/common/14 configure file/nosubst-nocopy1.txt.in b/meson/test cases/common/14 configure file/nosubst-nocopy1.txt.in
new file mode 100644
index 000000000..6e893a105
--- /dev/null
+++ b/meson/test cases/common/14 configure file/nosubst-nocopy1.txt.in
@@ -0,0 +1 @@
+#mesondefine FOO_BAR
diff --git a/meson/test cases/common/14 configure file/nosubst-nocopy2.txt.in b/meson/test cases/common/14 configure file/nosubst-nocopy2.txt.in
new file mode 100644
index 000000000..a6a7ccad2
--- /dev/null
+++ b/meson/test cases/common/14 configure file/nosubst-nocopy2.txt.in
@@ -0,0 +1 @@
+@FOO_BAR@
diff --git a/meson/test cases/common/14 configure file/prog.c b/meson/test cases/common/14 configure file/prog.c
new file mode 100644
index 000000000..85e66b97e
--- /dev/null
+++ b/meson/test cases/common/14 configure file/prog.c
@@ -0,0 +1,17 @@
+#include <string.h>
+/* config.h must not be in quotes:
+ * https://gcc.gnu.org/onlinedocs/cpp/Search-Path.html
+ */
+#include <config.h>
+
+#ifdef SHOULD_BE_UNDEF
+#error "FAIL!"
+#endif
+
+int main(void) {
+#ifndef BE_TRUE
+ return 1;
+#else
+ return strcmp(MESSAGE, "mystring");
+#endif
+}
diff --git a/meson/test cases/common/14 configure file/prog2.c b/meson/test cases/common/14 configure file/prog2.c
new file mode 100644
index 000000000..8b90bfb52
--- /dev/null
+++ b/meson/test cases/common/14 configure file/prog2.c
@@ -0,0 +1,5 @@
+#include<config2.h>
+
+int main(void) {
+ return ZERO_RESULT;
+}
diff --git a/meson/test cases/common/14 configure file/prog4.c b/meson/test cases/common/14 configure file/prog4.c
new file mode 100644
index 000000000..1e32a3129
--- /dev/null
+++ b/meson/test cases/common/14 configure file/prog4.c
@@ -0,0 +1,6 @@
+#include <config4a.h>
+#include <config4b.h>
+
+int main(void) {
+ return RESULTA + RESULTB;
+}
diff --git a/meson/test cases/common/14 configure file/prog5.c b/meson/test cases/common/14 configure file/prog5.c
new file mode 100644
index 000000000..1a8f78523
--- /dev/null
+++ b/meson/test cases/common/14 configure file/prog5.c
@@ -0,0 +1,6 @@
+#include <string.h>
+#include <config5.h>
+
+int main(void) {
+ return strcmp(MESSAGE, "@var2@");
+}
diff --git a/meson/test cases/common/14 configure file/prog6.c b/meson/test cases/common/14 configure file/prog6.c
new file mode 100644
index 000000000..57f558605
--- /dev/null
+++ b/meson/test cases/common/14 configure file/prog6.c
@@ -0,0 +1,11 @@
+#include <string.h>
+#include <config6.h>
+
+int main(void) {
+ return strcmp(MESSAGE1, "foo")
+ || strcmp(MESSAGE2, "@var1@")
+ || strcmp(MESSAGE3, "\\foo")
+ || strcmp(MESSAGE4, "\\@var1@")
+ || strcmp(MESSAGE5, "@var1bar")
+ || strcmp(MESSAGE6, "\\ @ @ \\@ \\@");
+}
diff --git a/meson/test cases/common/14 configure file/prog7.c b/meson/test cases/common/14 configure file/prog7.c
new file mode 100644
index 000000000..802bc46e5
--- /dev/null
+++ b/meson/test cases/common/14 configure file/prog7.c
@@ -0,0 +1,10 @@
+#include <string.h>
+#include <config7.h>
+
+int main(void) {
+ return strcmp(MESSAGE1, "foo")
+ || strcmp(MESSAGE2, "${var1}")
+ || strcmp(MESSAGE3, "\\foo")
+ || strcmp(MESSAGE4, "\\${var1}")
+ || strcmp(MESSAGE5, "\\ ${ ${ \\${ \\${");
+}
diff --git a/meson/test cases/common/14 configure file/prog9.c b/meson/test cases/common/14 configure file/prog9.c
new file mode 100644
index 000000000..3f7760129
--- /dev/null
+++ b/meson/test cases/common/14 configure file/prog9.c
@@ -0,0 +1,18 @@
+#include <string.h>
+#include <config9a.h>
+#include <config9b.h>
+
+#if defined(A_UNDEFINED) || defined(B_UNDEFINED)
+#error "Should not be defined"
+#endif
+
+#if !defined(A_DEFINED) || !defined(B_DEFINED)
+#error "Should be defined"
+#endif
+
+int main(void) {
+ return strcmp(A_STRING, "foo")
+ || strcmp(B_STRING, "foo")
+ || A_INT != 42
+ || B_INT != 42;
+}
diff --git a/meson/test cases/common/14 configure file/sameafterbasename.in b/meson/test cases/common/14 configure file/sameafterbasename.in
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/meson/test cases/common/14 configure file/sameafterbasename.in
diff --git a/meson/test cases/common/14 configure file/sameafterbasename.in2 b/meson/test cases/common/14 configure file/sameafterbasename.in2
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/meson/test cases/common/14 configure file/sameafterbasename.in2
diff --git a/meson/test cases/common/14 configure file/subdir/meson.build b/meson/test cases/common/14 configure file/subdir/meson.build
new file mode 100644
index 000000000..146b7b66c
--- /dev/null
+++ b/meson/test cases/common/14 configure file/subdir/meson.build
@@ -0,0 +1,38 @@
+# Configure in subdir with absolute paths for input and relative for output
+configure_file(input : '../dummy.dat',
+ output : 'config2-1.h',
+ command : [genprog, scriptfile, ifile, 'config2-1.h'],
+ install_dir : 'share/appdireh')
+run_command(check_file, join_paths(meson.current_build_dir(), 'config2-1.h'))
+
+# Configure in subdir with files() for input and relative for output
+configure_file(input : '../dummy.dat',
+ output : 'config2-2.h',
+ command : [genprog, scriptfile, files('../dummy.dat'), 'config2-2.h'],
+ install_dir : 'share/appdirok')
+run_command(check_file, join_paths(meson.current_build_dir(), 'config2-2.h'))
+
+# Configure in subdir with string templates for input and output
+configure_file(input : '../dummy.dat',
+ output : 'config2-3.h',
+ command : [found_script, '@INPUT@', '@OUTPUT@'])
+run_command(check_file, join_paths(meson.current_build_dir(), 'config2-3.h'))
+
+# Test that overwriting an existing file creates a warning.
+configure_file(
+ input: '../test.py.in',
+ output: 'double_output2.txt',
+ configuration: conf
+)
+configure_file(
+ input: '../test.py.in',
+ output: 'double_output2.txt',
+ configuration: conf
+)
+
+# Test that the same file name in a different subdir will not create a warning
+configure_file(
+ input: '../test.py.in',
+ output: 'no_write_conflict.txt',
+ configuration: conf
+)
diff --git a/meson/test cases/common/14 configure file/test.json b/meson/test cases/common/14 configure file/test.json
new file mode 100644
index 000000000..92f7b1896
--- /dev/null
+++ b/meson/test cases/common/14 configure file/test.json
@@ -0,0 +1,8 @@
+{
+ "installed": [
+ {"type": "file", "file": "usr/share/appdir/config2.h"},
+ {"type": "file", "file": "usr/share/appdir/config2b.h"},
+ {"type": "file", "file": "usr/share/appdireh/config2-1.h"},
+ {"type": "file", "file": "usr/share/appdirok/config2-2.h"}
+ ]
+}
diff --git a/meson/test cases/common/14 configure file/test.py.in b/meson/test cases/common/14 configure file/test.py.in
new file mode 100644
index 000000000..15a61f578
--- /dev/null
+++ b/meson/test cases/common/14 configure file/test.py.in
@@ -0,0 +1,4 @@
+#!/usr/bin/env python3
+
+import sys
+sys.exit(0)
diff --git a/meson/test cases/common/14 configure file/touch.py b/meson/test cases/common/14 configure file/touch.py
new file mode 100644
index 000000000..b48f48162
--- /dev/null
+++ b/meson/test cases/common/14 configure file/touch.py
@@ -0,0 +1,16 @@
+#!/usr/bin/env python3
+
+import sys
+import argparse
+from pathlib import Path
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('files', nargs='*', type=str)
+ args = parser.parse_args()
+
+ for filepath in args.files:
+ Path(filepath).touch()
+
+if __name__ == '__main__':
+ sys.exit(main())