// Decode a 200-byte binary frame
  private void sizeLimitDecodeBinaryFrame(int maxSize) throws Exception {
    ProtocolCodecSessionEx session = new ProtocolCodecSessionEx();
    IoBufferAllocatorEx<?> allocator = session.getBufferAllocator();
    ProtocolDecoder decoder = new WsFrameDecoder(allocator, maxSize);

    IoBufferEx in =
        allocator
            .wrap(allocator.allocate(204))
            .put((byte) 0x82)
            .put((byte) 126)
            .put((byte) 0x00)
            .put((byte) 0xC8)
            .fill(200)
            .flip();

    decoder.decode(session, (IoBuffer) in, session.getDecoderOutput());

    WsMessage out = (WsMessage) session.getDecoderOutputQueue().poll();
    assertEquals(
        new WsBinaryMessage(allocator.wrap(allocator.allocate(200)).fill(200).flip()), out);

    assertTrue(session.getDecoderOutputQueue().isEmpty());
    decoder.finishDecode(session, session.getDecoderOutput());

    assertTrue(session.getDecoderOutputQueue().isEmpty());
    assertFalse(in.hasRemaining());
  }
  // Decode a 12-byte text frame and a 15 byte text frame written in one go (one network packet)
  private void sizeLimitDecodeDoubleTextFrame(int maxSize) throws Exception {
    ProtocolCodecSessionEx session = new ProtocolCodecSessionEx();
    IoBufferAllocatorEx<?> allocator = session.getBufferAllocator();
    ProtocolDecoder decoder = new WsFrameDecoder(allocator, maxSize);

    IoBufferEx in =
        allocator
            .wrap(allocator.allocate(12 + 2 + 15 + 2))
            .put((byte) 0x81)
            .put((byte) 12)
            .putString("123456789012", UTF_8.newEncoder())
            .put((byte) 0x81)
            .put((byte) 15)
            .putString("123456789012345", UTF_8.newEncoder())
            .flip();

    decoder.decode(session, (IoBuffer) in, session.getDecoderOutput());

    WsMessage out = (WsMessage) session.getDecoderOutputQueue().poll();
    assertEquals(
        new WsTextMessage(allocator.wrap(ByteBuffer.wrap("123456789012".getBytes(UTF_8)))), out);

    WsMessage out2 = (WsMessage) session.getDecoderOutputQueue().poll();
    assertEquals(
        new WsTextMessage(allocator.wrap(ByteBuffer.wrap("123456789012345".getBytes(UTF_8)))),
        out2);

    assertTrue(session.getDecoderOutputQueue().isEmpty());
    decoder.finishDecode(session, session.getDecoderOutput());

    assertTrue(session.getDecoderOutputQueue().isEmpty());
    assertFalse(in.hasRemaining());
  }
  @Test
  public void decodeTextFrame() throws Exception {
    ProtocolCodecSessionEx session = new ProtocolCodecSessionEx();
    IoBufferAllocatorEx<?> allocator = session.getBufferAllocator();
    ProtocolDecoder decoder = new WsFrameDecoder(allocator, 0);

    IoBufferEx in =
        allocator
            .wrap(allocator.allocate(14))
            .put((byte) 0x81)
            .put((byte) 0x0C)
            .putString("Hello, world", UTF_8.newEncoder())
            .flip();

    decoder.decode(session, (IoBuffer) in, session.getDecoderOutput());

    WsMessage out = (WsMessage) session.getDecoderOutputQueue().poll();
    assertEquals(
        new WsTextMessage(allocator.wrap(ByteBuffer.wrap("Hello, world".getBytes(UTF_8)))), out);

    assertTrue(session.getDecoderOutputQueue().isEmpty());
    decoder.finishDecode(session, session.getDecoderOutput());

    assertTrue(session.getDecoderOutputQueue().isEmpty());
    assertFalse(in.hasRemaining());
  }
  @Test
  public void decodeZeroLengthMaskedPongFrame() throws Exception {
    ProtocolCodecSessionEx session = new ProtocolCodecSessionEx();
    IoBufferAllocatorEx<?> allocator = session.getBufferAllocator();
    ProtocolDecoder decoder = new WsFrameDecoder(allocator, 0);

    IoBufferEx in =
        allocator
            .wrap(allocator.allocate(6))
            .put((byte) 0x8A)
            .put((byte) 0x80)
            .fill(4) // mask
            .flip();

    decoder.decode(session, (IoBuffer) in, session.getDecoderOutput());

    WsMessage out = (WsMessage) session.getDecoderOutputQueue().poll();
    assertEquals(new WsPongMessage(allocator.wrap(allocator.allocate(0)).flip()), out);

    assertTrue(session.getDecoderOutputQueue().isEmpty());
    decoder.finishDecode(session, session.getDecoderOutput());

    assertTrue(session.getDecoderOutputQueue().isEmpty());
    assertFalse(in.hasRemaining());
  }
  @Test
  public void decodeTextContinuationFrameWithFragmentedPayload() throws Exception {
    ProtocolCodecSessionEx session = new ProtocolCodecSessionEx();
    IoBufferAllocatorEx<?> allocator = session.getBufferAllocator();
    ProtocolDecoder decoder = new WsFrameDecoder(allocator, 250);

    String textFramePayload = createString('a', 100);
    String continuationFramePayloadFirstFragment = createString('b', 50);
    String continuationFramePayloadSecondFragment = createString('b', 50);

    IoBufferEx in =
        allocator
            .wrap(allocator.allocate(102))
            // text frame
            .put((byte) 0x01)
            .put((byte) 100)
            .putString(textFramePayload, UTF_8.newEncoder())
            .flip();

    IoBufferEx[] array =
        new IoBufferEx[] {
          allocator
              .wrap(allocator.allocate(2))
              // continuation frame fragment (opcode and payload length)
              .put((byte) 0x80)
              .put((byte) 0x64)
              .flip(),
          allocator
              .wrap(allocator.allocate(50))
              // continuation frame payload first fragment
              .putString(continuationFramePayloadFirstFragment, UTF_8.newEncoder())
              .flip(),
          allocator
              .wrap(allocator.allocate(50))
              // continuation frame payload second fragment
              .putString(continuationFramePayloadSecondFragment, UTF_8.newEncoder())
              .flip()
        };
    decoder.decode(session, (IoBuffer) in, session.getDecoderOutput());

    for (IoBufferEx buffer : array) {
      decoder.decode(session, (IoBuffer) buffer, session.getDecoderOutput());
    }

    WsMessage out1 = (WsMessage) session.getDecoderOutputQueue().poll();
    assertEquals(
        new WsTextMessage(allocator.wrap(ByteBuffer.wrap(textFramePayload.getBytes(UTF_8))), false),
        out1);

    WsMessage out2 = (WsMessage) session.getDecoderOutputQueue().poll();
    assertEquals(
        new WsContinuationMessage(
            allocator.wrap(ByteBuffer.wrap(createString('b', 100).getBytes(UTF_8)))),
        out2);
  }
  @Test
  public void decodeTextContinuationFrame() throws Exception {
    ProtocolCodecSessionEx session = new ProtocolCodecSessionEx();
    IoBufferAllocatorEx<?> allocator = session.getBufferAllocator();
    ProtocolDecoder decoder = new WsFrameDecoder(allocator, 200);

    int firstPayload = 125;
    String first = createString('a', firstPayload);

    int secondPayload = 2;
    String second = createString('b', secondPayload);

    int thirdPayload = 4;
    String thrid = createString('c', thirdPayload);

    IoBufferEx in =
        allocator
            .wrap(allocator.allocate(firstPayload + secondPayload + thirdPayload + 6))
            // text frame
            .put((byte) 0x01)
            .put((byte) firstPayload)
            .putString(first, UTF_8.newEncoder())
            // continuation frame with FIN
            .put((byte) 0x80)
            .put((byte) secondPayload)
            .putString(second, UTF_8.newEncoder())
            // text frame with FIN
            .put((byte) 0x81)
            .put((byte) thirdPayload)
            .putString(thrid, UTF_8.newEncoder())
            .flip();

    decoder.decode(session, (IoBuffer) in, session.getDecoderOutput());

    WsMessage out1 = (WsMessage) session.getDecoderOutputQueue().poll();
    assertEquals(
        new WsTextMessage(allocator.wrap(ByteBuffer.wrap(first.getBytes(UTF_8))), false), out1);

    WsMessage out2 = (WsMessage) session.getDecoderOutputQueue().poll();
    assertEquals(
        new WsContinuationMessage(allocator.wrap(ByteBuffer.wrap(second.getBytes(UTF_8)))), out2);

    WsMessage out3 = (WsMessage) session.getDecoderOutputQueue().poll();
    assertEquals(new WsTextMessage(allocator.wrap(ByteBuffer.wrap(thrid.getBytes(UTF_8)))), out3);

    assertTrue(session.getDecoderOutputQueue().isEmpty());
    decoder.finishDecode(session, session.getDecoderOutput());

    assertTrue(session.getDecoderOutputQueue().isEmpty());
    assertFalse(in.hasRemaining());
  }
  @Test
  public void decodeBinaryContinuationFrameWithFragmentedPayload() throws Exception {
    ProtocolCodecSessionEx session = new ProtocolCodecSessionEx();
    IoBufferAllocatorEx<?> allocator = session.getBufferAllocator();
    ProtocolDecoder decoder = new WsFrameDecoder(allocator, 250);

    byte[] binaryFramePayload = createString('a', 100).getBytes();
    byte[] continuationFramePayload = createString('b', 100).getBytes();

    IoBufferEx in =
        allocator
            .wrap(allocator.allocate(102))
            // binary frame
            .put((byte) 0x02)
            .put((byte) 100)
            .put(binaryFramePayload)
            .flip();

    IoBufferEx[] array =
        new IoBufferEx[] {
          allocator
              .wrap(allocator.allocate(2))
              // continuation frame fragment (opcode and payload length)
              .put((byte) 0x80)
              .put((byte) 0x64)
              .flip(),
          allocator
              .wrap(allocator.allocate(50))
              // continuation frame first fragment
              .put(continuationFramePayload, 0, 50)
              .flip(),
          allocator
              .wrap(allocator.allocate(50))
              // continuation frame second fragment
              .put(continuationFramePayload, 50, 50)
              .flip()
        };
    decoder.decode(session, (IoBuffer) in, session.getDecoderOutput());

    for (IoBufferEx buffer : array) {
      decoder.decode(session, (IoBuffer) buffer, session.getDecoderOutput());
    }

    WsMessage out1 = (WsMessage) session.getDecoderOutputQueue().poll();
    assertEquals(
        new WsBinaryMessage(allocator.wrap(ByteBuffer.wrap(binaryFramePayload)), false), out1);

    WsMessage out2 = (WsMessage) session.getDecoderOutputQueue().poll();
    assertEquals(
        new WsContinuationMessage(allocator.wrap(ByteBuffer.wrap(continuationFramePayload))), out2);
  }
  @Test
  public void decodeBinaryContinuationFrame() throws Exception {
    ProtocolCodecSessionEx session = new ProtocolCodecSessionEx();
    IoBufferAllocatorEx<?> allocator = session.getBufferAllocator();
    ProtocolDecoder decoder = new WsFrameDecoder(allocator, 200);

    int firstPayload = 125;
    byte[] first = createString('a', firstPayload).getBytes("UTF-8");

    int secondPayload = 2;
    byte[] second = createString('b', secondPayload).getBytes("UTF-8");

    int thirdPayload = 4;
    byte[] thrid = createString('c', thirdPayload).getBytes("UTF-8");

    IoBufferEx in =
        allocator
            .wrap(allocator.allocate(firstPayload + secondPayload + thirdPayload + 6))
            // binary frame
            .put((byte) 0x02)
            .put((byte) firstPayload)
            .put(first)
            // continuation frame with FIN
            .put((byte) 0x80)
            .put((byte) secondPayload)
            .put(second)
            // binary frame with FIN
            .put((byte) 0x82)
            .put((byte) thirdPayload)
            .put(thrid)
            .flip();

    decoder.decode(session, (IoBuffer) in, session.getDecoderOutput());

    WsMessage out1 = (WsMessage) session.getDecoderOutputQueue().poll();
    assertEquals(new WsBinaryMessage(allocator.wrap(ByteBuffer.wrap(first)), false), out1);

    WsMessage out2 = (WsMessage) session.getDecoderOutputQueue().poll();
    assertEquals(new WsContinuationMessage(allocator.wrap(ByteBuffer.wrap(second))), out2);

    WsMessage out3 = (WsMessage) session.getDecoderOutputQueue().poll();
    assertEquals(new WsBinaryMessage(allocator.wrap(ByteBuffer.wrap(thrid))), out3);

    assertTrue(session.getDecoderOutputQueue().isEmpty());
    decoder.finishDecode(session, session.getDecoderOutput());

    assertTrue(session.getDecoderOutputQueue().isEmpty());
    assertFalse(in.hasRemaining());
  }
  @Test
  public void decodeFragmentedBinaryFrame() throws Exception {
    ProtocolCodecSessionEx session = new ProtocolCodecSessionEx();
    IoBufferAllocatorEx<?> allocator = session.getBufferAllocator();
    ProtocolDecoder decoder = new WsFrameDecoder(allocator, 0);

    IoBufferEx[] array =
        new IoBufferEx[] {
          allocator
              .wrap(allocator.allocate(104))
              .put((byte) 0x82)
              .put((byte) 126)
              .put((byte) 0x00)
              .put((byte) 0xC8)
              .fill(100)
              .flip(),
          allocator
              .wrap(allocator.allocate(102))
              .fill(100)
              .put((byte) 0x82)
              .put((byte) 0x00)
              .flip(),
        };

    for (IoBufferEx in : array) {
      decoder.decode(session, (IoBuffer) in, session.getDecoderOutput());
    }

    WsMessage fragmented = (WsMessage) session.getDecoderOutputQueue().poll();
    assertEquals(
        new WsBinaryMessage(allocator.wrap(allocator.allocate(200)).fill(200).flip()), fragmented);

    WsMessage empty = (WsMessage) session.getDecoderOutputQueue().poll();
    assertEquals(new WsBinaryMessage(allocator.wrap(allocator.allocate(0))), empty);

    assertTrue(session.getDecoderOutputQueue().isEmpty());
    decoder.finishDecode(session, session.getDecoderOutput());

    assertTrue(session.getDecoderOutputQueue().isEmpty());

    for (IoBufferEx in : array) {
      assertFalse(in.hasRemaining());
    }
  }
  @Test
  public void decodeFragmentedTextFrame() throws Exception {
    ProtocolCodecSessionEx session = new ProtocolCodecSessionEx();
    IoBufferAllocatorEx<?> allocator = session.getBufferAllocator();
    ProtocolDecoder decoder = new WsFrameDecoder(allocator, 0);

    IoBufferEx[] array =
        new IoBufferEx[] {
          allocator
              .wrap(allocator.allocate(103))
              .put((byte) 0x81)
              .put((byte) 0x0C)
              .putString("Hello", UTF_8.newEncoder())
              .flip(),
          allocator
              .wrap(allocator.allocate(102))
              .putString(", world", UTF_8.newEncoder())
              .put((byte) 0x81)
              .put((byte) 0x00)
              .flip(),
        };

    for (IoBufferEx in : array) {
      decoder.decode(session, (IoBuffer) in, session.getDecoderOutput());
    }

    WsMessage fragmented = (WsMessage) session.getDecoderOutputQueue().poll();
    assertEquals(
        new WsTextMessage(allocator.wrap(ByteBuffer.wrap("Hello, world".getBytes(UTF_8)))),
        fragmented);

    WsMessage empty = (WsMessage) session.getDecoderOutputQueue().poll();
    assertEquals(new WsTextMessage(allocator.wrap(allocator.allocate(0))), empty);

    assertTrue(session.getDecoderOutputQueue().isEmpty());
    decoder.finishDecode(session, session.getDecoderOutput());

    assertTrue(session.getDecoderOutputQueue().isEmpty());

    for (IoBufferEx in : array) {
      assertFalse(in.hasRemaining());
    }
  }
  @Test
  public void pingInBinaryContinuationSequence() throws Exception {
    ProtocolCodecSessionEx session = new ProtocolCodecSessionEx();
    IoBufferAllocatorEx<?> allocator = session.getBufferAllocator();
    ProtocolDecoder decoder = new WsFrameDecoder(allocator, 400);

    int firstPayload = 125;
    byte[] first = createString('a', firstPayload).getBytes("UTF-8");

    int secondPayload = 125;
    byte[] second = createString('b', secondPayload).getBytes("UTF-8");

    int thirdPayload = 4;
    byte[] third = createString('c', thirdPayload).getBytes("UTF-8");

    int fourthPayload = 6;
    String fourth = createString('d', fourthPayload);

    IoBufferEx in =
        allocator
            .wrap(
                allocator.allocate(
                    firstPayload + secondPayload + 2 + thirdPayload + fourthPayload + 8))
            // text frame
            .put((byte) 0x01)
            .put((byte) firstPayload)
            .put(first)
            // continuation frame
            .put((byte) 0x00)
            .put((byte) secondPayload)
            .put(second)
            // ping frame
            .put((byte) 0x89)
            .put((byte) 0x00)
            // continuation frame with FIN
            .put((byte) 0x80)
            .put((byte) thirdPayload)
            .put(third)
            // binary frame
            .put((byte) 0x82)
            .put((byte) fourthPayload)
            .putString(fourth, UTF_8.newEncoder())
            .flip();

    decoder.decode(session, (IoBuffer) in, session.getDecoderOutput());

    WsMessage out1 = (WsMessage) session.getDecoderOutputQueue().poll();
    assertEquals(new WsTextMessage(allocator.wrap(ByteBuffer.wrap(first)), false), out1);

    WsMessage out2 = (WsMessage) session.getDecoderOutputQueue().poll();
    assertEquals(new WsContinuationMessage(allocator.wrap(ByteBuffer.wrap(second)), false), out2);

    WsMessage out = (WsMessage) session.getDecoderOutputQueue().poll();
    assertEquals(new WsPingMessage(allocator.wrap(allocator.allocate(0))), out);

    WsMessage out3 = (WsMessage) session.getDecoderOutputQueue().poll();
    assertEquals(new WsContinuationMessage(allocator.wrap(ByteBuffer.wrap(third))), out3);

    WsMessage out4 = (WsMessage) session.getDecoderOutputQueue().poll();
    assertEquals(
        new WsBinaryMessage(allocator.wrap(ByteBuffer.wrap(fourth.getBytes(UTF_8)))), out4);

    assertTrue(session.getDecoderOutputQueue().isEmpty());
    decoder.finishDecode(session, session.getDecoderOutput());

    assertTrue(session.getDecoderOutputQueue().isEmpty());
    assertFalse(in.hasRemaining());
  }