Skip to content

Commit

Permalink
Add read-only and copiers.
Browse files Browse the repository at this point in the history
  • Loading branch information
dillof committed Jan 3, 2024
1 parent b58f9b4 commit 42aa85f
Show file tree
Hide file tree
Showing 17 changed files with 209 additions and 10 deletions.
32 changes: 32 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# base settings
BasedOnStyle: LLVM
IndentWidth: 4
ColumnLimit: 120
# details
# AlignArrayOfStructures: Left # Disable for now, crashes current clang-format.
AlignEscapedNewlines: Left
AllowAllConstructorInitializersOnNextLine: true
AllowShortBlocksOnASingleLine: Never
AlwaysBreakAfterReturnType: None
#BinPackArguments: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
BreakBeforeBraces: Custom
BraceWrapping:
BeforeElse: true
BeforeCatch: true
KeepEmptyLinesAtTheStartOfBlocks: false
MaxEmptyLinesToKeep: 2
# clang 14+:
#PackConstructorInitializers: NextLine
PointerAlignment: Left
UseTab: Never
#IncludeIsMainRegex: "$"
IncludeCategories:
- Regex: '^"config.h"'
Priority: 1
- Regex: '^"compat.h"'
Priority: 2
- Regex: '^<'
Priority: 3
- Regex: '.*'
Priority: 4
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.12)

# Also update version in nihtest/__main__.py and pyproject.toml
project(nihtest
VERSION 1.3.0
VERSION 1.4.0
DESCRIPTION "NiH testing framework"
HOMEPAGE_URL "https://github.com/nih-at/nihtest"
LANGUAGES C)
Expand Down
4 changes: 3 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# 1.4.0 [Unreleased]
# 1.4.0 [2024-01-03]

- Add copiers.
- Add `working-directory` directive.
- Add `read-only` directive.

# 1.3.0 [2023-12-22]

Expand Down
1 change: 1 addition & 0 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
- Add test for `read-only`.
- Include documentation in binary distribution.
- Allow running on multiple tests.
- Allow quotes in `description`.
4 changes: 4 additions & 0 deletions manpages/nihtest-case.mdoc
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,10 @@ If this directive is omitted,
from
.Pa nihtest.conf
is run.
.It Ic read-only Ar name
The file or directory
.Ar name
will be made read-only.
.It Ic return Ar exit-code
.Ar exit-code
is the expected exit code (usually 0 on success).
Expand Down
21 changes: 21 additions & 0 deletions manpages/nihtest.conf.mdoc
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,27 @@ and the test case containing
the command
.Dl zipcmp -v got.zip expected.zip
will be run to compare the files.
.Sh COMPARATOR-PREPROCESSORS
The
.Ic comparator-preprocessors
section specifies programs to use to preprocess certain file types for comparison.
The variable names have the format
.Ar got-extension . expected-extension ,
the value specifies the command line to use to preprocess the file in the sandbox.
The command will be run with the file in the sandbox first as argument.
The command's output will be compared to the expected file.
.Pp
If the command doesn't exit with code 0, the test will fail.
.Sh COPIERS
The
.Ic copiers
section specifies programs to use to copy certain file types into the sandbox.
The variable names have the format
.Ar sandbox-extension . source-extension ,
the value specifies the command line to use to copy the file into the sandbox.
The command will be run with the two files as arguments, the source file first and the file in the sandbox last.
.Pp
If the command doesn't exit with code 0, the test will fail.
.Sh EXAMPLES
.Bd -literal
[settings]
Expand Down
5 changes: 4 additions & 1 deletion nihtest/Configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

