1 /*
   2  * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /* @test
  25  * @bug 5067405
  26  * @summary Basic test for classes which implement Appendable.
  27  */
  28 
  29 import java.io.BufferedReader;
  30 import java.io.BufferedWriter;
  31 import java.io.ByteArrayOutputStream;
  32 import java.io.CharArrayWriter;
  33 import java.io.File;
  34 import java.io.FileReader;
  35 import java.io.FileWriter;
  36 import java.io.IOException;
  37 import java.io.OutputStreamWriter;
  38 import java.io.PrintStream;
  39 import java.io.PrintWriter;
  40 import java.io.StringWriter;
  41 import java.io.Writer;
  42 import java.nio.ByteBuffer;
  43 import java.nio.CharBuffer;
  44 
  45 interface BasicRunnable extends Runnable {
  46     void init(Appendable a, String csq, String exp);
  47     Appendable reset(Appendable csq);
  48 }
  49 
  50 public class Basic {
  51 
  52     private static final String s = "Beware the Jabberwock, my son!";
  53     private static CharArrayWriter gw = new CharArrayWriter();
  54     private static ByteArrayOutputStream gos = new ByteArrayOutputStream();
  55 
  56     private static File newFile() {
  57         File f = null;
  58         try {
  59             f = File.createTempFile("append", ".txt");
  60             f.deleteOnExit();
  61         } catch (IOException x) {
  62             fail(x);
  63         }
  64         return f;
  65     }
  66     private static File gf = newFile();
  67 
  68     private static int fail = 0;
  69     private static int pass = 0;
  70 
  71     private static Throwable first;
  72 
  73     static void pass() {
  74         pass++;
  75     }
  76 
  77     static void fail(Throwable ex) {
  78         if (first == null)
  79             first = ex;
  80         System.err.println("FAILED: unexpected exception");
  81         fail++;
  82     }
  83 
  84     static void fail(String fs, Throwable ex) {
  85         String s = "'" + fs + "': " + ex.getClass().getName() + " not thrown";
  86         if (first == null)
  87             first = ex;
  88         System.err.println("FAILED: " + s);
  89         fail++;
  90     }
  91 
  92     static void fail(String fs, String exp, String got) {
  93         String s = "'" + fs + "': Expected '" + exp + "', got '" + got + "'";
  94         if (first == null)
  95             first = new RuntimeException(s);
  96         System.err.println("FAILED: " + s);
  97         fail++;
  98     }
  99 
 100     static void ck(String s, String exp, String got) {
 101         if (!exp.equals(got))
 102             fail(s, exp, got);
 103         else
 104             pass();
 105     }
 106 
 107     private static BasicRunnable testBufferedWriter =
 108         new BasicRunnable() {
 109             private String csn, exp;
 110             public void init(Appendable bw, String csn, String exp) {
 111                 try {
 112                     ((BufferedWriter)bw).flush();
 113                 } catch (IOException x) {
 114                     fail(x);
 115                 }
 116                 this.csn = csn;
 117                 this.exp = exp;
 118             }
 119             public void run() {
 120                 ck("BufferedWriter.append(" + csn + ")", exp, gw.toString());
 121             }
 122             public Appendable reset(Appendable bw) {
 123                 gw.reset();
 124                 return bw;
 125             }};
 126 
 127     private static BasicRunnable testCharArrayWriter =
 128         new BasicRunnable() {
 129             private String csn, exp;
 130             private CharArrayWriter cw;
 131             public void init(Appendable cw, String csn, String exp) {
 132                 this.cw = (CharArrayWriter)cw;
 133                 this.csn = csn;
 134                 this.exp = exp;
 135             }
 136             public void run() {
 137                 ck("CharArrayWriter.append(" + csn + ")", exp, cw.toString());
 138             }
 139             public Appendable reset(Appendable cw) {
 140                 ((CharArrayWriter)cw).reset();
 141                 return cw;
 142             }};
 143 
 144     private static BasicRunnable testFileWriter =
 145         new BasicRunnable() {
 146             private String csn, exp;
 147             public void init(Appendable fw, String csn, String exp) {
 148                 try {
 149                     ((FileWriter)fw).flush();
 150                 } catch (IOException x) {
 151                     fail(x);
 152                 }
 153                 this.csn = csn;
 154                 this.exp = exp;
 155             }
 156             public void run() {
 157                 StringBuilder sb = new StringBuilder();
 158                 try {
 159                     BufferedReader in = new BufferedReader(new FileReader(gf));
 160                     String line;
 161                     while (true) {
 162                         if ((line = in.readLine()) == null)
 163                             break;
 164                         sb.append(line);
 165                     }
 166                 } catch (IOException x) {
 167                     fail(x);
 168                 }
 169                 ck("FileWriter.append(" + csn + ")", exp, sb.toString());
 170             }
 171             public Appendable reset(Appendable fw) {
 172                 try {
 173                     fw = new FileWriter(gf);
 174                 } catch (IOException x) {
 175                     fail(x);
 176                 }
 177                 return fw;
 178             }};
 179 
 180     private static BasicRunnable testOutputStreamWriter =
 181         new BasicRunnable() {
 182             private String csn, exp;
 183             public void init(Appendable osw, String csn, String exp) {
 184                 try {
 185                     ((OutputStreamWriter)osw).flush();
 186                 } catch (IOException x) {
 187                     fail(x);
 188                 }
 189                 this.csn = csn;
 190                 this.exp = exp;
 191             }
 192             public void run() {
 193                 ck("OutputStreamWriter.append(" + csn + ")", exp, gos.toString());
 194             }
 195             public Appendable reset(Appendable osw) {
 196                 gos.reset();
 197                 return osw;
 198             }};
 199 
 200     private static BasicRunnable testPrintWriter =
 201         new BasicRunnable() {
 202             private String csn, exp;
 203             public void init(Appendable pw, String csn, String exp) {
 204                 ((PrintWriter)pw).flush();
 205                 this.csn = csn;
 206                 this.exp = exp;
 207             }
 208             public void run() {
 209                 ck("PrintWriter.append(" + csn + ")", exp, gw.toString());
 210             }
 211             public Appendable reset(Appendable pw) {
 212                 gw.reset();
 213                 return pw;
 214             }};
 215 
 216     private static BasicRunnable testStringWriter =
 217         new BasicRunnable() {
 218             private String csn, exp;
 219             private StringWriter sw;
 220             public void init(Appendable sw, String csn, String exp) {
 221                 this.sw = (StringWriter)sw;
 222                 this.csn = csn;
 223                 this.exp = exp;
 224             }
 225             public void run() {
 226                 ck("StringWriter.append(" + csn + ")", exp, sw.toString());
 227             }
 228             public Appendable reset(Appendable sw) {
 229                 return new StringWriter();
 230             }};
 231 
 232     private static BasicRunnable testPrintStream =
 233         new BasicRunnable() {
 234             private String csn, exp;
 235             public void init(Appendable ps, String csn, String exp) {
 236                 ((PrintStream)ps).flush();
 237                 this.csn = csn;
 238                 this.exp = exp;
 239             }
 240             public void run() {
 241                 ck("PrintStream.append(" + csn + ")", exp, gos.toString());
 242             }
 243             public Appendable reset(Appendable ps) {
 244                 gos.reset();
 245                 return ps;
 246             }};
 247 
 248     private static BasicRunnable testCharBuffer =
 249         new BasicRunnable() {
 250             private String csn, exp;
 251             private CharBuffer cb;
 252             public void init(Appendable cb, String csn, String exp) {
 253                 this.cb = (CharBuffer)cb;
 254                 this.csn = csn;
 255                 this.exp = exp;
 256             }
 257             public void run() {
 258                 cb.limit(cb.position()).rewind();
 259                 ck("CharBuffer.append(" + csn + ")", exp, cb.toString());
 260             }
 261             public Appendable reset(Appendable cb) {
 262                 ((CharBuffer)cb).clear();
 263                 return cb;
 264             }};
 265 
 266     private static BasicRunnable testStringBuffer =
 267         new BasicRunnable() {
 268             private String csn, exp;
 269             private StringBuffer sb;
 270             public void init(Appendable sb, String csn, String exp) {
 271                 this.sb = (StringBuffer)sb;
 272                 this.csn = csn;
 273                 this.exp = exp;
 274             }
 275             public void run() {
 276                 ck("StringBuffer.append(" + csn + ")", exp, sb.toString());
 277             }
 278             public Appendable reset(Appendable sb) {
 279                 return new StringBuffer();
 280             }};
 281 
 282     private static BasicRunnable testStringBuilder =
 283         new BasicRunnable() {
 284             private String csn, exp;
 285             private StringBuilder sb;
 286             public void init(Appendable sb, String csn, String exp) {
 287                 this.sb = (StringBuilder)sb;
 288                 this.csn = csn;
 289                 this.exp = exp;
 290             }
 291             public void run() {
 292                 ck("StringBuilder.append(" + csn + ")", exp, sb.toString());
 293             }
 294             public Appendable reset(Appendable sb) {
 295                 return new StringBuilder();
 296             }};
 297 
 298     private static void test(Appendable a, CharSequence csq, BasicRunnable thunk) {
 299         // appends that should always work
 300         int [][] sp = { { 0, 0 }, { 11, 11 }, { 11, 21 }, { 0, 7 },
 301                         { 0, s.length() }, { s.length(), s.length() },
 302         };
 303         for (int j = 0; j < sp.length; j++) {
 304             int start = sp[j][0];
 305             int end = sp[j][1];
 306             try {
 307                 thunk.init(a.append(csq, start, end),
 308                            csq.getClass().getName(),
 309                            s.subSequence(start, end).toString());
 310                 thunk.run();
 311                 a = thunk.reset(a);
 312             } catch (IOException x) {
 313                 fail(x);
 314             }
 315         }
 316 
 317         // appends that should always throw IndexOutOfBoundsException
 318         int [][] sf = { { -1, 0 }, { 0, -1 }, { 11, 10 },
 319                         { 0, s.length() + 1},
 320         };
 321         for (int j = 0; j < sf.length; j++) {
 322             int start = sf[j][0];
 323             int end = sf[j][1];
 324             try {
 325                 a.append(csq, start, end);
 326                 fail("start = " + start + ", end = " + end,
 327                      new IndexOutOfBoundsException());
 328                 a = thunk.reset(a);
 329             } catch (IndexOutOfBoundsException x) {
 330                 pass();
 331             } catch (IOException x) {
 332                 fail(x);
 333             }
 334         }
 335 
 336         // appendN with negative count
 337         int[] neg = { -1, -2, -65537, Integer.MIN_VALUE + 1, Integer.MIN_VALUE };
 338         for (int j = 0; j < neg.length; j++) {
 339             try {
 340                 a.appendN('%', neg[j]);
 341                 fail("repeat count = " + neg[j], new IllegalArgumentException());
 342                 a = thunk.reset(a);
 343             } catch (IllegalArgumentException x) {
 344                 pass();
 345             } catch (IOException x) {
 346                 fail(x);
 347             }
 348         }
 349 
 350         // appends of null
 351         int start = 1;
 352         int end = 2;
 353         try {
 354             thunk.init(a.append(null, start, end), "null",
 355                        "null".subSequence(start, end).toString());
 356             thunk.run();
 357             a = thunk.reset(a);
 358         } catch (IOException x) {
 359             fail(x);
 360         }
 361 
 362         // appendN
 363         for (int i = 128; i > 0; ) {
 364             try {
 365                 i /= 2;
 366                 String s = "";
 367                 for (int j = 0; j < i; j++) {
 368                     s += "@";
 369                 }
 370                 thunk.init(a.appendN('@', i), "'@' x 0", s);
 371                 thunk.run();
 372                 a = thunk.reset(a);
 373             } catch (IOException x) {
 374                 fail(x);
 375             }
 376         }
 377     }
 378 
 379     public static void main(String [] args) throws Exception {
 380         // CharSequences
 381         CharBuffer cb = CharBuffer.allocate(128).put(s);
 382         cb.limit(s.length()).rewind();
 383         CharBuffer dcb = ByteBuffer.allocateDirect(128).asCharBuffer().put(s);
 384         dcb.limit(s.length()).rewind();
 385         CharSequence [] ca = { s,
 386                                new StringBuffer(s),
 387                                new StringBuilder(s),
 388                                cb,
 389                                dcb,
 390         };
 391 
 392         // Appendables/Writers
 393         Object [][] wa = { { new CharArrayWriter(), testCharArrayWriter },
 394                            { new BufferedWriter(gw), testBufferedWriter },
 395                            // abstract, no implementing classes in jdk
 396                            // { new FilterWriter(), testFilterWriter },
 397                            { new FileWriter(gf), testFileWriter },
 398                            { new OutputStreamWriter(gos), testOutputStreamWriter },
 399                            // covered by previous two test cases
 400                            // { new PipedWriter(gw), testPipedWriter },
 401                            { new PrintWriter(gw), testPrintWriter },
 402                            { new StringWriter(), testStringWriter },
 403         };
 404 
 405         for (int i = 0; i < ca.length; i++) {
 406             CharSequence a = ca[i];
 407             for (int j = 0; j < wa.length; j++)
 408                 test((Writer)wa[j][0], a, (BasicRunnable)wa[j][1]);
 409 
 410             // other Appendables
 411             test(new PrintStream(gos), a, testPrintStream);
 412             test(CharBuffer.allocate(128), a, testCharBuffer);
 413             test(ByteBuffer.allocateDirect(128).asCharBuffer(), a, testCharBuffer);
 414             test(new StringBuffer(), a, testStringBuffer);
 415             test(new StringBuilder(), a, testStringBuilder);
 416         }
 417 
 418         if (fail != 0)
 419             throw new RuntimeException((fail + pass) + " tests: "
 420                                        + fail + " failure(s), first", first);
 421         else
 422             System.out.println("all " + (fail + pass) + " tests passed");
 423     }
 424 }