Add golden tests for make-binary-wrapper.
To run tests after cloning on linux, use the following: nix-build pkgs/top-level/release.nix -A tests.make-binary-wrapper.x86_64-linux
This commit is contained in:
parent
adef70ce7c
commit
b7d36b8d59
@ -35,6 +35,8 @@ with pkgs;
|
|||||||
|
|
||||||
macOSSierraShared = callPackage ./macos-sierra-shared {};
|
macOSSierraShared = callPackage ./macos-sierra-shared {};
|
||||||
|
|
||||||
|
make-binary-wrapper = callPackage ./make-binary-wrapper { inherit makeBinaryWrapper; };
|
||||||
|
|
||||||
cross = callPackage ./cross {};
|
cross = callPackage ./cross {};
|
||||||
|
|
||||||
rustCustomSysroot = callPackage ./rust-sysroot {};
|
rustCustomSysroot = callPackage ./rust-sysroot {};
|
||||||
|
23
pkgs/test/make-binary-wrapper/add-flags.c
Normal file
23
pkgs/test/make-binary-wrapper/add-flags.c
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// makeCWrapper /send/me/flags \
|
||||||
|
--add-flags "-x -y -z" \
|
||||||
|
--add-flags -abc
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
char **argv_tmp = malloc(sizeof(*argv_tmp) * (5 + argc));
|
||||||
|
argv_tmp[0] = argv[0];
|
||||||
|
argv_tmp[1] = "-x";
|
||||||
|
argv_tmp[2] = "-y";
|
||||||
|
argv_tmp[3] = "-z";
|
||||||
|
argv_tmp[4] = "-abc";
|
||||||
|
for (int i = 1; i < argc; ++i) {
|
||||||
|
argv_tmp[4 + i] = argv[i];
|
||||||
|
}
|
||||||
|
argv_tmp[4 + argc] = NULL;
|
||||||
|
argv = argv_tmp;
|
||||||
|
|
||||||
|
argv[0] = "/send/me/flags";
|
||||||
|
return execv("/send/me/flags", argv);
|
||||||
|
}
|
10
pkgs/test/make-binary-wrapper/argv0.c
Normal file
10
pkgs/test/make-binary-wrapper/argv0.c
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// makeCWrapper /path/to/some/executable \
|
||||||
|
--argv0 alternative-name
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
argv[0] = "alternative-name";
|
||||||
|
return execv("/path/to/some/executable", argv);
|
||||||
|
}
|
9
pkgs/test/make-binary-wrapper/basic.c
Normal file
9
pkgs/test/make-binary-wrapper/basic.c
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// makeCWrapper /path/to/executable
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
argv[0] = "/path/to/executable";
|
||||||
|
return execv("/path/to/executable", argv);
|
||||||
|
}
|
58
pkgs/test/make-binary-wrapper/combination.c
Normal file
58
pkgs/test/make-binary-wrapper/combination.c
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
// makeCWrapper /path/to/executable \
|
||||||
|
--argv0 my-wrapper \
|
||||||
|
--set-default MESSAGE HELLO \
|
||||||
|
--prefix PATH : /usr/bin/ \
|
||||||
|
--suffix PATH : /usr/local/bin/ \
|
||||||
|
--add-flags "-x -y -z" \
|
||||||
|
--set MESSAGE2 WORLD
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
char *concat3(char *x, char *y, char *z) {
|
||||||
|
int xn = strlen(x);
|
||||||
|
int yn = strlen(y);
|
||||||
|
int zn = strlen(z);
|
||||||
|
char *res = malloc(sizeof(*res)*(xn + yn + zn + 1));
|
||||||
|
strncpy(res, x, xn);
|
||||||
|
strncpy(res + xn, y, yn);
|
||||||
|
strncpy(res + xn + yn, z, zn);
|
||||||
|
res[xn + yn + zn] = '\0';
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_env_prefix(char *env, char *sep, char *val) {
|
||||||
|
char *existing = getenv(env);
|
||||||
|
if (existing) val = concat3(val, sep, existing);
|
||||||
|
setenv(env, val, 1);
|
||||||
|
if (existing) free(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_env_suffix(char *env, char *sep, char *val) {
|
||||||
|
char *existing = getenv(env);
|
||||||
|
if (existing) val = concat3(existing, sep, val);
|
||||||
|
setenv(env, val, 1);
|
||||||
|
if (existing) free(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
setenv("MESSAGE", "HELLO", 0);
|
||||||
|
set_env_prefix("PATH", ":", "/usr/bin/");
|
||||||
|
set_env_suffix("PATH", ":", "/usr/local/bin/");
|
||||||
|
putenv("MESSAGE2=WORLD");
|
||||||
|
|
||||||
|
char **argv_tmp = malloc(sizeof(*argv_tmp) * (4 + argc));
|
||||||
|
argv_tmp[0] = argv[0];
|
||||||
|
argv_tmp[1] = "-x";
|
||||||
|
argv_tmp[2] = "-y";
|
||||||
|
argv_tmp[3] = "-z";
|
||||||
|
for (int i = 1; i < argc; ++i) {
|
||||||
|
argv_tmp[3 + i] = argv[i];
|
||||||
|
}
|
||||||
|
argv_tmp[3 + argc] = NULL;
|
||||||
|
argv = argv_tmp;
|
||||||
|
|
||||||
|
argv[0] = "my-wrapper";
|
||||||
|
return execv("/path/to/executable", argv);
|
||||||
|
}
|
69
pkgs/test/make-binary-wrapper/default.nix
Normal file
69
pkgs/test/make-binary-wrapper/default.nix
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
{ lib, stdenv, runCommand, makeBinaryWrapper }:
|
||||||
|
|
||||||
|
let
|
||||||
|
makeGoldenTest = { name, filename }: stdenv.mkDerivation {
|
||||||
|
name = name;
|
||||||
|
dontUnpack = true;
|
||||||
|
buildInputs = [ makeBinaryWrapper ];
|
||||||
|
phases = [ "installPhase" ];
|
||||||
|
installPhase = ''
|
||||||
|
source ${./golden-test-utils.sh}
|
||||||
|
mkdir -p $out/bin
|
||||||
|
command=$(getInputCommand "${filename}")
|
||||||
|
eval "$command" > "$out/bin/result"
|
||||||
|
'';
|
||||||
|
passthru = {
|
||||||
|
assertion = ''
|
||||||
|
source ${./golden-test-utils.sh}
|
||||||
|
contents=$(getOutputText "${filename}")
|
||||||
|
echo "$contents" | diff $out/bin/result -
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
tests = {
|
||||||
|
add-flags = makeGoldenTest { name = "add-flags"; filename = ./add-flags.c; };
|
||||||
|
argv0 = makeGoldenTest { name = "argv0"; filename = ./argv0.c; };
|
||||||
|
basic = makeGoldenTest { name = "basic"; filename = ./basic.c; };
|
||||||
|
combination = makeGoldenTest { name = "combination"; filename = ./combination.c; };
|
||||||
|
env = makeGoldenTest { name = "env"; filename = ./env.c; };
|
||||||
|
prefix = makeGoldenTest { name = "prefix"; filename = ./prefix.c; };
|
||||||
|
suffix = makeGoldenTest { name = "suffix"; filename = ./suffix.c; };
|
||||||
|
};
|
||||||
|
in runCommand "make-binary-wrapper-test" {
|
||||||
|
passthru = tests;
|
||||||
|
meta.platforms = lib.platforms.all;
|
||||||
|
} ''
|
||||||
|
validate() {
|
||||||
|
local name=$1
|
||||||
|
local testout=$2
|
||||||
|
local assertion=$3
|
||||||
|
|
||||||
|
echo -n "... $name: " >&2
|
||||||
|
|
||||||
|
local rc=0
|
||||||
|
(out=$testout eval "$assertion") || rc=1
|
||||||
|
|
||||||
|
if [ "$rc" -eq 0 ]; then
|
||||||
|
echo "yes" >&2
|
||||||
|
else
|
||||||
|
echo "no" >&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
return "$rc"
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "checking whether makeCWrapper works properly... ">&2
|
||||||
|
|
||||||
|
fail=
|
||||||
|
${lib.concatStringsSep "\n" (lib.mapAttrsToList (_: test: ''
|
||||||
|
validate "${test.name}" "${test}" ${lib.escapeShellArg test.assertion} || fail=1
|
||||||
|
'') tests)}
|
||||||
|
|
||||||
|
if [ "$fail" ]; then
|
||||||
|
echo "failed"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo "succeeded"
|
||||||
|
touch $out
|
||||||
|
fi
|
||||||
|
''
|
17
pkgs/test/make-binary-wrapper/env.c
Normal file
17
pkgs/test/make-binary-wrapper/env.c
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// makeCWrapper /hello/world \
|
||||||
|
--set PART1 HELLO \
|
||||||
|
--set-default PART2 WORLD \
|
||||||
|
--unset SOME_OTHER_VARIABLE \
|
||||||
|
--set PART3 $'"!!\n"'
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
putenv("PART1=HELLO");
|
||||||
|
setenv("PART2", "WORLD", 0);
|
||||||
|
unsetenv("SOME_OTHER_VARIABLE");
|
||||||
|
putenv("PART3=\"!!\n\"");
|
||||||
|
argv[0] = "/hello/world";
|
||||||
|
return execv("/hello/world", argv);
|
||||||
|
}
|
44
pkgs/test/make-binary-wrapper/golden-test-utils.sh
Normal file
44
pkgs/test/make-binary-wrapper/golden-test-utils.sh
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Split a generated C-file into the command used to generate it,
|
||||||
|
# and the outputted code itself.
|
||||||
|
|
||||||
|
# This is useful because it allows input and output to be inside the same file
|
||||||
|
|
||||||
|
# How it works:
|
||||||
|
# - The first line needs to start with '//' (and becomes the command).
|
||||||
|
# - Whitespace/padding between the comment and the generated code is ignored
|
||||||
|
# - To write a command using multiple lines, end each line with backslash (\)
|
||||||
|
|
||||||
|
# Count the number of lines before the output text starts
|
||||||
|
# commandLineCount FILE
|
||||||
|
commandLineCount() {
|
||||||
|
local n state
|
||||||
|
n=0
|
||||||
|
state="init"
|
||||||
|
while IFS="" read -r p || [ -n "$p" ]; do
|
||||||
|
case $state in
|
||||||
|
init)
|
||||||
|
if [[ $p =~ ^//.*\\$ ]]; then state="comment"
|
||||||
|
elif [[ $p =~ ^//.* ]]; then state="padding"
|
||||||
|
else break
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
comment) [[ ! $p =~ ^.*\\$ ]] && state="padding";;
|
||||||
|
padding) [ -n "${p// }" ] && break;;
|
||||||
|
esac
|
||||||
|
n=$((n+1))
|
||||||
|
done < "$1"
|
||||||
|
printf '%s' "$n"
|
||||||
|
}
|
||||||
|
|
||||||
|
# getInputCommand FILE
|
||||||
|
getInputCommand() {
|
||||||
|
n=$(commandLineCount "$1")
|
||||||
|
head -n "$n" "$1" | awk '{ if (NR == 1) print substr($0, 3); else print $0 }'
|
||||||
|
}
|
||||||
|
|
||||||
|
# getOutputText FILE
|
||||||
|
getOutputText() {
|
||||||
|
n=$(commandLineCount "$1")
|
||||||
|
sed "1,${n}d" "$1"
|
||||||
|
}
|
33
pkgs/test/make-binary-wrapper/prefix.c
Normal file
33
pkgs/test/make-binary-wrapper/prefix.c
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// makeCWrapper /path/to/executable \
|
||||||
|
--prefix PATH : /usr/bin/ \
|
||||||
|
--prefix PATH : /usr/local/bin/
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
char *concat3(char *x, char *y, char *z) {
|
||||||
|
int xn = strlen(x);
|
||||||
|
int yn = strlen(y);
|
||||||
|
int zn = strlen(z);
|
||||||
|
char *res = malloc(sizeof(*res)*(xn + yn + zn + 1));
|
||||||
|
strncpy(res, x, xn);
|
||||||
|
strncpy(res + xn, y, yn);
|
||||||
|
strncpy(res + xn + yn, z, zn);
|
||||||
|
res[xn + yn + zn] = '\0';
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_env_prefix(char *env, char *sep, char *val) {
|
||||||
|
char *existing = getenv(env);
|
||||||
|
if (existing) val = concat3(val, sep, existing);
|
||||||
|
setenv(env, val, 1);
|
||||||
|
if (existing) free(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
set_env_prefix("PATH", ":", "/usr/bin/");
|
||||||
|
set_env_prefix("PATH", ":", "/usr/local/bin/");
|
||||||
|
argv[0] = "/path/to/executable";
|
||||||
|
return execv("/path/to/executable", argv);
|
||||||
|
}
|
33
pkgs/test/make-binary-wrapper/suffix.c
Normal file
33
pkgs/test/make-binary-wrapper/suffix.c
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// makeCWrapper /path/to/executable \
|
||||||
|
--suffix PATH : /usr/bin/ \
|
||||||
|
--suffix PATH : /usr/local/bin/
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
char *concat3(char *x, char *y, char *z) {
|
||||||
|
int xn = strlen(x);
|
||||||
|
int yn = strlen(y);
|
||||||
|
int zn = strlen(z);
|
||||||
|
char *res = malloc(sizeof(*res)*(xn + yn + zn + 1));
|
||||||
|
strncpy(res, x, xn);
|
||||||
|
strncpy(res + xn, y, yn);
|
||||||
|
strncpy(res + xn + yn, z, zn);
|
||||||
|
res[xn + yn + zn] = '\0';
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_env_suffix(char *env, char *sep, char *val) {
|
||||||
|
char *existing = getenv(env);
|
||||||
|
if (existing) val = concat3(existing, sep, val);
|
||||||
|
setenv(env, val, 1);
|
||||||
|
if (existing) free(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
set_env_suffix("PATH", ":", "/usr/bin/");
|
||||||
|
set_env_suffix("PATH", ":", "/usr/local/bin/");
|
||||||
|
argv[0] = "/path/to/executable";
|
||||||
|
return execv("/path/to/executable", argv);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user