config_schema = {
"comparators": True,
# "copiers": True,
"copiers": True,
"comparator-preprocessors": True,
"environment": True,
"settings": [
Expand Down Expand Up @@ -126,6 +126,7 @@ def __init__(self, args):
self.test_input_directories = get_array(settings, "test-input-directories")
self.comparator_preprocessors = get_section(config, "comparator-preprocessors")
self.comparators = get_section(config, "comparators")
self.copiers = get_section(config, "copiers")
self.environment = get_section(config, "environment")
self.environment_clear = get_boolean(settings, "environment-clear", False)
self.environment_passthrough = get_array(settings, "environment-passthrough")
Expand All @@ -134,6 +135,8 @@ def __init__(self, args):
self.run_test = True

self.default_stderr_replace = list(map(process_stderr_replace, self.default_stderr_replace))
for key, value in self.copiers.items():
self.copiers[key] = shlex.split(value)
for key, value in self.comparators.items():
self.comparators[key] = shlex.split(value)
for key, value in self.comparator_preprocessors.items():
Expand Down
24 changes: 21 additions & 3 deletions nihtest/File.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import os
import pathlib
import re
import shutil

from nihtest import Command
from nihtest import Environment
from nihtest import Configuration
from nihtest import Utility

sandbox = re.compile("@SANDBOX@")

class Data:
def __init__(self, file_name, data=None):
Expand All @@ -20,11 +22,14 @@ def __init__(self, name, input=None, result=None):
self.input = input
self.result = result

def file_name(self, directory):
return sandbox.sub(directory, self.name)

def compare(self, configuration, directory):
if not self.result:
return True

input_file_name = os.path.join(directory, self.name)
input_file_name = os.path.join(directory, self.file_name(directory))
output_is_binary = False

file_extension = pathlib.Path(self.name).suffix[1:]
Expand Down Expand Up @@ -90,11 +95,24 @@ def compare(self, configuration, directory):

def prepare(self, configuration, directory):
if self.input:
output_file_name = os.path.join(directory, self.name)
output_file_name = os.path.join(directory, self.file_name(directory))
os.makedirs(os.path.dirname(output_file_name), 0o777, True)
if self.input.data is None:
input_file_name = configuration.find_input_file(self.input.file_name)
shutil.copyfile(input_file_name, output_file_name)
file_extension = pathlib.Path(self.name).suffix[1:]
output_extension = pathlib.Path(self.input.file_name).suffix[1:]
key = f"{file_extension}.{output_extension}"
if key in configuration.copiers:
copier = configuration.copiers[key]
program = configuration.find_program(copier[0])
arguments = copier[1:] + [input_file_name, output_file_name]
command = Command.Command(program, arguments, environment=Environment.Environment(configuration).environment)
command.run()
if command.exit_code != 0:
print("\n".join(command.stderr))
raise RuntimeError(f"can't prepare '{self.name}'")
else:
shutil.copyfile(input_file_name, output_file_name)
else:
with open(output_file_name, "w", encoding='utf-8') as file:
Utility.write_lines(file, self.input.data)
14 changes: 13 additions & 1 deletion nihtest/Test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import os
import platform
import re
import stat
import sys

from nihtest import Command
Expand Down Expand Up @@ -72,6 +73,11 @@ def run(self):
if not self.case.configuration.run_test:
return TestResult.OK

for file in self.case.read_only:
full_file = os.path.join(self.sandbox.directory, file)
st = os.stat(full_file)
os.chmod(full_file, st.st_mode & ~(stat.S_IWUSR))

self.sandbox.enter()
program = self.case.configuration.find_program(self.case.program)
environment = Environment.Environment(self.case).environment
Expand All @@ -87,14 +93,20 @@ def run(self):
files_got = self.list_files()
self.sandbox.leave()

for file in self.case.read_only:
full_file = os.path.join(self.sandbox.directory, file)
if os.path.exists(full_file):
st = os.stat(full_file)
os.chmod(full_file, st.st_mode | stat.S_IWRITE)

self.compare("exit code", [str(self.case.exit_code)], [str(command.exit_code)])
self.compare("output", self.case.stdout, command.stdout)
self.compare("error output", self.case.stderr, self.process_stderr(command.stderr))

files_expected = []
for file in self.case.files:
if file.result:
files_expected.append(file.name)
files_expected.append(file.file_name(self.sandbox.directory))

self.compare("file list", sorted(files_expected), sorted(files_got))

Expand Down
6 changes: 6 additions & 0 deletions nihtest/TestCase.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ def __init__(self, configuration, args):
self.preload = []
self.program = configuration.default_program
self.exit_code = 0
self.read_only = []
self.stderr = []
self.stderr_replace = []
self.stdin = []
Expand Down Expand Up @@ -175,6 +176,8 @@ def directive_preload(self, arguments):
def directive_program(self, arguments):
self.program = arguments[0]

def directive_read_only(self, arguments):
self.read_only.append(arguments[0])
def directive_return(self, arguments):
self.exit_code = int(arguments[0]) # TODO: error check?

Expand Down Expand Up @@ -242,6 +245,9 @@ def directive_working_directory(self, arguments):
usage="name",
minimum_arguments=1,
only_once=True),
"read-only": Directive(method=directive_read_only,
usage="name",
minimum_arguments=1),
"return": Directive(method=directive_return,
usage="exit-code",
minimum_arguments=1,
Expand Down
2 changes: 1 addition & 1 deletion nihtest/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from nihtest import Test
from nihtest import Configuration

VERSION = "1.3.0"
VERSION = "1.4.0"


def main():
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "nihtest"
version = "1.3.0"
version = "1.4.0"
authors = [
{ name="Dieter Baron", email="dillo@nih.at" },
{ name="Thomas Klausner", email="wiz@gatalith.at"}
Expand All @@ -30,7 +30,7 @@ dependencies = [
nihtest = "nihtest.__main__:main"

[tool.bumpver]
current_version = "1.3.0"
current_version = "1.4.0"
version_pattern = "MAJOR.MINOR.PATCH"

[tool.bumpver.file_patterns]
Expand Down
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ set(TEST_PROGRAMS
cat
getenv
file
uppercase
)

foreach(PROGRAM ${TEST_PROGRAMS})
Expand Down
6 changes: 6 additions & 0 deletions tests/copier.input
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
program nihtest-true
arguments
return 0
file test.uc test.lc <inline>
LOWERCASE TEXT
end-of-inline-data
8 changes: 8 additions & 0 deletions tests/copier.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
program nihtest
arguments test.test
return 0
file test.test copier.input
file nihtest.conf nihtest-conf
file test.lc <inline>
lowercase text
end-of-inline-data
3 changes: 3 additions & 0 deletions tests/nihtest-conf.in
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,6 @@ fail.fail = nihtest-comparator 1
[comparator-preprocessors]
true.txt = nihtest-true -v
cat.txt = nihtest-cat

[copiers]
uc.lc = nihtest-uppercase
82 changes: 82 additions & 0 deletions tests/uppercase.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
uppercase.c --
Copyright (C) Dieter Baron
The authors can be contacted at <assembler@tpau.group>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. The names of the authors may not be used to endorse or promote
products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[]) {
if (argc != 3) {
fprintf(stderr, "usage: %s: input output\n", argv[0]);
}

FILE *in = fopen(argv[1], "r");
if (in == NULL) {
fprintf(stderr, "%s: can't open '%s': %s\n", argv[0], argv[1], strerror(errno));
exit(1);
}

FILE *out = fopen(argv[2], "w");
if (out == NULL) {
fprintf(stderr, "%s: can't create '%s': %s\n", argv[0], argv[2], strerror(errno));
exit(1);
}

unsigned char buf[512];
size_t n;

while (((n=fread(buf, 1, sizeof(buf), in))) > 0) {
for (size_t i=0; i < n; i++) {
if (islower(buf[i])) {
buf[i] = toupper(buf[i]);
}
}
if (fwrite(buf, 1, n, out) != n) {
fprintf(stderr, "%s: can't write to '%s': %s\n", argv[0], argv[2], strerror(errno));
exit(1);
}
}

if (ferror(in)) {
fprintf(stderr, "%s: can't read from '%s': %s\n", argv[0], argv[1], strerror(errno));
exit(1);
}
fclose(in);

if (fclose(out) != 0) {
fprintf(stderr, "%s: can't write to '%s': %s\n", argv[0], argv[2], strerror(errno));
exit(1);
}

exit(0);
}

0 comments on commit 42aa85f

Please sign in to comment.