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}