/*
 * Copyright (C) 2007 The Guava Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.common.io;

import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import java.io.EOFException;
import java.io.FilterReader;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.CharBuffer;
import java.util.List;

/**
 * Unit test for {@link CharStreams}.
 *
 * @author Chris Nokleberg
 */
public class CharStreamsTest extends IoTestCase {

  private static final String TEXT = "The quick brown fox jumped over the lazy dog.";

  public void testToString() throws IOException {
    assertEquals(TEXT, CharStreams.toString(new StringReader(TEXT)));
  }

  public void testReadLines() throws IOException {
    List<String> lines = CharStreams.readLines(new StringReader("a\nb\nc"));
    assertEquals(ImmutableList.of("a", "b", "c"), lines);
  }

  public void testReadLines_withLineProcessor() throws IOException {
    String text = "a\nb\nc";

    // Test a LineProcessor that always returns false.
    Reader r = new StringReader(text);
    LineProcessor<Integer> alwaysFalse =
        new LineProcessor<Integer>() {
          int seen;

          @Override
          public boolean processLine(String line) {
            seen++;
            return false;
          }

          @Override
          public Integer getResult() {
            return seen;
          }
        };
    assertEquals(
        "processLine was called more than once",
        1,
        CharStreams.readLines(r, alwaysFalse).intValue());

    // Test a LineProcessor that always returns true.
    r = new StringReader(text);
    LineProcessor<Integer> alwaysTrue =
        new LineProcessor<Integer>() {
          int seen;

          @Override
          public boolean processLine(String line) {
            seen++;
            return true;
          }

          @Override
          public Integer getResult() {
            return seen;
          }
        };
    assertEquals(
        "processLine was not called for all the lines",
        3,
        CharStreams.readLines(r, alwaysTrue).intValue());

    // Test a LineProcessor that is conditional.
    r = new StringReader(text);
    final StringBuilder sb = new StringBuilder();
    LineProcessor<Integer> conditional =
        new LineProcessor<Integer>() {
          int seen;

          @Override
          public boolean processLine(String line) {
            seen++;
            sb.append(line);
            return seen < 2;
          }

          @Override
          public Integer getResult() {
            return seen;
          }
        };
    assertEquals(2, CharStreams.readLines(r, conditional).intValue());
    assertEquals("ab", sb.toString());
  }

  public void testSkipFully_EOF() throws IOException {
    Reader reader = new StringReader("abcde");
    try {
      CharStreams.skipFully(reader, 6);
      fail("expected EOFException");
    } catch (EOFException expected) {
    }
  }

  public void testSkipFully() throws IOException {
    String testString = "abcdef";
    Reader reader = new StringReader(testString);

    assertEquals(testString.charAt(0), reader.read());
    CharStreams.skipFully(reader, 1);
    assertEquals(testString.charAt(2), reader.read());
    CharStreams.skipFully(reader, 2);
    assertEquals(testString.charAt(5), reader.read());

    assertEquals(-1, reader.read());
  }

  public void testAsWriter() {
    // Should wrap Appendable in a new object
    Appendable plainAppendable = new StringBuilder();
    Writer result = CharStreams.asWriter(plainAppendable);
    assertNotSame(plainAppendable, result);
    assertNotNull(result);

    // A Writer should not be wrapped
    Appendable secretlyAWriter = new StringWriter();
    result = CharStreams.asWriter(secretlyAWriter);
    assertSame(secretlyAWriter, result);
  }

  // CharStreams.copy has type specific optimizations for Readers,StringBuilders and Writers

  public void testCopy() throws IOException {
    StringBuilder builder = new StringBuilder();
    long copied =
        CharStreams.copy(
            wrapAsGenericReadable(new StringReader(ASCII)), wrapAsGenericAppendable(builder));
    assertEquals(ASCII, builder.toString());
    assertEquals(ASCII.length(), copied);

    StringBuilder builder2 = new StringBuilder();
    copied =
        CharStreams.copy(
            wrapAsGenericReadable(new StringReader(I18N)), wrapAsGenericAppendable(builder2));
    assertEquals(I18N, builder2.toString());
    assertEquals(I18N.length(), copied);
  }

  public void testCopy_toStringBuilder_fromReader() throws IOException {
    StringBuilder builder = new StringBuilder();
    long copied = CharStreams.copy(new StringReader(ASCII), builder);
    assertEquals(ASCII, builder.toString());
    assertEquals(ASCII.length(), copied);

    StringBuilder builder2 = new StringBuilder();
    copied = CharStreams.copy(new StringReader(I18N), builder2);
    assertEquals(I18N, builder2.toString());
    assertEquals(I18N.length(), copied);
  }

  public void testCopy_toStringBuilder_fromReadable() throws IOException {
    StringBuilder builder = new StringBuilder();
    long copied = CharStreams.copy(wrapAsGenericReadable(new StringReader(ASCII)), builder);
    assertEquals(ASCII, builder.toString());
    assertEquals(ASCII.length(), copied);

    StringBuilder builder2 = new StringBuilder();
    copied = CharStreams.copy(wrapAsGenericReadable(new StringReader(I18N)), builder2);
    assertEquals(I18N, builder2.toString());
    assertEquals(I18N.length(), copied);
  }

