001/**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.cli2.application;
018
019import java.io.BufferedReader;
020import java.io.IOException;
021import java.io.PrintWriter;
022import java.io.StringReader;
023import java.io.StringWriter;
024
025import junit.framework.Test;
026import junit.framework.TestCase;
027import junit.framework.TestSuite;
028
029import org.apache.commons.cli2.Argument;
030import org.apache.commons.cli2.CommandLine;
031import org.apache.commons.cli2.Group;
032import org.apache.commons.cli2.Option;
033import org.apache.commons.cli2.OptionException;
034import org.apache.commons.cli2.builder.ArgumentBuilder;
035import org.apache.commons.cli2.builder.DefaultOptionBuilder;
036import org.apache.commons.cli2.builder.GroupBuilder;
037import org.apache.commons.cli2.commandline.Parser;
038import org.apache.commons.cli2.option.ArgumentImpl;
039import org.apache.commons.cli2.option.SourceDestArgument;
040import org.apache.commons.cli2.util.HelpFormatter;
041
042/**
043 * <p>Test the <code>cp</code> command. Duplicated Option types are not
044 * tested e.g. -a and -d are the same Option type.</p>
045 *
046 * <p>The following is the man output for 'cp'. See
047 * <a href="http://www.rt.com/man/cp.1.html">http://www.rt.com/man/cp.1.html</a>.</p>
048 *
049 * <pre>
050 *  CP(1) FSF CP(1)
051 *
052 *  NAME cp - copy files and directories
053 *
054 *  SYNOPSIS cp [OPTION]... SOURCE DEST cp [OPTION]... SOURCE... DIRECTORY
055 *
056 *  DESCRIPTION Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.
057 *
058 *  -a, --archive same as -dpR
059 *
060 *  -b, --backup make backup before removal
061 *
062 *  -d, --no-dereference preserve links
063 *
064 *  -f, --force remove existing destinations, never prompt
065 *
066 *  -i, --interactive prompt before overwrite
067 *
068 *  -l, --link link files instead of copying
069 *
070 *  -p, --preserve preserve file attributes if possible
071 *
072 *  -P, --parents append source path to DIRECTORY
073 * -r copy recursively, non-directories as files
074 *
075 *  --sparse=WHEN control creation of sparse files
076 *
077 *  -R, --recursive copy directories recursively
078 *
079 *  -s, --symbolic-link make symbolic links instead of copying
080 *
081 *  -S, --suffix=SUFFIX override the usual backup suffix
082 *
083 *  -u, --update copy only when the SOURCE file is newer than the destination file or when the destination file is missing
084 *
085 *  -v, --verbose explain what is being done
086 *
087 *  -V, --version-control=WORD override the usual version control
088 *
089 *  -x, --one-file-system stay on this file system
090 *
091 *  --help display this help and exit
092 *
093 *  --version output version information and exit
094 *
095 *  By default, sparse SOURCE files are detected by a crude heuristic and the corresponding DEST file is made sparse as well. That is the behavior selected by --sparse=auto. Specify --sparse=always to create a sparse DEST file when- ever the SOURCE file contains a long enough sequence of zero bytes. Use --sparse=never to inhibit creation of sparse files.
096 *
097 *  The backup suffix is ~, unless set with SIMPLE_BACKUP_SUF- FIX. The version control may be set with VERSION_CONTROL, values are:
098 * t, numbered make numbered backups
099 *
100 *  nil, existing numbered if numbered backups exist, simple other- wise
101 *
102 *  never, simple always make simple backups
103 *
104 *  As a special case, cp makes a backup of SOURCE when the force and backup options are given and SOURCE and DEST are the same name for an existing, regular file. * </pre>
105 * </pre>
106 *
107 * @author Rob Oxspring
108 * @author John Keyes
109 */
110public class CpTest extends TestCase {
111
112    /** Option Builder */
113    private static final DefaultOptionBuilder oBuilder =
114        new DefaultOptionBuilder();
115
116    /** Argument Builder */
117    private static final ArgumentBuilder aBuilder = new ArgumentBuilder();
118
119    /** Group Builder */
120    private static final GroupBuilder gBuilder = new GroupBuilder();
121
122    private Group options;
123
124    public static Test suite() {
125        return new TestSuite(CpTest.class);
126    }
127
128    private ArgumentImpl source;
129    private ArgumentImpl dest;
130    private Argument targets;
131
132    private Option archive;
133    private Option backup;
134    private Option noDereference;
135    private Option force;
136    private Option interactive;
137    private Option link;
138    private Option preserve;
139    private Option parents;
140    private Option recursive1;
141    private Option sparse;
142    private Option recursive2;
143    private Option symbolicLink;
144    private Option suffix;
145    private Option update;
146    private Option verbose;
147    private Option versionControl;
148    private Option oneFileSystem;
149    private Option help;
150    private Option version;
151
152    public void setUp() {
153        source =
154            (ArgumentImpl)aBuilder.withName("SOURCE").withMinimum(1).create();
155        dest =
156            (ArgumentImpl)aBuilder
157                .withName("DEST")
158                .withMinimum(1)
159                .withMaximum(1)
160                .create();
161        targets = new SourceDestArgument(source, dest);
162
163        archive =
164            oBuilder
165                .withShortName("a")
166                .withLongName("archive")
167                .withDescription("same as -dpR")
168                .create();
169
170        backup =
171            oBuilder
172                .withShortName("b")
173                .withLongName("backup")
174                .withDescription("make backup before removal")
175                .create();
176
177        noDereference =
178            oBuilder
179                .withShortName("d")
180                .withLongName("no-dereference")
181                .withDescription("preserve links")
182                .create();
183
184        force =
185            oBuilder
186                .withShortName("f")
187                .withLongName("force")
188                .withDescription("remove existing destinations, never prompt")
189                .create();
190
191        interactive =
192            oBuilder
193                .withShortName("i")
194                .withLongName("interactive")
195                .withDescription("prompt before overwrite")
196                .create();
197
198        link =
199            oBuilder
200                .withShortName("l")
201                .withLongName("link")
202                .withDescription("link files instead of copying")
203                .create();
204
205        preserve =
206            oBuilder
207                .withShortName("p")
208                .withLongName("preserve")
209                .withDescription("preserve file attributes if possible")
210                .create();
211
212        parents =
213            oBuilder
214                .withShortName("P")
215                .withLongName("parents")
216                .withDescription("append source path to DIRECTORY")
217                .create();
218
219        recursive1 =
220            oBuilder
221                .withShortName("r")
222                .withDescription("copy recursively, non-directories as files")
223                .create();
224
225        sparse =
226            oBuilder
227                .withLongName("sparse")
228                .withDescription("control creation of sparse files")
229                .withArgument(
230                    aBuilder
231                        .withName("WHEN")
232                        .withMinimum(1)
233                        .withMaximum(1)
234                        .withInitialSeparator('=')
235                        .create())
236                .create();
237
238        recursive2 =
239            oBuilder
240                .withShortName("R")
241                .withLongName("recursive")
242                .withDescription("copy directories recursively")
243                .create();
244
245        symbolicLink =
246            oBuilder
247                .withShortName("s")
248                .withLongName("symbolic-link")
249                .withDescription("make symbolic links instead of copying")
250                .create();
251
252        suffix =
253            oBuilder
254                .withShortName("S")
255                .withLongName("suffix")
256                .withDescription("override the usual backup suffix")
257                .withArgument(
258                    aBuilder
259                        .withName("SUFFIX")
260                        .withMinimum(1)
261                        .withMaximum(1)
262                        .create())
263                .create();
264
265        update =
266            oBuilder
267                .withShortName("u")
268                .withLongName("update")
269                .withDescription("copy only when the SOURCE file is newer than the destination file or when the destination file is missing")
270                .create();
271
272        verbose =
273            oBuilder
274                .withShortName("v")
275                .withLongName("verbose")
276                .withDescription("explain what is being done")
277                .create();
278
279        versionControl =
280            oBuilder
281                .withShortName("V")
282                .withLongName("version-contol")
283                .withDescription("explain what is being done")
284                .withArgument(
285                    aBuilder
286                        .withName("WORD")
287                        .withInitialSeparator('=')
288                        .withMinimum(1)
289                        .withMaximum(1)
290                        .create())
291                .create();
292
293        oneFileSystem =
294            oBuilder
295                .withShortName("x")
296                .withLongName("one-file-system")
297                .withDescription("stay on this file system")
298                .create();
299
300        help =
301            oBuilder
302                .withLongName("help")
303                .withDescription("display this help and exit")
304                .create();
305
306        version =
307            oBuilder
308                .withLongName("version")
309                .withDescription("output version information and exit")
310                .create();
311
312        options =
313            gBuilder
314                .withOption(archive)
315                .withOption(backup)
316                .withOption(noDereference)
317                .withOption(force)
318                .withOption(interactive)
319                .withOption(link)
320                .withOption(preserve)
321                .withOption(parents)
322                .withOption(recursive1)
323                .withOption(sparse)
324                .withOption(recursive2)
325                .withOption(symbolicLink)
326                .withOption(suffix)
327                .withOption(update)
328                .withOption(verbose)
329                .withOption(versionControl)
330                .withOption(oneFileSystem)
331                .withOption(help)
332                .withOption(version)
333                .withOption(targets)
334                .withName("OPTIONS")
335                .create();
336    }
337
338    public void testNoSource() {
339        Parser parser = new Parser();
340        parser.setGroup(options);
341        try {
342            parser.parse(new String[0]);
343        }
344        catch (OptionException mve) {
345            assertEquals(
346                "Missing value(s) SOURCE [SOURCE ...]",
347                mve.getMessage());
348        }
349    }
350
351    public void testOneSource() throws OptionException {
352        final String[] args = new String[] { "source1", "dest1" };
353        final Parser parser = new Parser();
354        parser.setGroup(options);
355        final CommandLine commandLine = parser.parse(args);
356
357        assertTrue(commandLine.getValues(source).contains("source1"));
358        assertEquals(1, commandLine.getValues(source).size());
359        assertTrue(commandLine.getValues(dest).contains("dest1"));
360        assertEquals(1, commandLine.getValues(dest).size());
361    }
362
363    public void testMultiSource() throws OptionException {
364        final String[] args =
365            new String[] { "source1", "source2", "source3", "dest1" };
366        final Parser parser = new Parser();
367        parser.setGroup(options);
368        final CommandLine commandLine = parser.parse(args);
369
370        assertTrue(commandLine.getValues(source).contains("source1"));
371        assertTrue(commandLine.getValues(source).contains("source2"));
372        assertTrue(commandLine.getValues(source).contains("source3"));
373        assertEquals(3, commandLine.getValues(source).size());
374
375        assertTrue(commandLine.getValues(dest).contains("dest1"));
376        assertEquals(1, commandLine.getValues(dest).size());
377    }
378
379    public void testHelp() throws IOException {
380        final StringWriter out = new StringWriter();
381        final HelpFormatter helpFormatter = new HelpFormatter();
382        helpFormatter.setGroup(options);
383        helpFormatter.setPrintWriter(new PrintWriter(out));
384        helpFormatter.print();
385
386        final BufferedReader in =
387            new BufferedReader(new StringReader(out.toString()));
388        assertEquals(
389            "Usage:                                                                          ",
390            in.readLine());
391        assertEquals(
392            " [-a -b -d -f -i -l -p -P -r --sparse <WHEN> -R -s -S <SUFFIX> -u -v -V <WORD>  ",
393            in.readLine());
394        assertEquals(
395            "-x --help --version] <SOURCE1> [<SOURCE2> ...] <DEST>                           ",
396            in.readLine());
397        assertEquals(
398            "OPTIONS                                                                         ",
399            in.readLine());
400        assertEquals(
401            "  -a (--archive)                same as -dpR                                    ",
402            in.readLine());
403        assertEquals(
404            "  -b (--backup)                 make backup before removal                      ",
405            in.readLine());
406        assertEquals(
407            "  -d (--no-dereference)         preserve links                                  ",
408            in.readLine());
409        assertEquals(
410            "  -f (--force)                  remove existing destinations, never prompt      ",
411            in.readLine());
412        assertEquals(
413            "  -i (--interactive)            prompt before overwrite                         ",
414            in.readLine());
415        assertEquals(
416            "  -l (--link)                   link files instead of copying                   ",
417            in.readLine());
418        assertEquals(
419            "  -p (--preserve)               preserve file attributes if possible            ",
420            in.readLine());
421        assertEquals(
422            "  -P (--parents)                append source path to DIRECTORY                 ",
423            in.readLine());
424        assertEquals(
425            "  -r                            copy recursively, non-directories as files      ",
426            in.readLine());
427        assertEquals(
428            "  --sparse WHEN                 control creation of sparse files                ",
429            in.readLine());
430        assertEquals(
431            "  -R (--recursive)              copy directories recursively                    ",
432            in.readLine());
433        assertEquals(
434            "  -s (--symbolic-link)          make symbolic links instead of copying          ",
435            in.readLine());
436        assertEquals(
437            "  -S (--suffix) SUFFIX          override the usual backup suffix                ",
438            in.readLine());
439        assertEquals(
440            "  -u (--update)                 copy only when the SOURCE file is newer than    ",
441            in.readLine());
442        assertEquals(
443            "                                the destination file or when the destination    ",
444            in.readLine());
445        assertEquals(
446            "                                file is missing                                 ",
447            in.readLine());
448        assertEquals(
449            "  -v (--verbose)                explain what is being done                      ",
450            in.readLine());
451        assertEquals(
452            "  -V (--version-contol) WORD    explain what is being done                      ",
453            in.readLine());
454        assertEquals(
455            "  -x (--one-file-system)        stay on this file system                        ",
456            in.readLine());
457        assertEquals(
458            "  --help                        display this help and exit                      ",
459            in.readLine());
460        assertEquals(
461            "  --version                     output version information and exit             ",
462            in.readLine());
463        assertEquals(
464            "  SOURCE [SOURCE ...]                                                           ",
465            in.readLine());
466        assertEquals(
467            "  DEST                                                                          ",
468            in.readLine());
469        assertNull(in.readLine());
470    }
471}