Merge branch '3730_extfs_tester'

* 3730_extfs_tester:
  tests/src/vfs/extfs/helpers-list/Makefile.am: create run silently.
  Move extfs tester from tests/src/extfs-helpers-listcmd into tests/src/vfs/extfs/helpers-list.
  extfs: lslR: add tests.
  extfs: lslR: make it testable.
  extfs: urar: add tests.
  extfs: urar: make it testable.
  extfs: uzip: add tests.
  extfs: uzip: make it testable.
  extfs: uzoo: add tests.
  extfs: uzoo: make it testable.
  extfs: documentation for the tester.
  extfs: introduce a tester.
  Ticket #3730: extfs: introduce a command-line tool for parsing file lists.
This commit is contained in:
Andrew Borodin 2016-12-19 13:18:07 +03:00
commit 3a25b7198f
45 changed files with 1627 additions and 4 deletions

View File

@ -638,6 +638,9 @@ tests/src/Makefile
tests/src/filemanager/Makefile
tests/src/editor/Makefile
tests/src/editor/test-data.txt
tests/src/vfs/Makefile
tests/src/vfs/extfs/Makefile
tests/src/vfs/extfs/helpers-list/Makefile
])
fi

View File

@ -23,6 +23,8 @@ case "$1" in
*) MYCAT="cat";;
esac
MYCAT=${MC_TEST_EXTFS_LIST_CMD:-$MYCAT} # Let the test framework hook in.
$MYCAT "$1" | $AWK '
BEGIN {
dir="";

View File

@ -24,6 +24,10 @@ UNRAR=`which unrar 2>/dev/null`
# Define $UNRAR version
UNRAR_VERSION=`$UNRAR -cfg- -? | grep "Copyright" | sed -e 's/.*\([0-9]\)\..*/\1/'`
# Let the test framework hook in:
UNRAR=${MC_TEST_EXTFS_LIST_CMD:-$UNRAR}
UNRAR_VERSION=${MC_TEST_EXTFS_UNRAR_VERSION:-$UNRAR_VERSION}
mcrar4fs_list ()
{
$UNRAR v -c- -cfg- "$1" | @AWK@ -v uid=`id -u` -v gid=`id -g` '

View File

@ -17,9 +17,9 @@ use strict;
# Location of the zip program
my $app_zip = "@ZIP@";
# Location of the unzip program
my $app_unzip = "@UNZIP@";
my $app_unzip = $ENV{MC_TEST_EXTFS_LIST_CMD} || "@UNZIP@";
# Set this to 1 if zipinfo (unzip -Z) is to be used (recommended), otherwise 0.
my $op_has_zipinfo = @HAVE_ZIPINFO@;
my $op_has_zipinfo = exists($ENV{MC_TEST_EXTFS_HAVE_ZIPINFO}) ? $ENV{MC_TEST_EXTFS_HAVE_ZIPINFO} : @HAVE_ZIPINFO@;
# Command used to list archives (zipinfo mode)
my $cmd_list_zi = "$app_unzip -Z -l -T";

View File

@ -5,7 +5,7 @@
# Source of zoo can be found at
# ftp://ftp.ibiblio.org/pub/Linux/utils/compress/
ZOO=zoo
ZOO=${MC_TEST_EXTFS_LIST_CMD:-zoo}
# Stupid zoo won't work if the archive name has no .zoo extension, so we
# have to make a symlink with a "better" name. Also, zoo can create

View File

@ -1,6 +1,6 @@
PACKAGE_STRING = "/src"
SUBDIRS = . filemanager
SUBDIRS = . filemanager vfs
if USE_INTERNAL_EDIT
SUBDIRS += editor

View File

@ -0,0 +1,2 @@
SUBDIRS = extfs

View File

@ -0,0 +1,2 @@
SUBDIRS = helpers-list

View File

@ -0,0 +1,91 @@
PACKAGE_STRING = "/src/vfs/extfs/helpers-list"
AM_CPPFLAGS = $(GLIB_CFLAGS) -I$(top_srcdir)
# This lets mc_parse_ls_l.c override MC's message() without the linker
# complaining about multiple definitions.
AM_LDFLAGS = @TESTS_LDFLAGS@
LIBS = $(top_builddir)/lib/libmc.la
# Programs/scripts to build on 'make check'.
check_PROGRAMS = mc_parse_ls_l
check_SCRIPTS = run
# Tests to run on 'make check'
TESTS = run
# On 'make clean', delete 'run' as well.
CLEANFILES = run
mc_parse_ls_l_SOURCES = \
mc_parse_ls_l.c
data_files_to_distribute = \
data/lslR.1.spaces.args \
data/lslR.1.spaces.input \
data/lslR.1.spaces.output \
data/lslR.2.spaces-iso.args \
data/lslR.2.spaces-iso.input \
data/lslR.2.spaces-iso.output \
data/lslR.3.spaces-iso-noslash.args \
data/lslR.3.spaces-iso-noslash.input \
data/lslR.3.spaces-iso-noslash.output \
data/lslR.README \
data/urar.README \
data/urar.v4,v3.env_vars \
data/urar.v4,v3.input \
data/urar.v4,v3.output \
data/urar.v5.env_vars \
data/urar.v5.input \
data/urar.v5.output \
data/uzip.README \
data/uzip.with-zipinfo.env_vars \
data/uzip.with-zipinfo.input \
data/uzip.with-zipinfo.output \
data/uzip.without-zipinfo--mdy.env_vars \
data/uzip.without-zipinfo--mdy.input \
data/uzip.without-zipinfo--mdy.output \
data/uzip.without-zipinfo--ymd.env_vars \
data/uzip.without-zipinfo--ymd.input \
data/uzip.without-zipinfo--ymd.output \
data/uzoo.README \
data/uzoo.input \
data/uzoo.output \
data/dummy
EXTRA_DIST = mc_xcat test_all $(data_files_to_distribute)
run:
@echo '#!/bin/sh' > $@
@echo >> $@
@echo '# This script is an easy way to launch the "test_all" script' >> $@
@echo '# with all the required arguments.' >> $@
@echo '#' >> $@
@echo '# Run this script with "--help" to learn more.' >> $@
@echo >> $@
@echo '# Where to find mc_parse_ls_l and mc_xcat, respectively.' >> $@
@echo 'PATH="$(abs_builddir):$(abs_srcdir):$$PATH"' >> $@
@echo >> $@
# The 'abs_' isn't mandatory. It lets you move this script out of the build tree.
@echo '"$(abs_srcdir)"/test_all "$$@" \' >> $@
@echo ' --data-dir "$(abs_srcdir)/data" \' >> $@
# Before installation, some helpers are in the build tree, some in the src tree.
@echo ' --helpers-dir "$(abs_top_builddir)/src/vfs/extfs/helpers" \' >> $@
@echo ' --helpers-dir "$(abs_top_srcdir)/src/vfs/extfs/helpers"' >> $@
@chmod +x $@
# (We can alternatively create run from a run.in template
# with 'AC_CONFIG_FILES[run, chmod +x run]'.)
#
# Documentation
#
doc: README.html
# (Thanks to VPATH we don't need to write "$(srcdir)/README". doc/hlp/Makefile.am needlessly does this.)
README.html: README
pandoc --include-in-header=$(srcdir)/README.css.inc -N --old-dashes --toc --standalone -o $@ $<
EXTRA_DIST += README.css.inc
CLEANFILES += README.html

View File

@ -0,0 +1,171 @@
---
title: A tester for extfs helpers
...
Guide
=====
Introduction
------------
The extfs filesystem is composed of various helpers (uzip, urar, uarc,
...). One command every helper must answer to is "list", to list the
files on its filesystem.
The purpose of this tester is to test this "list" facet of every helper
to ensure that it indeed works, at present, and that we won't
inadvertently break it, in the future, as we modify its code or MC's
code.
Key concept: Inputs
-------------------
Most helpers work by parsing the output of some 3'rd party software.
Which for them becomes the *input*. Helpers sometimes support **several
variations** of such input. E.g., the uzip helper supports three
variations.
The tester keeps a repository, in the data folder, of the various inputs
each helper proclaims to support. Each input is stored in a file with an
`.input` suffix.
Key concept: Outputs
--------------------
Along with each input file, the data folder also holds the output the
helper is expected to produce given the corresponding input. Each output
is stored in a file with an `.output` suffix.
We call this output "the expected output".
Incidentally, an `.output` file stores not the _raw_ output of the helper
but its output _after parsing_. In other words, what's stored is the
unambiguous _meaning_ of the helper's output. This means that as long as
the helper's code isn't modified in a way that changes the meaning of its
output, the `.output` file remains up-to-date.
How the tester works
--------------------
The tester feeds each helper its prepared inputs and reads back the
helper's "list" answer -- the helper's **output**. This output is a list
of files in a format similar to `ls -l`, which MC is able to parse. The
tester checks that this output parses without errors (errors are, for
example, dates in unsupported format). It then compares this parsed
output (which we call "the actual output") with a previously saved copy
of this output which is known to be correct (and which we call "the
expected output", mentioned in the previous section). This previously
stored output too is in the data folder, in files with `.output` suffix.
If there's any discrepancy between the *actual output* and the
*expected output*, the test fails.
Running the tester
------------------
You can run the tester with `make check`.
But you'll find it more appealing to run the tester with the `run`
script. You'll get a colorful description of what's going on.
(`run` is created by running `make check` for the 1st time, in the build
tree.)
Reference
=========
The data folder
---------------
There are several types of files in the data folder:
### Input file ###
An input file is named:
> `<helper-name>[.optional-embedded-description].input`
You create such files simply by redirecting the 3'rd party software's
output to a file.
### Output file ###
This file is named the same as the corresponding input file but with an
`.output` suffix.
The easiest way to create these files is by invoking the `run` script
with the `--create-output` option.
### Environment file ###
Optional. This file defines environment variables the helper may use to
determine the variant of the input. This file is named the same as the
corresponding input file but with an `.env_var` suffix.
### Arguments file ###
Optional. This file defines extra command-line options to pass to the
[parser](#mc_parse_ls_l). This file is named the same as the
corresponding input file but with an `.args` suffix.
The contents of an output file must be the same no matter on what
computer and at what time we generate it. Therefore we need to tell the
parser to drop any non-fixed elements in that file. E.g., if the dates
used are relative (as is the case for the default `ls` dates), we need to
drop them with `--drop-mtime`. Similarly, if a helper returns user and
group _names_ that are different than the running user's, they must be
dropped with `--drop-ids`.
### Other files ###
Any other file is ignored by the tester.
mc_parse_ls_l
-------------
This program (built with `make check`) is at the heart of the tester
mechanism. It parses a list of files, in a format similar to `ls -l`,
just as MC would. This program is used to parse (and thereby verify) the
output of the helpers. _You don't need to invoke it yourself;_ but, for
educational purpose, here are a few examples:
$ LC_ALL=C ls -l | ./mc_parse_ls_l
$ LC_ALL=C ls -l | ./mc_parse_ls_l --symbolic-ids
$ LC_ALL=C ls -l | ./mc_parse_ls_l --output-format yaml
test_all
--------
This is the tester itself. You invoke it with `make check`, or with the
`run` script. Invoking it directly is a bit involving because you need to
provide it with 2 or 3 directory paths. `run` does this work for you.
MC_TEST_EXTFS_LIST_CMD
----------------------
When a helper runs under the tester, the environment variable
`MC_TEST_EXTFS_LIST_CMD` holds the command that's to provide input. The
helper's source code must be modified to use this command instead of the
command it usually uses. This is the device which lets us plug our own
input into the helper and *without which a helper can't be tested!*
Let's have a little example. The uzoo helper originally has:
ZOO=zoo
...
mczoofs_list () {
$ZOO lq "$ARCHIVE" | mawk '......'
}
...
To make this helper testable, we need to change the first line to:
ZOO=${MC_TEST_EXTFS_LIST_CMD:-zoo}
(or equivalent.)
The command in `MC_TEST_EXTFS_LIST_CMD` is a black-box for the helper,
and it intentionally ignores any arguments passed to it (so that `lq
"$ARCHIVE"`, above, won't cause problems).

View File

@ -0,0 +1,19 @@
<style type="text/css">
body {
padding: 1em 2.5em;
line-height: 140%;
}
code, pre {
background-color: #FFB;
padding: 2px 3px;
}
h1, h2 { text-indent: -0.5em; }
h1, h2, h3 {
color: #005A9C;
font-family: sans-serif;
}
</style>

View File

@ -0,0 +1,3 @@
This is a dummy file meant to ensure this directory isn't empty so that git always creates it.
Otherwise our 'test_all' script will fail complaining the directory doesn't exist.

View File

@ -0,0 +1 @@
--drop-ids --drop-mtime

View File

@ -0,0 +1,23 @@
.:
total 12
drwxr-xr-x 3 serhiy serhiy 4096 Dec 29 19:12 1 2
drwxr-xr-x 2 serhiy serhiy 4096 Dec 29 19:08 1 2
drwxr-xr-x 2 serhiy serhiy 4096 Dec 29 19:12 1 2
./ 1 2:
total 4
-rw-r--r-- 1 serhiy serhiy 0 Dec 29 19:08 b
drwxr-xr-x 2 serhiy serhiy 4096 Dec 29 19:12 z
./ 1 2/z:
total 0
./1 2:
total 0
-rw-r--r-- 1 serhiy serhiy 0 Dec 29 19:08 a
./1 2 :
total 0
-rw-r--r-- 1 serhiy serhiy 0 Dec 29 19:09 d
-rw-r--r-- 1 serhiy serhiy 0 Dec 29 19:08 c
-rw-r--r-- 1 serhiy serhiy 0 Dec 29 19:09 x:

View File

@ -0,0 +1,9 @@
drwxr-xr-x 3 4096 ./ 1 2
drwxr-xr-x 2 4096 ./1 2
drwxr-xr-x 2 4096 ./1 2
-rw-r--r-- 1 0 ./ 1 2/b
drwxr-xr-x 2 4096 ./ 1 2/z
-rw-r--r-- 1 0 ./1 2/a
-rw-r--r-- 1 0 ./1 2 / d
-rw-r--r-- 1 0 ./1 2 /c
-rw-r--r-- 1 0 ./1 2 /x:

View File

@ -0,0 +1 @@
--drop-ids

View File

@ -0,0 +1,23 @@
.:
total 12
drwxr-xr-x 3 serhiy serhiy 4096 2009-12-29 19:12 1 2
drwxr-xr-x 2 serhiy serhiy 4096 2009-12-29 19:08 1 2
drwxr-xr-x 2 serhiy serhiy 4096 2009-12-29 19:12 1 2
./ 1 2:
total 4
-rw-r--r-- 1 serhiy serhiy 0 2009-12-29 19:08 b
drwxr-xr-x 2 serhiy serhiy 4096 2009-12-29 19:12 z
./ 1 2/z:
total 0
./1 2:
total 0
-rw-r--r-- 1 serhiy serhiy 0 2009-12-29 19:08 a
./1 2 :
total 0
-rw-r--r-- 1 serhiy serhiy 0 2009-12-29 19:08 c
-rw-r--r-- 1 serhiy serhiy 0 2009-12-29 19:09 d
-rw-r--r-- 1 serhiy serhiy 0 2009-12-29 19:09 x:

View File

@ -0,0 +1,9 @@
drwxr-xr-x 3 4096 2009-12-29 19:12:00 ./ 1 2
drwxr-xr-x 2 4096 2009-12-29 19:08:00 ./1 2
drwxr-xr-x 2 4096 2009-12-29 19:12:00 ./1 2
-rw-r--r-- 1 0 2009-12-29 19:08:00 ./ 1 2/b
drwxr-xr-x 2 4096 2009-12-29 19:12:00 ./ 1 2/z
-rw-r--r-- 1 0 2009-12-29 19:08:00 ./1 2/a
-rw-r--r-- 1 0 2009-12-29 19:08:00 ./1 2 /c
-rw-r--r-- 1 0 2009-12-29 19:09:00 ./1 2 / d
-rw-r--r-- 1 0 2009-12-29 19:09:00 ./1 2 /x:

View File

@ -0,0 +1 @@
--drop-ids

View File

@ -0,0 +1,17 @@
1 2:
total 4
-rw-r--r-- 1 serhiy serhiy 0 2009-12-29 19:08 b
drwxr-xr-x 2 serhiy serhiy 4096 2009-12-29 19:12 z
1 2/z:
total 0
1 2:
total 0
-rw-r--r-- 1 serhiy serhiy 0 2009-12-29 19:08 a
1 2 :
total 0
-rw-r--r-- 1 serhiy serhiy 0 2009-12-29 19:08 c
-rw-r--r-- 1 serhiy serhiy 0 2009-12-29 19:09 d
-rw-r--r-- 1 serhiy serhiy 0 2009-12-29 19:09 x:

View File

@ -0,0 +1,6 @@
-rw-r--r-- 1 0 2009-12-29 19:08:00 ./ 1 2/b
drwxr-xr-x 2 4096 2009-12-29 19:12:00 ./ 1 2/z
-rw-r--r-- 1 0 2009-12-29 19:08:00 1 2/a
-rw-r--r-- 1 0 2009-12-29 19:08:00 1 2 /c
-rw-r--r-- 1 0 2009-12-29 19:09:00 1 2 / d
-rw-r--r-- 1 0 2009-12-29 19:09:00 1 2 /x:

View File

@ -0,0 +1,26 @@
The inputs were taken from:
http://www.midnight-commander.org/ticket/1921
These inputs are supposed to cover:
- "spaces": spaces in dir/file names.
- "iso": ISO date. The ticket claims this is enabled in en_US.UTF-8
locale, but that's untrue. Nevertheless, it's a useful format (the
default 'ls' dates are relative and therefore somewhat useless in lslR
files) so we don't mind covering it here.
- "noshalsh": directories not starting with "./".
Argument files:
The output produced must be constant anytime. Therefore:
- For the one input using non-ISO date we must use --drop-mtime.
Otherwise, because these are relative dates, next year the output
will show a different year.
- For all inputs we use --drop-ids for the case we have user "serhiy" on
our system (and we aren't running as that user).

View File

@ -0,0 +1,17 @@
The archive was created thus:
echo hello > 'filename with spaces.txt'
rar a archive.rar 'filename with spaces.txt' ...
Our 'urar' supports two listing formats: that of version 5, and that of
version 4.
'urar.v5.input' was created with "unrar vt -c- -cfg- archive.rar" using
unrar 5.30.
'urar.v4,v3.input' was created with "unrar v -c- -cfg- archive.rar" using
unrar 3.80 for DOS (google "unrar dos"), via DOSBox (and then the "\" was
changed to "/" by hand). An inspection of our urar's source code should
lead us to conclude that this format is compatible with that of version
4.

View File

@ -0,0 +1 @@
MC_TEST_EXTFS_UNRAR_VERSION=4

View File

@ -0,0 +1,29 @@
UNRAR 3.80 freeware Copyright (c) 1993-2008 Alexander Roshal
Archive ARCHIVE.RAR
Pathname/Comment
Size Packed Ratio Date Time Attr CRC Meth Ver
-------------------------------------------------------------------------------
.viminfo
11032 2468 22% 23-11-16 07:10 -rw------- 295ED9AB m3g 2.9
.wget-hsts
205 181 88% 26-10-16 13:14 -rw-rw-r-- 58429CA4 m3g 2.9
.xboardrc
7527 2964 39% 17-04-16 01:21 -rw-rw-r-- 1DA6AD04 m3g 2.9
.xchm
559 382 68% 29-09-16 01:08 -rw-rw-r-- 73DBF2B9 m3g 2.9
.xinputrc
130 123 94% 27-12-15 17:08 -rw-rw-r-- 70CD8EF3 m3g 2.9
.dosbox/dosbox-0.74.conf
10730 4005 37% 07-06-16 20:43 -rw-rw-r-- 1D5A9AA6 m3g 2.9
log.txt
5869937 42114 0% 23-11-16 07:43 -rw-rw-r-- E63DE4A6 m3g 2.9
filename with spaces.txt
6 16 266% 23-11-16 07:39 -rw-r--r-- 363A3020 m3g 2.9
.dosbox
0 0 0% 07-06-16 20:43 drwx------ 00000000 m0 2.0
-------------------------------------------------------------------------------
9 5900126 52253 0%

View File

@ -0,0 +1,9 @@
drwx------ 1 <<uid>> <<gid>> 0 2016-06-07 20:43:00 ./.dosbox
-rw-rw-r-- 1 <<uid>> <<gid>> 10730 2016-06-07 20:43:00 ./.dosbox/dosbox-0.74.conf
-rw-r--r-- 1 <<uid>> <<gid>> 6 2016-11-23 07:39:00 ./filename with spaces.txt
-rw-rw-r-- 1 <<uid>> <<gid>> 5869937 2016-11-23 07:43:00 ./log.txt
-rw------- 1 <<uid>> <<gid>> 11032 2016-11-23 07:10:00 ./.viminfo
-rw-rw-r-- 1 <<uid>> <<gid>> 205 2016-10-26 13:14:00 ./.wget-hsts
-rw-rw-r-- 1 <<uid>> <<gid>> 7527 2016-04-17 01:21:00 ./.xboardrc
-rw-rw-r-- 1 <<uid>> <<gid>> 559 2016-09-29 01:08:00 ./.xchm
-rw-rw-r-- 1 <<uid>> <<gid>> 130 2015-12-27 17:08:00 ./.xinputrc

View File

@ -0,0 +1 @@
MC_TEST_EXTFS_UNRAR_VERSION=5

View File

@ -0,0 +1,102 @@
UNRAR 5.30 beta 2 freeware Copyright (c) 1993-2015 Alexander Roshal
Archive: archive.rar
Details: RAR 4
Name: .viminfo
Type: File
Size: 11032
Packed size: 2468
Ratio: 22%
mtime: 2016-11-23 07:10:39,000
Attributes: -rw-------
CRC32: 295ED9AB
Host OS: Unix
Compression: RAR 3.0(v29) -m3 -md=4M
Name: .wget-hsts
Type: File
Size: 205
Packed size: 181
Ratio: 88%
mtime: 2016-10-26 13:14:09,000
Attributes: -rw-rw-r--
CRC32: 58429CA4
Host OS: Unix
Compression: RAR 3.0(v29) -m3 -md=4M
Name: .xboardrc
Type: File
Size: 7527
Packed size: 2964
Ratio: 39%
mtime: 2016-04-17 01:21:46,000
Attributes: -rw-rw-r--
CRC32: 1DA6AD04
Host OS: Unix
Compression: RAR 3.0(v29) -m3 -md=4M
Name: .xchm
Type: File
Size: 559
Packed size: 382
Ratio: 68%
mtime: 2016-09-29 01:08:46,000
Attributes: -rw-rw-r--
CRC32: 73DBF2B9
Host OS: Unix
Compression: RAR 3.0(v29) -m3 -md=4M
Name: .xinputrc
Type: File
Size: 130
Packed size: 123
Ratio: 94%
mtime: 2015-12-27 17:08:35,000
Attributes: -rw-rw-r--
CRC32: 70CD8EF3
Host OS: Unix
Compression: RAR 3.0(v29) -m3 -md=4M
Name: .dosbox/dosbox-0.74.conf
Type: File
Size: 10730
Packed size: 4005
Ratio: 37%
mtime: 2016-06-07 20:43:58,000
Attributes: -rw-rw-r--
CRC32: 1D5A9AA6
Host OS: Unix
Compression: RAR 3.0(v29) -m3 -md=4M
Name: log.txt
Type: File
Size: 5869937
Packed size: 42114
Ratio: 0%
mtime: 2016-11-23 07:43:18,000
Attributes: -rw-rw-r--
CRC32: E63DE4A6
Host OS: Unix
Compression: RAR 3.0(v29) -m3 -md=4M
Name: filename with spaces.txt
Type: File
Size: 6
Packed size: 16
Ratio: 266%
mtime: 2016-11-23 07:39:15,000
Attributes: -rw-r--r--
CRC32: 363A3020
Host OS: Unix
Compression: RAR 3.0(v29) -m3 -md=4M
Name: .dosbox
Type: Directory
mtime: 2016-06-07 20:43:58,000
Attributes: drwx------
CRC32: 00000000
Host OS: Unix
Compression: RAR 3.0(v20) -m0 -md=0K

View File

@ -0,0 +1,9 @@
drwx------ 1 <<uid>> <<gid>> 0 2016-06-07 20:43:00 ./.dosbox
-rw-rw-r-- 1 <<uid>> <<gid>> 10730 2016-06-07 20:43:00 ./.dosbox/dosbox-0.74.conf
-rw-r--r-- 1 <<uid>> <<gid>> 6 2016-11-23 07:39:00 ./filename with spaces.txt
-rw-rw-r-- 1 <<uid>> <<gid>> 5869937 2016-11-23 07:43:00 ./log.txt
-rw------- 1 <<uid>> <<gid>> 11032 2016-11-23 07:10:00 ./.viminfo
-rw-rw-r-- 1 <<uid>> <<gid>> 205 2016-10-26 13:14:00 ./.wget-hsts
-rw-rw-r-- 1 <<uid>> <<gid>> 7527 2016-04-17 01:21:00 ./.xboardrc
-rw-rw-r-- 1 <<uid>> <<gid>> 559 2016-09-29 01:08:00 ./.xchm
-rw-rw-r-- 1 <<uid>> <<gid>> 130 2015-12-27 17:08:00 ./.xinputrc

View File

@ -0,0 +1,14 @@
The input files were created thus:
cd ~/.gimp-2.8
echo hello > 'filename with spaces.txt'
zip a.zip *
unzip -Z -l -T a.zip > uzip.with-zipinfo.input
unzip -qq -v a.zip > uzip.without-zipinfo--ymd.input
rm a.zip
uzip supports two date formats for "without-zipinfo" mode: ymd
(YYYY-MM-DD) and mdy (MM-DD-YY). To create the
'uzip.without-zipinfo--mdy.input' file, with MM-DD-YY dates, I simply
altered two dates with an editor (one with year before 70, one after).

View File

@ -0,0 +1 @@
MC_TEST_EXTFS_HAVE_ZIPINFO=1

View File

@ -0,0 +1,43 @@
Archive: a.zip
Zip file size: 75222 bytes, number of entries: 40
drwxr-xr-x 3.0 unx 0 bx 0 stor 20151225.001514 brushes/
-rw------- 3.0 unx 739 tx 164 defN 20160918.164557 colorrc
-rw------- 3.0 unx 1863 tx 441 defN 20160918.164558 controllerrc
drwxr-xr-x 3.0 unx 0 bx 0 stor 20151225.001514 curves/
-rw------- 3.0 unx 1982 tx 423 defN 20160918.164557 dockrc
drwxr-xr-x 3.0 unx 0 bx 0 stor 20151225.001514 dynamics/
drwxr-xr-x 3.0 unx 0 bx 0 stor 20151225.001514 environ/
-rw-r--r-- 3.0 unx 6 tx 6 stor 20161123.071336 filename with spaces.txt
drwxr-xr-x 3.0 unx 0 bx 0 stor 20151225.001514 fonts/
drwxr-xr-x 3.0 unx 0 bx 0 stor 20151225.001514 fractalexplorer/
drwxr-xr-x 3.0 unx 0 bx 0 stor 20151225.001514 gfig/
drwxr-xr-x 3.0 unx 0 bx 0 stor 20151225.001514 gflare/
-rw------- 3.0 unx 355 tx 223 defN 20160108.011031 gimprc
drwxr-xr-x 3.0 unx 0 bx 0 stor 20151225.001514 gimpressionist/
drwxr-xr-x 3.0 unx 0 bx 0 stor 20151225.001514 gradients/
-rw-r--r-- 3.0 unx 430 tx 251 defN 20151225.001514 gtkrc
drwxr-xr-x 3.0 unx 0 bx 0 stor 20151225.001514 interpreters/
drwxr-xr-x 3.0 unx 0 bx 0 stor 20151225.001514 levels/
-rw-r--r-- 3.0 unx 76873 tx 8770 defN 20160918.164558 menurc
drwxr-xr-x 3.0 unx 0 bx 0 stor 20151225.001514 modules/
drwxr-xr-x 3.0 unx 0 bx 0 stor 20151225.001514 palettes/
-rw------- 3.0 unx 102 tx 86 defN 20160918.164559 parasiterc
drwxr-xr-x 3.0 unx 0 bx 0 stor 20151225.001514 patterns/
-rw-r--r-- 3.0 unx 277486 tx 48556 defN 20151225.001526 pluginrc
drwxr-xr-x 3.0 unx 0 bx 0 stor 20151225.001514 plug-ins/
-rw-rw-r-- 3.0 unx 209 tx 143 defN 20160918.164437 print-page-setup
-rw-rw-r-- 3.0 unx 506 tx 295 defN 20160918.164437 print-settings
-rw------- 3.0 unx 62 tx 43 defN 20160108.010813 profilerc
drwxr-xr-x 3.0 unx 0 bx 0 stor 20151225.001514 scripts/
-rw------- 3.0 unx 2370 tx 685 defN 20160918.164557 sessionrc
-rw-rw-r-- 3.0 unx 34747 tx 7545 defN 20160918.164559 tags.xml
-rw------- 3.0 unx 4817 tx 589 defN 20160918.164559 templaterc
drwxr-xr-x 3.0 unx 0 bx 0 stor 20151225.001514 templates/
-rw-rw-r-- 3.0 unx 310 tx 204 defN 20160918.164204 themerc
drwxr-xr-x 3.0 unx 0 bx 0 stor 20151225.001514 themes/
drwxr-xr-x 3.0 unx 0 bx 0 stor 20151225.001514 tmp/
drwxr-xr-x 3.0 unx 0 bx 0 stor 20160403.000739 tool-options/
drwxr-xr-x 3.0 unx 0 bx 0 stor 20151225.001514 tool-presets/
-rw------- 3.0 unx 3996 tx 528 defN 20160918.164558 toolrc
-rw------- 3.0 unx 1178 tx 388 defN 20160918.164559 unitrc
40 files, 408031 bytes uncompressed, 69340 bytes compressed: 83.0%

View File

@ -0,0 +1,40 @@
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:14 brushes/
-rw------- 1 <<uid>> <<gid>> 739 2016-09-18 16:45:57 colorrc
-rw------- 1 <<uid>> <<gid>> 1863 2016-09-18 16:45:58 controllerrc
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:14 curves/
-rw------- 1 <<uid>> <<gid>> 1982 2016-09-18 16:45:57 dockrc
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:14 dynamics/
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:14 environ/
-rw-r--r-- 1 <<uid>> <<gid>> 6 2016-11-23 07:13:36 filename with spaces.txt
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:14 fonts/
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:14 fractalexplorer/
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:14 gfig/
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:14 gflare/
-rw------- 1 <<uid>> <<gid>> 355 2016-01-08 01:10:31 gimprc
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:14 gimpressionist/
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:14 gradients/
-rw-r--r-- 1 <<uid>> <<gid>> 430 2015-12-25 00:15:14 gtkrc
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:14 interpreters/
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:14 levels/
-rw-r--r-- 1 <<uid>> <<gid>> 76873 2016-09-18 16:45:58 menurc
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:14 modules/
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:14 palettes/
-rw------- 1 <<uid>> <<gid>> 102 2016-09-18 16:45:59 parasiterc
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:14 patterns/
-rw-r--r-- 1 <<uid>> <<gid>> 277486 2015-12-25 00:15:26 pluginrc
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:14 plug-ins/
-rw-rw-r-- 1 <<uid>> <<gid>> 209 2016-09-18 16:44:37 print-page-setup
-rw-rw-r-- 1 <<uid>> <<gid>> 506 2016-09-18 16:44:37 print-settings
-rw------- 1 <<uid>> <<gid>> 62 2016-01-08 01:08:13 profilerc
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:14 scripts/
-rw------- 1 <<uid>> <<gid>> 2370 2016-09-18 16:45:57 sessionrc
-rw-rw-r-- 1 <<uid>> <<gid>> 34747 2016-09-18 16:45:59 tags.xml
-rw------- 1 <<uid>> <<gid>> 4817 2016-09-18 16:45:59 templaterc
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:14 templates/
-rw-rw-r-- 1 <<uid>> <<gid>> 310 2016-09-18 16:42:04 themerc
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:14 themes/
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:14 tmp/
drwxr-xr-x 1 <<uid>> <<gid>> 0 2016-04-03 00:07:39 tool-options/
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:14 tool-presets/
-rw------- 1 <<uid>> <<gid>> 3996 2016-09-18 16:45:58 toolrc
-rw------- 1 <<uid>> <<gid>> 1178 2016-09-18 16:45:59 unitrc

View File

@ -0,0 +1 @@
MC_TEST_EXTFS_HAVE_ZIPINFO=0

View File

@ -0,0 +1,2 @@
0 Stored 0 0% 12-25-15 00:15 00000000 brushes/
739 Defl:N 164 78% 09-16-78 16:45 2d7277eb colorrc

View File

@ -0,0 +1,2 @@
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:00 brushes/
-rw-r--r-- 1 <<uid>> <<gid>> 739 1978-09-16 16:45:00 colorrc

View File

@ -0,0 +1 @@
MC_TEST_EXTFS_HAVE_ZIPINFO=0

View File

@ -0,0 +1,40 @@
0 Stored 0 0% 2015-12-25 00:15 00000000 brushes/
739 Defl:N 164 78% 2016-09-18 16:45 2d7277eb colorrc
1863 Defl:N 441 76% 2016-09-18 16:45 4a229bae controllerrc
0 Stored 0 0% 2015-12-25 00:15 00000000 curves/
1982 Defl:N 423 79% 2016-09-18 16:45 0f21e877 dockrc
0 Stored 0 0% 2015-12-25 00:15 00000000 dynamics/
0 Stored 0 0% 2015-12-25 00:15 00000000 environ/
6 Stored 6 0% 2016-11-23 07:13 363a3020 filename with spaces.txt
0 Stored 0 0% 2015-12-25 00:15 00000000 fonts/
0 Stored 0 0% 2015-12-25 00:15 00000000 fractalexplorer/
0 Stored 0 0% 2015-12-25 00:15 00000000 gfig/
0 Stored 0 0% 2015-12-25 00:15 00000000 gflare/
355 Defl:N 223 37% 2016-01-08 01:10 05197193 gimprc
0 Stored 0 0% 2015-12-25 00:15 00000000 gimpressionist/
0 Stored 0 0% 2015-12-25 00:15 00000000 gradients/
430 Defl:N 251 42% 2015-12-25 00:15 a3ed42bc gtkrc
0 Stored 0 0% 2015-12-25 00:15 00000000 interpreters/
0 Stored 0 0% 2015-12-25 00:15 00000000 levels/
76873 Defl:N 8770 89% 2016-09-18 16:45 7d9cb346 menurc
0 Stored 0 0% 2015-12-25 00:15 00000000 modules/
0 Stored 0 0% 2015-12-25 00:15 00000000 palettes/
102 Defl:N 86 16% 2016-09-18 16:45 62252c7b parasiterc
0 Stored 0 0% 2015-12-25 00:15 00000000 patterns/
277486 Defl:N 48556 83% 2015-12-25 00:15 f846b075 pluginrc
0 Stored 0 0% 2015-12-25 00:15 00000000 plug-ins/
209 Defl:N 143 32% 2016-09-18 16:44 1c6688d4 print-page-setup
506 Defl:N 295 42% 2016-09-18 16:44 ce580111 print-settings
62 Defl:N 43 31% 2016-01-08 01:08 d149fa62 profilerc
0 Stored 0 0% 2015-12-25 00:15 00000000 scripts/
2370 Defl:N 685 71% 2016-09-18 16:45 b31b0c93 sessionrc
34747 Defl:N 7545 78% 2016-09-18 16:45 6f219ddd tags.xml
4817 Defl:N 589 88% 2016-09-18 16:45 edb121a1 templaterc
0 Stored 0 0% 2015-12-25 00:15 00000000 templates/
310 Defl:N 204 34% 2016-09-18 16:42 0b2c424e themerc
0 Stored 0 0% 2015-12-25 00:15 00000000 themes/
0 Stored 0 0% 2015-12-25 00:15 00000000 tmp/
0 Stored 0 0% 2016-04-03 00:07 00000000 tool-options/
0 Stored 0 0% 2015-12-25 00:15 00000000 tool-presets/
3996 Defl:N 528 87% 2016-09-18 16:45 f51984ae toolrc
1178 Defl:N 388 67% 2016-09-18 16:45 b8420722 unitrc

View File

@ -0,0 +1,40 @@
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:00 brushes/
-rw-r--r-- 1 <<uid>> <<gid>> 739 2016-09-18 16:45:00 colorrc
-rw-r--r-- 1 <<uid>> <<gid>> 1863 2016-09-18 16:45:00 controllerrc
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:00 curves/
-rw-r--r-- 1 <<uid>> <<gid>> 1982 2016-09-18 16:45:00 dockrc
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:00 dynamics/
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:00 environ/
-rw-r--r-- 1 <<uid>> <<gid>> 6 2016-11-23 07:13:00 filename with spaces.txt
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:00 fonts/
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:00 fractalexplorer/
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:00 gfig/
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:00 gflare/
-rw-r--r-- 1 <<uid>> <<gid>> 355 2016-01-08 01:10:00 gimprc
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:00 gimpressionist/
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:00 gradients/
-rw-r--r-- 1 <<uid>> <<gid>> 430 2015-12-25 00:15:00 gtkrc
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:00 interpreters/
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:00 levels/
-rw-r--r-- 1 <<uid>> <<gid>> 76873 2016-09-18 16:45:00 menurc
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:00 modules/
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:00 palettes/
-rw-r--r-- 1 <<uid>> <<gid>> 102 2016-09-18 16:45:00 parasiterc
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:00 patterns/
-rw-r--r-- 1 <<uid>> <<gid>> 277486 2015-12-25 00:15:00 pluginrc
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:00 plug-ins/
-rw-r--r-- 1 <<uid>> <<gid>> 209 2016-09-18 16:44:00 print-page-setup
-rw-r--r-- 1 <<uid>> <<gid>> 506 2016-09-18 16:44:00 print-settings
-rw-r--r-- 1 <<uid>> <<gid>> 62 2016-01-08 01:08:00 profilerc
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:00 scripts/
-rw-r--r-- 1 <<uid>> <<gid>> 2370 2016-09-18 16:45:00 sessionrc
-rw-r--r-- 1 <<uid>> <<gid>> 34747 2016-09-18 16:45:00 tags.xml
-rw-r--r-- 1 <<uid>> <<gid>> 4817 2016-09-18 16:45:00 templaterc
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:00 templates/
-rw-r--r-- 1 <<uid>> <<gid>> 310 2016-09-18 16:42:00 themerc
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:00 themes/
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:00 tmp/
drwxr-xr-x 1 <<uid>> <<gid>> 0 2016-04-03 00:07:00 tool-options/
drwxr-xr-x 1 <<uid>> <<gid>> 0 2015-12-25 00:15:00 tool-presets/
-rw-r--r-- 1 <<uid>> <<gid>> 3996 2016-09-18 16:45:00 toolrc
-rw-r--r-- 1 <<uid>> <<gid>> 1178 2016-09-18 16:45:00 unitrc

View File

@ -0,0 +1,8 @@
The input file was created by running "zoo lq" on the archive at:
http://www.midnight-commander.org/ticket/3696
Known bugs in our uzoo:
- It doesn't support filenames with spaces.
- It reports '0' gid.

View File

@ -0,0 +1,18 @@
4 0% 4 26 Sep 16 12:56:02+61 тест/тест3/тест2.txt
4 0% 4 26 Sep 16 12:56:00+61 тест/тест3/тест1.txt
4 0% 4 26 Sep 16 12:56:08+61 тест/тест3/тест3.txt
4 0% 4 26 Sep 16 12:56:02+61 тест/тест1/тест2.txt
4 0% 4 26 Sep 16 12:56:00+61 тест/тест1/тест1.txt
4 0% 4 26 Sep 16 12:56:08+61 тест/тест1/тест3.txt
4 0% 4 26 Sep 16 12:56:02+61 тест/тест2/тест2.txt
4 0% 4 26 Sep 16 12:56:00+61 тест/тест2/тест1.txt
4 0% 4 26 Sep 16 12:56:08+61 тест/тест2/тест3.txt
4 0% 4 26 Sep 16 12:56:02+61 тест/test1/тест2.txt
4 0% 4 26 Sep 16 12:56:00+61 тест/test1/тест1.txt
4 0% 4 26 Sep 16 12:56:08+61 тест/test1/тест3.txt
4 0% 4 26 Sep 16 12:56:02+61 тест/test3/тест2.txt
4 0% 4 26 Sep 16 12:56:00+61 тест/test3/тест1.txt
4 0% 4 26 Sep 16 12:56:08+61 тест/test3/тест3.txt
4 0% 4 26 Sep 16 12:56:02+61 тест/test2/тест2.txt
4 0% 4 26 Sep 16 12:56:00+61 тест/test2/тест1.txt
4 0% 4 26 Sep 16 12:56:08+61 тест/test2/тест3.txt

View File

@ -0,0 +1,18 @@
-rw-r--r-- 1 <<uid>> 0 4 2016-09-26 12:56:00 тест/тест3/тест2.txt
-rw-r--r-- 1 <<uid>> 0 4 2016-09-26 12:56:00 тест/тест3/тест1.txt
-rw-r--r-- 1 <<uid>> 0 4 2016-09-26 12:56:00 тест/тест3/тест3.txt
-rw-r--r-- 1 <<uid>> 0 4 2016-09-26 12:56:00 тест/тест1/тест2.txt
-rw-r--r-- 1 <<uid>> 0 4 2016-09-26 12:56:00 тест/тест1/тест1.txt
-rw-r--r-- 1 <<uid>> 0 4 2016-09-26 12:56:00 тест/тест1/тест3.txt
-rw-r--r-- 1 <<uid>> 0 4 2016-09-26 12:56:00 тест/тест2/тест2.txt
-rw-r--r-- 1 <<uid>> 0 4 2016-09-26 12:56:00 тест/тест2/тест1.txt
-rw-r--r-- 1 <<uid>> 0 4 2016-09-26 12:56:00 тест/тест2/тест3.txt
-rw-r--r-- 1 <<uid>> 0 4 2016-09-26 12:56:00 тест/test1/тест2.txt
-rw-r--r-- 1 <<uid>> 0 4 2016-09-26 12:56:00 тест/test1/тест1.txt
-rw-r--r-- 1 <<uid>> 0 4 2016-09-26 12:56:00 тест/test1/тест3.txt
-rw-r--r-- 1 <<uid>> 0 4 2016-09-26 12:56:00 тест/test3/тест2.txt
-rw-r--r-- 1 <<uid>> 0 4 2016-09-26 12:56:00 тест/test3/тест1.txt
-rw-r--r-- 1 <<uid>> 0 4 2016-09-26 12:56:00 тест/test3/тест3.txt
-rw-r--r-- 1 <<uid>> 0 4 2016-09-26 12:56:00 тест/test2/тест2.txt
-rw-r--r-- 1 <<uid>> 0 4 2016-09-26 12:56:00 тест/test2/тест1.txt
-rw-r--r-- 1 <<uid>> 0 4 2016-09-26 12:56:00 тест/test2/тест3.txt

View File

@ -0,0 +1,405 @@
/*
A parser for file-listings formatted like 'ls -l'.
Copyright (C) 2016
Free Software Foundation, Inc.
This file is part of the Midnight Commander.
The Midnight Commander is free software: you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of the License,
or (at your option) any later version.
The Midnight Commander is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/** \file
* \brief A parser for file-listings formatted like 'ls -l'.
*
* This program parses file-listings the same way MC does.
* It's basically a wrapper around vfs_parse_ls_lga().
* You can feed it the output of any of extfs's helpers.
*
* After parsing, the data is written out to stdout. The output
* format can be either YAML or a format similar to 'ls -l'.
*
* This program is the main tool our tester script is going to use.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include "lib/global.h"
#include "lib/vfs/utilvfs.h" /* vfs_parse_ls_lga() */
#include "lib/util.h" /* string_perm() */
#include "lib/timefmt.h" /* FMT_LOCALTIME */
#include "lib/widget.h" /* for the prototype of message() only */
/*** global variables ****************************************************************************/
/*** file scope macro definitions ****************************************************************/
/*** file scope type declarations ****************************************************************/
typedef enum
{
FORMAT_YAML,
FORMAT_LS
} output_format_t;
/*** file scope variables ************************************************************************/
/* Command-line options. */
static gboolean opt_drop_mtime = FALSE;
static gboolean opt_drop_ids = FALSE;
static gboolean opt_symbolic_ids = FALSE;
static output_format_t opt_output_format = FORMAT_LS;
/* Misc. */
static int error_count = 0;
/* forward declarations */
static gboolean
parse_format_name_argument (const gchar * option_name, const gchar * value, gpointer data,
GError ** error);
static GOptionEntry entries[] = {
{"drop-mtime", 0, 0, G_OPTION_ARG_NONE, &opt_drop_mtime, "Don't include mtime in the output.",
NULL},
{"drop-ids", 0, 0, G_OPTION_ARG_NONE, &opt_drop_ids, "Don't include uid/gid in the output.",
NULL},
{"symbolic-ids", 0, 0, G_OPTION_ARG_NONE, &opt_symbolic_ids,
"Print the strings '<<uid>>'/'<<gid>>' instead of the numeric IDs when they match the process' uid/gid.",
NULL},
{"format", 'f', 0, G_OPTION_ARG_CALLBACK, parse_format_name_argument,
"Output format. Default: ls.", "<ls|yaml>"},
{NULL, '\0', 0, 0, NULL, NULL, NULL} /* Make the compiler shut up by initializing everything. */
};
/*** file scope functions ************************************************************************/
/* --------------------------------------------------------------------------------------------- */
/**
* Command-line handling.
*/
/* --------------------------------------------------------------------------------------------- */
static gboolean
parse_format_name_argument (const gchar * option_name, const gchar * value, gpointer data,
GError ** error)
{
(void) option_name;
(void) data;
if (strcmp (value, "yaml") == 0)
opt_output_format = FORMAT_YAML;
else if (strcmp (value, "ls") == 0)
opt_output_format = FORMAT_LS;
else
{
g_set_error (error, MC_ERROR, G_OPTION_ERROR_FAILED, "unknown output format '%s'", value);
return FALSE;
}
return TRUE;
}
/* --------------------------------------------------------------------------------------------- */
static gboolean
parse_command_line (int *argc, char **argv[])
{
GError *error = NULL;
GOptionContext *context;
context =
g_option_context_new
("- Parses its input, which is expected to be in a format similar to 'ls -l', and writes the result to stdout.");
g_option_context_add_main_entries (context, entries, NULL);
if (!g_option_context_parse (context, argc, argv, &error))
{
g_print ("option parsing failed: %s\n", error->message);
return FALSE;
}
return TRUE;
}
/* --------------------------------------------------------------------------------------------- */
/**
* Utility functions.
*/
/* --------------------------------------------------------------------------------------------- */
static const char *
my_itoa (int i)
{
static char buf[BUF_SMALL];
sprintf (buf, "%d", i);
return buf;
}
/* --------------------------------------------------------------------------------------------- */
/**
* Returns the uid as-is, or as "<<uid>>" if the same as current user.
*/
static const char *
symbolic_uid (uid_t uid)
{
return (opt_symbolic_ids && uid == getuid ())? "<<uid>>" : my_itoa ((int) uid);
}
/* --------------------------------------------------------------------------------------------- */
static const char *
symbolic_gid (gid_t gid)
{
return (opt_symbolic_ids && gid == getgid ())? "<<gid>>" : my_itoa ((int) gid);
}
/* --------------------------------------------------------------------------------------------- */
/**
* Cuts off a string's line-end (as in Perl).
*/
static void
chomp (char *s)
{
int i;
i = strlen (s);
/* Code taken from vfs_parse_ls_lga(), with modifications. */
if ((--i >= 0) && (s[i] == '\r' || s[i] == '\n'))
s[i] = '\0';
if ((--i >= 0) && (s[i] == '\r' || s[i] == '\n'))
s[i] = '\0';
}
/* --------------------------------------------------------------------------------------------- */
static const char *
string_date (time_t time)
{
static char buf[BUF_SMALL];
/*
* If we ever want to be able to re-parse the output of this program,
* we'll need to use the American brain-damaged MM-DD-YYYY instead of
* YYYY-MM-DD because vfs_parse_ls_lga() doesn't currently recognize
* the latter.
*/
FMT_LOCALTIME (buf, sizeof buf, "%Y-%m-%d %H:%M:%S", time);
return buf;
}
/* --------------------------------------------------------------------------------------------- */
/**
* Override MC's message().
*
* vfs_parse_ls_lga() calls this on error. Since MC's uses tty/widgets, it
* will crash us. We replace it with a plain version.
*/
void
message (int flags, const char *title, const char *text, ...)
{
char *p;
va_list ap;
(void) flags;
(void) title;
va_start (ap, text);
p = g_strdup_vprintf (text, ap);
va_end (ap);
printf ("message(): vfs_parse_ls_lga(): parsing error at: %s\n", p);
g_free (p);
}
/* --------------------------------------------------------------------------------------------- */
/**
* YAML output format.
*/
/* --------------------------------------------------------------------------------------------- */
static void
yaml_dump_stbuf (const struct stat *st)
{
/* Various casts and flags here were taken/inspired by info_show_info(). */
printf (" perm: %s\n", string_perm (st->st_mode));
if (!opt_drop_ids)
{
printf (" uid: %s\n", symbolic_uid (st->st_uid));
printf (" gid: %s\n", symbolic_gid (st->st_gid));
}
printf (" size: %" PRIuMAX "\n", (uintmax_t) st->st_size);
printf (" nlink: %d\n", (int) st->st_nlink);
if (!opt_drop_mtime)
printf (" mtime: %s\n", string_date (st->st_mtime));
}
/* --------------------------------------------------------------------------------------------- */
static void
yaml_dump_string (const char *name, const char *val)
{
char *q;
q = g_shell_quote (val);
printf (" %s: %s\n", name, q);
g_free (q);
}
/* --------------------------------------------------------------------------------------------- */
static void
yaml_dump_record (gboolean success, const char *input_line, const struct stat *st,
const char *filename, const char *linkname)
{
printf ("-\n"); /* Start new item in the list. */
if (success)
{
if (filename != NULL)
yaml_dump_string ("name", filename);
if (linkname != NULL)
yaml_dump_string ("linkname", linkname);
yaml_dump_stbuf (st);
}
else
{
yaml_dump_string ("cannot parse input line", input_line);
}
}
/* --------------------------------------------------------------------------------------------- */
/**
* 'ls' output format.
*/
/* --------------------------------------------------------------------------------------------- */
static void
ls_dump_stbuf (const struct stat *st)
{
/* Various casts and flags here were taken/inspired by info_show_info(). */
printf ("%s %3d ", string_perm (st->st_mode), (int) st->st_nlink);
if (!opt_drop_ids)
{
printf ("%8s ", symbolic_uid (st->st_uid));
printf ("%8s ", symbolic_gid (st->st_gid));
}
printf ("%10" PRIuMAX " ", (uintmax_t) st->st_size);
if (!opt_drop_mtime)
printf ("%s ", string_date (st->st_mtime));
}
/* --------------------------------------------------------------------------------------------- */
static void
ls_dump_record (gboolean success, const char *input_line, const struct stat *st,
const char *filename, const char *linkname)
{
if (success)
{
ls_dump_stbuf (st);
if (filename != NULL)
printf ("%s", filename);
if (linkname != NULL)
printf (" -> %s", linkname);
printf ("\n");
}
else
{
printf ("cannot parse input line: '%s'\n", input_line);
}
}
/* ------------------------------------------------------------------------------ */
/**
* Main code.
*/
/* ------------------------------------------------------------------------------ */
static void
process_ls_line (const char *line)
{
struct stat st;
char *filename, *linkname;
gboolean success;
memset (&st, 0, sizeof st);
filename = NULL;
linkname = NULL;
success = vfs_parse_ls_lga (line, &st, &filename, &linkname, NULL);
if (!success)
error_count++;
if (opt_output_format == FORMAT_YAML)
yaml_dump_record (success, line, &st, filename, linkname);
else
ls_dump_record (success, line, &st, filename, linkname);
g_free (filename);
g_free (linkname);
}
/* ------------------------------------------------------------------------------ */
static void
process_input (FILE * input)
{
char line[BUF_4K];
while (fgets (line, sizeof line, input) != NULL)
{
chomp (line); /* Not mandatory. Makes error messages nicer. */
if (strncmp (line, "total ", 6) == 0) /* Convenience only: makes 'ls -l' parse cleanly. */
continue;
process_ls_line (line);
}
}
/* ------------------------------------------------------------------------------ */
int
main (int argc, char *argv[])
{
FILE *input;
if (!parse_command_line (&argc, &argv))
return EXIT_FAILURE;
if (argc >= 2)
{
input = fopen (argv[1], "r");
if (input == NULL)
{
perror (argv[1]);
return EXIT_FAILURE;
}
}
else
{
input = stdin;
}
process_input (input);
return (error_count > 0) ? EXIT_FAILURE : EXIT_SUCCESS;
}
/* ------------------------------------------------------------------------------ */

View File

@ -0,0 +1,16 @@
#!/bin/sh
#
# This program is intended to be identical to 'cat' with the exception that
# it ignores any arguments past the 1st one.
#
# To understand why it's needed, first read the section about
# MC_TEST_EXTFS_LIST_CMD in the README. As explained there, the command in
# MC_TEST_EXTFS_LIST_CMD has to ignore any extra arguments passed to it.
# The tester achieves this by invoking a helper thus (roughly):
#
# export MC_TEST_EXTFS_LIST_CMD="mc_xcat /path/to/fake/input"
# sh /path/to/helper list /dev/null
#
exec cat "$1"

View File

@ -0,0 +1,393 @@
#!/bin/sh
# A tester for extfs helpers.
#
# Copyright (C) 2016
# The Free Software Foundation, Inc.
#
# This file is part of the Midnight Commander.
#
# The Midnight Commander is free software: you can redistribute it
# and/or modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 3 of the License,
# or (at your option) any later version.
#
# The Midnight Commander is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
help() {
cat << EOS
NAME
$(basename "$0") - Tests the 'list' command of extfs helpers.
SYNOPSIS
$(basename "$0") \\
--data-dir /path/to/where/data/files/are/stored \\
--helpers-dir /path/to/where/helpers/are/stored
(But you're more likely to invoke this program with the 'run' script
created by 'make check'; or by 'make check' itself.)
DESCRIPTION
This program tests extfs helpers by feeding them input and comparing
their output to the expected output.
See README for full details.
You need to tell this program two things: where the helpers are stored,
and where the "data files" are stored. The data files are *.input files
that are fed to the helpers and *.output files that are the correct
output expected from these helpers.
EOS
}
#"'
############################ Global variables ##############################
# The directories used.
DATA_DIR=
HELPERS_DIR1=
HELPERS_DIR2=
opt_create_output=no # "yes" if '--create-output' provided.
opt_run_mcdiff_on_error=no # "yes" if '--mcdiff' provided.
############################ Coding guidance ###############################
#
# Portability notes:
#
# - We do `local var="$whatever"` instead of `local var=$whatever` for
# compatibility with Dash. See http://unix.stackexchange.com/questions/97560.
#
# - The 'local' keyword used in this file isn't mandatory. Feel free to
# remove it if it isn't supported by your archaic shell.
#
############################ Utility functions #############################
#
# Does $1 contain $2?
#
# Accepts basic regex.
#
has_string() {
local haystack="$1" # quotes needed for Dash, as may contain spaces (see notes above).
local needle="$2"
echo "$haystack" | grep "$needle" > /dev/null
}
#
# Given "/path/to/basename.and.some.ext", returns "basename"
#
basename_sans_extensions() {
local base="$(basename "$1")"
echo "${base%%.*}"
}
#
# Does an executable exist?
#
has_prog() {
# see http://stackoverflow.com/questions/592620
command -v "$1" >/dev/null 2>&1
}
#
# Can we use colors?
#
has_colors() {
[ -t 1 ] && has_string "$TERM" 'linux\|xterm\|screen\|tmux\|putty'
}
init_colors() {
if has_colors; then
ESC=$(printf '\033') # for portability
C_bold="$ESC[1m"
C_green="$ESC[1;32m"
C_red="$ESC[1;31m"
C_magenta="$ESC[1;35m"
C_norm="$ESC[0m"
fi
}
#
# A few colorful alternatives to 'echo'.
#
header() { echo $C_bold"$@"$C_norm; }
err() { echo $C_red"$@"$C_norm; }
notice() { echo $C_magenta"$@"$C_norm; }
success() { echo $C_green"$@"$C_norm; }
die() {
err "Error: $@"
exit 1
}
assert_dir_exists() {
[ -d "$1" ] || die "The directory '$1' doesn't exist, or is not a directory."
}
#
# Creates a temporary file.
#
temp_file() {
local template="$1"
# BSD's doesn't support -t.
mktemp "${TMPDIR:-/tmp}/$template"
}
################################ Main code #################################
#
# Prints out the command to run a helper, if it can find it.
#
# For example,
#
# find_helper uzip /path/to/helpers/dir
#
# prints:
#
# /usr/bin/perl -w /path/to/helpers/dir/uzip
#
# Since helpers in the build tree don't yet have executable bit set, we
# need to extract the shebang line.
#
find_helper() {
local helper_name="$1"
local dir="$2"
local try="$dir/$helper_name"
if [ -f "$try" ]; then
helper_CMD="$(head -1 $try | cut -c 3-) $try" # reason #1 we don't allow spaces in pathnames.
true
else
false
fi
}
#
# The crux of this program.
#
run() {
local error_count=0
local pass_count=0
for INPUT in "$DATA_DIR"/*.input; do
has_string "$INPUT" '\*' && break # we can't use 'shopt -s nullglob' as it's bash-specific.
header "Testing $INPUT"
has_string "$INPUT" " " && die "Error: filename contains spaces."
#
# Set up variables:
#
local helper_name="$(basename_sans_extensions "$INPUT")"
local expected_parsed_output="${INPUT%.input}.output"
local env_vars_file="${INPUT%.input}.env_vars"
local args_file="${INPUT%.input}.args"
local do_create_output=no
if [ ! -f "$expected_parsed_output" ]; then
# Corresponding *.output file doesn't exist. We either create it, later, or exit with error.
if [ $opt_create_output = "yes" ]; then
do_create_output=yes
else
err
err "Missing file: '$expected_parsed_output'."
err "You have to create an '.output' file for each '.input' one."
err
notice "Tip: invoke this program with '--create-output' to"
notice "automatically create missing '.output' files."
notice
exit 1
fi
fi
find_helper "$helper_name" "$HELPERS_DIR1" ||
find_helper "$helper_name" "$HELPERS_DIR2" ||
die "I can't find helper '$helper_name' in either $HELPERS_DIR1 or $HELPERS_DIR2"
local extra_parser_args=""
[ -f "$args_file" ] && extra_parser_args="$(cat "$args_file")"
local actual_output="$(temp_file $helper_name.actual-output.XXXXXXXX)"
local actual_parsed_output="$(temp_file $helper_name.actual-parsed-output.XXXXXXXX)"
#
# Variables are all set. Now do the actual stuff:
#
(
MC_TEST_EXTFS_LIST_CMD="mc_xcat $INPUT" # reason #2 we don't allow spaces in pathnames.
export MC_TEST_EXTFS_LIST_CMD
if [ -f "$env_vars_file" ]; then
set -a # "allexport: Export all variables assigned to."
. "$env_vars_file"
set +a
fi
$helper_CMD list /dev/null > "$actual_output"
)
error_count=$((error_count + 1)) # we'll decrement it later.
if [ ! -s "$actual_output" ]; then
err
err "The helper '$helper_name' produced no output for this input. Something is wrong."
err
err "Make sure this helper supports testability: that it uses \$MC_TEST_EXTFS_LIST_CMD."
err
err "You may try running the helper yourself with:"
err
err " \$ MC_TEST_EXTFS_LIST_CMD=\"mc_xcat $INPUT\" \\"
err " $helper_CMD list /dev/null"
err
continue
fi
# '--symbolic-ids': uid/gid aren't portable between computers,
# of course, so we always represent them symbolically when possible.
if ! mc_parse_ls_l --symbolic-ids $extra_parser_args "$actual_output" > "$actual_parsed_output"; then
err
err "ERROR: Parsing of the output of the helper '$helper_name' has failed."
err "This means that $helper_name has produced output that MC won't be able to parse."
err "Run the parsing command yourself ('mc_parse_ls_l $extra_parser_args $actual_output')"
err "to figure out the problem."
err
continue
fi
if [ $do_create_output = "yes" ]; then
# We arrive here if we were invoked with '--create-output' and
# the .output file doesn't exist. We create it and move to the next iteration.
cp "$actual_parsed_output" "$expected_parsed_output"
notice "The output file has been created in $expected_parsed_output"
continue
fi
if ! cmp "$expected_parsed_output" "$actual_parsed_output"; then
err
err "ERROR: $helper_name has produced output that's different than the expected output."
err
err " Expected output (after parsing): $expected_parsed_output"
err " Actual output (after parsing): $actual_parsed_output"
err
err "This might mean that a bug was introduced into $helper_name. Or that a bug was fixed."
err "Please compare the files."
err
err "If the actual output is the correct one, just copy the latter file"
err "onto the former (and commit to the git repository)."
err
if [ $opt_run_mcdiff_on_error = "yes" ]; then
notice "Hit ENTER to launch mcdiff ..."
read DUMMY_VAR # dash needs this.
${MCDIFF:-mcdiff} "$expected_parsed_output" "$actual_parsed_output"
else
notice "Tip: invoke this program with '--mcdiff' to automatically launch"
notice "mcdiff to visually inspect the diff."
notice
fi
continue
fi
rm "$actual_output" "$actual_parsed_output"
error_count=$((error_count - 1)) # cancel the earlier "+1".
pass_count=$((pass_count + 1))
success "PASSED."
done
[ $pass_count = "0" -a $error_count = "0" ] && notice "Note: The data directory contains no *.input files."
[ $error_count = "0" ] # exit status of function.
}
parse_command_line_arguments() {
# We want --long-options, so we don't use 'getopts'.
while [ -n "$1" ]; do
case "$1" in
--data-dir)
DATA_DIR=$2
shift 2
;;
--helpers-dir)
if [ -z "$HELPERS_DIR1" ]; then
HELPERS_DIR1=$2
else
HELPERS_DIR2=$2
fi
shift 2
;;
--create-output)
opt_create_output=yes
shift
;;
--mcdiff)
opt_run_mcdiff_on_error=yes
shift
;;
--help|-h)
help
exit
;;
*)
die "Unknown command-line option $1"
;;
esac
done
}
#
# Check that everything is set up correctly.
#
verify_setup() {
[ -n "$DATA_DIR" ] || die "You didn't specify the data dir (--data-dir). Run me with --help for info."
[ -n "$HELPERS_DIR1" ] || die "You didn't specify the helpers dir (--helpers-dir). Run me with --help for info."
[ -z "$HELPERS_DIR2" ] && HELPERS_DIR2=$HELPERS_DIR1 # we're being lazy.
local dir
for dir in "$DATA_DIR" "$HELPERS_DIR1" "$HELPERS_DIR2"; do
assert_dir_exists "$dir"
has_string "$dir" " " && die "$dir: Sorry, spaces aren't allowed in pathnames." # search "reason", twice, above.
done
local missing_progs=""
check_prog() {
if ! has_prog "$1"; then
err "I can't see the program '$1'."
missing_progs="${missing_progs}${missing_progs:+ and }'$1'"
fi
}
check_prog "mc_parse_ls_l"
check_prog "mc_xcat"
check_prog "mktemp" # non-POSIX
[ -z "$missing_progs" ] || die "You need to add to your PATH the directories containing the executables $missing_progs."
}
main() {
init_colors
parse_command_line_arguments "$@"
verify_setup
run # being the last command executed, its exit status is that of this whole script.
}
main "$@"