  public void testCopy_toWriter_fromReader() throws IOException {
    StringWriter writer = new StringWriter();
    long copied = CharStreams.copy(new StringReader(ASCII), writer);
    assertEquals(ASCII, writer.toString());
    assertEquals(ASCII.length(), copied);

    StringWriter writer2 = new StringWriter();
    copied = CharStreams.copy(new StringReader(I18N), writer2);
    assertEquals(I18N, writer2.toString());
    assertEquals(I18N.length(), copied);
  }

  public void testCopy_toWriter_fromReadable() throws IOException {
    StringWriter writer = new StringWriter();
    long copied = CharStreams.copy(wrapAsGenericReadable(new StringReader(ASCII)), writer);
    assertEquals(ASCII, writer.toString());
    assertEquals(ASCII.length(), copied);

    StringWriter writer2 = new StringWriter();
    copied = CharStreams.copy(wrapAsGenericReadable(new StringReader(I18N)), writer2);
    assertEquals(I18N, writer2.toString());
    assertEquals(I18N.length(), copied);
  }

  /**
   * Test for Guava issue 1061: http://code.google.com/p/guava-libraries/issues/detail?id=1061
   *
   * <p>CharStreams.copy was failing to clear its CharBuffer after each read call, which effectively
   * reduced the available size of the buffer each time a call to read didn't fill up the available
   * space in the buffer completely. In general this is a performance problem since the buffer size
   * is permanently reduced, but with certain Reader implementations it could also cause the buffer
   * size to reach 0, causing an infinite loop.
   */
  public void testCopyWithReaderThatDoesNotFillBuffer() throws IOException {
    // need a long enough string for the buffer to hit 0 remaining before the copy completes
    String string = Strings.repeat("0123456789", 100);
    StringBuilder b = new StringBuilder();
    // the main assertion of this test is here... the copy will fail if the buffer size goes down
    // each time it is not filled completely
    long copied = CharStreams.copy(newNonBufferFillingReader(new StringReader(string)), b);
    assertEquals(string, b.toString());
    assertEquals(string.length(), copied);
  }

  public void testExhaust_reader() throws IOException {
    Reader reader = new StringReader(ASCII);
    assertEquals(ASCII.length(), CharStreams.exhaust(reader));
    assertEquals(-1, reader.read());
    assertEquals(0, CharStreams.exhaust(reader));

    Reader empty = new StringReader("");
    assertEquals(0, CharStreams.exhaust(empty));
    assertEquals(-1, empty.read());
  }

  public void testExhaust_readable() throws IOException {
    CharBuffer buf = CharBuffer.wrap(ASCII);
    assertEquals(ASCII.length(), CharStreams.exhaust(buf));
    assertEquals(0, buf.remaining());
    assertEquals(0, CharStreams.exhaust(buf));

    CharBuffer empty = CharBuffer.wrap("");
    assertEquals(0, CharStreams.exhaust(empty));
    assertEquals(0, empty.remaining());
  }

  public void testNullWriter() throws Exception {
    // create a null writer
    Writer nullWriter = CharStreams.nullWriter();
    // write to the writer
    nullWriter.write('n');
    String test = "Test string for NullWriter";
    nullWriter.write(test);
    nullWriter.write(test, 2, 10);
    nullWriter.append(null);
    nullWriter.append(null, 0, 4);

    try {
      nullWriter.append(null, -1, 4);
      fail();
    } catch (IndexOutOfBoundsException expected) {
    }

    try {
      nullWriter.append(null, 0, 5);
      fail();
    } catch (IndexOutOfBoundsException expected) {
    }

    // nothing really to assert?
    assertSame(CharStreams.nullWriter(), CharStreams.nullWriter());
  }

  /**
   * Returns a reader wrapping the given reader that only reads half of the maximum number of
   * characters that it could read in read(char[], int, int).
   */
  private static Reader newNonBufferFillingReader(Reader reader) {
    return new FilterReader(reader) {
      @Override
      public int read(char[] cbuf, int off, int len) throws IOException {
        // if a buffer isn't being cleared correctly, this method will eventually start being called
        // with a len of 0 forever
        if (len <= 0) {
          fail("read called with a len of " + len);
        }
        // read fewer than the max number of chars to read
        // shouldn't be a problem unless the buffer is shrinking each call
        return in.read(cbuf, off, Math.max(len - 1024, 0));
      }
    };
  }

  /** Wrap an appendable in an appendable to defeat any type specific optimizations. */
  private static Appendable wrapAsGenericAppendable(final Appendable a) {
    return new Appendable() {

      @Override
      public Appendable append(CharSequence csq) throws IOException {
        a.append(csq);
        return this;
      }

      @Override
      public Appendable append(CharSequence csq, int start, int end) throws IOException {
        a.append(csq, start, end);
        return this;
      }

      @Override
      public Appendable append(char c) throws IOException {
        a.append(c);
        return this;
      }
    };
  }

  /** Wrap a readable in a readable to defeat any type specific optimizations. */
  private static Readable wrapAsGenericReadable(final Readable a) {
    return new Readable() {
      @Override
      public int read(CharBuffer cb) throws IOException {
        return a.read(cb);
      }
    };
  }
}
