/*
 * Copyright 2012 The Netty Project
 *
 * The Netty Project licenses this file to you 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 io.netty.handler.codec;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufIndexFinder;
import io.netty.buffer.MessageBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.embedded.EmbeddedByteChannel;
import org.junit.Test;

import static org.junit.Assert.*;

public class ReplayingDecoderTest {

    @Test
    public void testLineProtocol() {
        EmbeddedByteChannel ch = new EmbeddedByteChannel(new LineDecoder());

        // Ordinary input
        ch.writeInbound(Unpooled.wrappedBuffer(new byte[] { 'A' }));
        assertNull(ch.readInbound());
        ch.writeInbound(Unpooled.wrappedBuffer(new byte[] { 'B' }));
        assertNull(ch.readInbound());
        ch.writeInbound(Unpooled.wrappedBuffer(new byte[] { 'C' }));
        assertNull(ch.readInbound());
        ch.writeInbound(Unpooled.wrappedBuffer(new byte[] { '\n' }));
        assertEquals(Unpooled.wrappedBuffer(new byte[] { 'A', 'B', 'C' }), ch.readInbound());

        // Truncated input
        ch.writeInbound(Unpooled.wrappedBuffer(new byte[] { 'A' }));
        assertNull(ch.readInbound());
        ch.close();
        assertNull(ch.readInbound());
    }

    private static final class LineDecoder extends ReplayingDecoder<Void> {

        LineDecoder() {
        }

        @Override
        protected void decode(ChannelHandlerContext ctx, ByteBuf in, MessageBuf<Object> out) {
            ByteBuf msg = in.readBytes(in.bytesBefore(ByteBufIndexFinder.LF));
            in.skipBytes(1);
            out.add(msg);
        }
    }
}

@@ -851,16 +851,74 @@
 ontext;%0A
+import io.netty.channel.ChannelInboundByteHandlerAdapter;%0A
 import i
@@ -963,16 +963,41 @@
 hannel;%0A
+import org.junit.Ignore;%0A
 import o
@@ -1847,32 +1847,33 @@
 readInbound());%0A
+%0A
         ch.close
@@ -1871,13 +1871,14 @@
  ch.
-close
+finish
 ();%0A
@@ -2255,16 +2255,16 @@
 tes(1);%0A
-
         
@@ -2296,11 +2296,996 @@
  %7D%0A    %7D
+%0A%0A    @Test%0A    @Ignore(%22needs a fix%22)%0A    public void testReplacement() throws Exception %7B%0A        EmbeddedByteChannel ch = new EmbeddedByteChannel(new BloatedLineDecoder());%0A%0A        // %22AB%22 should be forwarded to LineDecoder by BloatedLineDecoder.%0A        ch.writeInbound(Unpooled.wrappedBuffer(new byte%5B%5D%7B'A', 'B'%7D));%0A        assertNull(ch.readInbound());%0A%0A        // %22C%5Cn%22 should be appended to %22AB%22 so that LineDecoder decodes it correctly.%0A        ch.writeInbound(Unpooled.wrappedBuffer(new byte%5B%5D%7B'C', '%5Cn'%7D));%0A        assertEquals(Unpooled.wrappedBuffer(new byte%5B%5D %7B 'A', 'B', 'C' %7D), ch.readInbound());%0A%0A        ch.finish();%0A        assertNull(ch.readInbound());%0A    %7D%0A%0A    private static final class BloatedLineDecoder extends ChannelInboundByteHandlerAdapter %7B%0A        @Override%0A        protected void inboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf in) throws Exception %7B%0A            ctx.pipeline().replace(this, %22less-bloated%22, new LineDecoder());%0A        %7D%0A    %7D
 %0A%7D%0A

Add a failing test that will pass once #1306 is fixed