001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020package org.apache.mina.filter.codec; 021 022import static org.junit.Assert.assertEquals; 023import static org.junit.Assert.assertFalse; 024import static org.junit.Assert.assertTrue; 025import static org.junit.Assert.fail; 026 027import java.net.SocketAddress; 028 029import org.apache.mina.core.buffer.IoBuffer; 030import org.apache.mina.core.service.DefaultTransportMetadata; 031import org.apache.mina.core.session.IoSession; 032import org.apache.mina.core.session.IoSessionConfig; 033import org.junit.After; 034import org.junit.Before; 035import org.junit.Test; 036 037/** 038 * Tests {@link CumulativeProtocolDecoder}. 039 * 040 * @author <a href="http://mina.apache.org">Apache MINA Project</a> 041 */ 042public class CumulativeProtocolDecoderTest { 043 private final ProtocolCodecSession session = new ProtocolCodecSession(); 044 045 private IoBuffer buf; 046 047 private IntegerDecoder decoder; 048 049 @Before 050 public void setUp() throws Exception { 051 buf = IoBuffer.allocate(16); 052 decoder = new IntegerDecoder(); 053 session.setTransportMetadata(new DefaultTransportMetadata("mina", "dummy", false, true, SocketAddress.class, 054 IoSessionConfig.class, IoBuffer.class)); 055 } 056 057 @After 058 public void tearDown() throws Exception { 059 decoder.dispose(session); 060 } 061 062 @Test 063 public void testCumulation() throws Exception { 064 buf.put((byte) 0); 065 buf.flip(); 066 067 decoder.decode(session, buf, session.getDecoderOutput()); 068 assertEquals(0, session.getDecoderOutputQueue().size()); 069 assertEquals(buf.limit(), buf.position()); 070 071 buf.clear(); 072 buf.put((byte) 0); 073 buf.put((byte) 0); 074 buf.put((byte) 1); 075 buf.flip(); 076 077 decoder.decode(session, buf, session.getDecoderOutput()); 078 assertEquals(1, session.getDecoderOutputQueue().size()); 079 assertEquals(new Integer(1), session.getDecoderOutputQueue().poll()); 080 assertEquals(buf.limit(), buf.position()); 081 } 082 083 @Test 084 public void testRepeatitiveDecode() throws Exception { 085 for (int i = 0; i < 4; i++) { 086 buf.putInt(i); 087 } 088 buf.flip(); 089 090 decoder.decode(session, buf, session.getDecoderOutput()); 091 assertEquals(4, session.getDecoderOutputQueue().size()); 092 assertEquals(buf.limit(), buf.position()); 093 094 for (int i = 0; i < 4; i++) { 095 assertTrue(session.getDecoderOutputQueue().contains(i)); 096 } 097 } 098 099 @Test 100 public void testWrongImplementationDetection() throws Exception { 101 try { 102 new WrongDecoder().decode(session, buf, session.getDecoderOutput()); 103 fail(); 104 } catch (IllegalStateException e) { 105 // OK 106 } 107 } 108 109 @Test 110 public void testBufferDerivation() throws Exception { 111 decoder = new DuplicatingIntegerDecoder(); 112 113 buf.putInt(1); 114 115 // Put some extra byte to make the decoder create an internal buffer. 116 buf.put((byte) 0); 117 buf.flip(); 118 119 decoder.decode(session, buf, session.getDecoderOutput()); 120 assertEquals(1, session.getDecoderOutputQueue().size()); 121 assertEquals(1, session.getDecoderOutputQueue().poll()); 122 assertEquals(buf.limit(), buf.position()); 123 124 // Keep appending to the internal buffer. 125 // DuplicatingIntegerDecoder will keep duplicating the internal 126 // buffer to disable auto-expansion, and CumulativeProtocolDecoder 127 // should detect that user derived its internal buffer. 128 // Consequently, CumulativeProtocolDecoder will perform 129 // reallocation to avoid putting incoming data into 130 // the internal buffer with auto-expansion disabled. 131 for (int i = 2; i < 10; i++) { 132 buf.clear(); 133 buf.putInt(i); 134 // Put some extra byte to make the decoder keep the internal buffer. 135 buf.put((byte) 0); 136 buf.flip(); 137 buf.position(1); 138 139 decoder.decode(session, buf, session.getDecoderOutput()); 140 assertEquals(1, session.getDecoderOutputQueue().size()); 141 assertEquals(i, session.getDecoderOutputQueue().poll()); 142 assertEquals(buf.limit(), buf.position()); 143 } 144 } 145 146 private static class IntegerDecoder extends CumulativeProtocolDecoder { 147 /** 148 * Default constructor 149 */ 150 public IntegerDecoder() { 151 super(); 152 } 153 154 @Override 155 protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception { 156 assertTrue(in.hasRemaining()); 157 158 if (in.remaining() < 4) { 159 return false; 160 } 161 162 out.write(new Integer(in.getInt())); 163 return true; 164 } 165 } 166 167 private static class WrongDecoder extends CumulativeProtocolDecoder { 168 /** 169 * Default constructor 170 */ 171 public WrongDecoder() { 172 super(); 173 } 174 175 @Override 176 protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception { 177 return true; 178 } 179 } 180 181 private static class DuplicatingIntegerDecoder extends IntegerDecoder { 182 /** 183 * Default constructor 184 */ 185 public DuplicatingIntegerDecoder() { 186 super(); 187 } 188 189 @Override 190 protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception { 191 in.duplicate(); // Will disable auto-expansion. 192 assertFalse(in.isAutoExpand()); 193 return super.doDecode(session, in, out); 194 } 195 } 196}