Home | History | Annotate | Download | only in reporters
      1 package org.testng.reporters;
      2 
      3 import java.io.BufferedWriter;
      4 import java.io.File;
      5 import java.io.FileReader;
      6 import java.io.FileWriter;
      7 import java.io.IOException;
      8 import java.io.Reader;
      9 import java.io.StringReader;
     10 import java.io.Writer;
     11 import java.util.Random;
     12 
     13 /**
     14  * A string buffer that flushes its content to a temporary file whenever the internal
     15  * string buffer becomes larger than MAX. If the buffer never reaches that size, no file
     16  * is ever created and everything happens in memory, so the overhead compared to
     17  * StringBuffer/StringBuilder is minimal.
     18  *
     19  * Note: calling toString() will force the entire string to be loaded in memory, use
     20  * toWriter() if you need to avoid this.
     21  *
     22  * This class is not multi thread safe.
     23  *
     24  * @author Cedric Beust <cedric (at) beust.com>
     25  *
     26  * @since Nov 9, 2012
     27  */
     28 public class FileStringBuffer implements IBuffer {
     29   private static int MAX = 100000;
     30   private static final boolean VERBOSE = System.getProperty("fileStringBuffer") != null;
     31 
     32   private File m_file;
     33   private StringBuilder m_sb = new StringBuilder();
     34   private final int m_maxCharacters;
     35 
     36   public FileStringBuffer() {
     37     this(MAX);
     38   }
     39 
     40   public FileStringBuffer(int maxCharacters) {
     41     m_maxCharacters = maxCharacters;
     42   }
     43 
     44   @Override
     45   public FileStringBuffer append(CharSequence s) {
     46     if (s == null) {
     47       throw new IllegalArgumentException("CharSequence (Argument 0 of FileStringBuffer#append) should not be null");
     48     }
     49 //    m_sb.append(s);
     50     if (m_sb.length() > m_maxCharacters) {
     51       flushToFile();
     52     }
     53     if (s.length() < MAX) {
     54       // Small string, add it to our internal buffer
     55       m_sb.append(s);
     56     } else {
     57       // Big string, add it to the temporary file directly
     58       flushToFile();
     59       try {
     60         copy(new StringReader(s.toString()), new FileWriter(m_file, true /* append */));
     61       } catch (IOException e) {
     62         e.printStackTrace();
     63       }
     64     }
     65     return this;
     66   }
     67 
     68   @Override
     69   public void toWriter(Writer fw) {
     70     if (fw == null) {
     71       throw new IllegalArgumentException("Writer (Argument 0 of FileStringBuffer#toWriter) should not be null");
     72     }
     73     try {
     74       BufferedWriter bw = new BufferedWriter(fw);
     75       if (m_file == null) {
     76         bw.write(m_sb.toString());
     77         bw.close();
     78       } else {
     79         flushToFile();
     80         copy(new FileReader(m_file), bw);
     81       }
     82     } catch(IOException ex) {
     83       ex.printStackTrace();
     84     }
     85   }
     86 
     87   private static void copy(Reader input, Writer output)
     88       throws IOException {
     89     char[] buf = new char[MAX];
     90     while (true) {
     91       int length = input.read(buf);
     92       if (length < 0) break;
     93       output.write(buf, 0, length);
     94     }
     95 
     96     try {
     97       input.close();
     98     } catch (IOException ignore) {
     99     }
    100     try {
    101       output.close();
    102     } catch (IOException ignore) {
    103     }
    104   }
    105 
    106   private void flushToFile() {
    107     if (m_sb.length() == 0) return;
    108 
    109     if (m_file == null) {
    110       try {
    111         m_file = File.createTempFile("testng", "fileStringBuffer");
    112         m_file.deleteOnExit();
    113         p("Created temp file " + m_file);
    114       } catch (IOException e) {
    115         e.printStackTrace();
    116       }
    117     }
    118 
    119     p("Size " + m_sb.length() + ", flushing to " + m_file);
    120     try (FileWriter fw = new FileWriter(m_file, true /* append */)) {
    121       fw.append(m_sb);
    122     } catch (IOException e) {
    123       e.printStackTrace();
    124     }
    125     m_sb = new StringBuilder();
    126   }
    127 
    128   private static void p(String s) {
    129     if (VERBOSE) {
    130       System.out.println("[FileStringBuffer] " + s);
    131     }
    132   }
    133 
    134   @Override
    135   public String toString() {
    136     String result = null;
    137     if (m_file != null) {
    138       flushToFile();
    139       try {
    140         result = Files.readFile(m_file);
    141       } catch (IOException e) {
    142         e.printStackTrace();
    143       }
    144     } else {
    145       result = m_sb.toString();
    146     }
    147     return result;
    148   }
    149 
    150   private static void save(File expected, String s) throws IOException {
    151     expected.delete();
    152     try (FileWriter expectedWriter = new FileWriter(expected)) {
    153       expectedWriter.append(s);
    154     }
    155   }
    156 
    157   public static void main(String[] args) throws IOException {
    158     String s = "abcdefghijklmnopqrstuvwxyz";
    159     FileStringBuffer fsb = new FileStringBuffer(10);
    160     StringBuilder control = new StringBuilder();
    161     Random r = new Random();
    162     for (int i = 0; i < 1000; i++) {
    163       int start = Math.abs(r.nextInt() % 26);
    164       int length = Math.abs(r.nextInt() % (26 - start));
    165       String fragment = s.substring(start, start + length);
    166       p("... Appending " + fragment);
    167       fsb.append(fragment);
    168       control.append(fragment);
    169     }
    170 
    171     File expected = new File("/tmp/expected");
    172     expected.delete();
    173     FileWriter expectedWriter = new FileWriter(expected);
    174     expectedWriter.append(control);
    175     expectedWriter.close();
    176 
    177     File actual = new File("/tmp/actual");
    178     actual.delete();
    179     FileWriter actualWriter = new FileWriter(actual);
    180     fsb.toWriter(actualWriter);
    181     actualWriter.close();
    182 //    Assert.assertEquals(fsb.toString(), control.toString());
    183   }
    184 
    185 }
    186