1   /*
2    *   Copyright 2004 The Apache Software Foundation
3    *
4    *   Licensed under the Apache License, Version 2.0 (the "License");
5    *   you may not use this file except in compliance with the License.
6    *   You may obtain a copy of the License at
7    *
8    *       http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *   Unless required by applicable law or agreed to in writing, software
11   *   distributed under the License is distributed on an "AS IS" BASIS,
12   *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *   See the License for the specific language governing permissions and
14   *   limitations under the License.
15   *
16   */
17  package org.apache.asn1.codec.stateful ;
18  
19  
20  import junit.framework.TestCase;
21  
22  import org.apache.asn1.codec.DecoderException;
23  
24  
25  /***
26   * Tests the DecoderStack.
27   *
28   * @author <a href="mailto:dev@directory.apache.org">
29   * Apache Directory Project</a>
30   * @version $Rev: 161723 $
31   */
32  public class DecoderStackTest extends TestCase
33  {
34      /***
35       * Constructor for DecoderStackTest.
36       * @param arg0
37       */
38      public DecoderStackTest( String arg0 )
39      {
40          super( arg0 ) ;
41      }
42  
43      
44      /***
45       * Tests the push method.
46       */
47      public void testPush()
48      {
49          DecoderStack stack = new DecoderStack() ;
50          assertNotNull( stack ) ;
51          assertTrue( "expecting empty stack after creation", stack.isEmpty() ) ;
52          PassThroDecoder decoder = new PassThroDecoder() ;
53          stack.push( decoder ) ;
54          assertFalse( "expecting non-empty stack after push", stack.isEmpty() ) ;
55      }
56  
57      
58      /***
59       * Tests the pop method.
60       */
61      public void testPop()
62      {
63          DecoderStack stack = new DecoderStack() ;
64          assertNotNull( stack ) ;
65          assertTrue( "expecting empty stack after creation", stack.isEmpty() ) ;
66          PassThroDecoder decoder = new PassThroDecoder() ;
67          stack.push( decoder ) ;
68          assertFalse( "expecting non-empty stack after push", stack.isEmpty() ) ;
69          StatefulDecoder popped = stack.pop() ;
70          assertTrue( "expecting empty stack after last pop", stack.isEmpty() ) ;
71          assertNotNull( popped ) ;
72          assertSame( "expecting last popped == last pushed", popped, decoder ) ;
73          StatefulDecoder empty = stack.pop() ;
74          assertNotNull( "expecting empty pop to be non-null", empty ) ; 
75          assertNotSame( "expecting empty pop != last popped", popped, empty ) ;
76          assertSame( "expecting empty pop == stack decoder", stack, empty ) ;
77          assertTrue( "expecting empty stack after empty pop", stack.isEmpty() ) ;
78      }
79  
80      
81      public void testDecode() throws Exception
82      {
83          DecoderStack stack = new DecoderStack() ;
84          CallbackHistory history = new CallbackHistory() ;
85          stack.setCallback( history ) ;
86          assertNotNull( stack ) ;
87          assertTrue( "expecting empty stack after creation", stack.isEmpty() ) ;
88          PassThroDecoder decoder = new PassThroDecoder() ;
89          stack.push( decoder ) ;
90          stack.decode( new Integer(0) ) ;
91          assertEquals( new Integer(0), history.getMostRecent() ) ;
92          
93          assertFalse( "expecting non-empty stack after push", stack.isEmpty() ) ;
94  
95          stack.push( new IncrementingDecoder() ) ;
96          stack.decode( new Integer(0) ) ;
97          assertEquals( new Integer(1), history.getMostRecent() ) ;
98  
99          stack.push( new IncrementingDecoder() ) ;
100         stack.decode( new Integer(0) ) ;
101         assertEquals( new Integer(2), history.getMostRecent() ) ;
102 
103         stack.push( new IncrementingDecoder() ) ;
104         stack.decode( new Integer(0) ) ;
105         assertEquals( new Integer(3), history.getMostRecent() ) ;
106 
107         stack.push( new IncrementingDecoder() ) ;
108         stack.decode( new Integer(0) ) ;
109         assertEquals( new Integer(4), history.getMostRecent() ) ;
110 
111         stack.push( new IncrementingDecoder() ) ;
112         stack.decode( new Integer(0) ) ;
113         assertEquals( new Integer(5), history.getMostRecent() ) ;
114 
115         stack.push( new IncrementingDecoder() ) ;
116         stack.decode( new Integer(0) ) ;
117         assertEquals( new Integer(6), history.getMostRecent() ) ;
118 
119         stack.push( new IncrementingDecoder() ) ;
120         stack.decode( new Integer(0) ) ;
121         assertEquals( new Integer(7), history.getMostRecent() ) ;
122 
123         // start popping and decrementing now
124 
125         stack.pop() ;
126         stack.decode( new Integer(0) ) ;
127         assertEquals( new Integer(6), history.getMostRecent() ) ;
128 
129         stack.pop() ;
130         stack.decode( new Integer(0) ) ;
131         assertEquals( new Integer(5), history.getMostRecent() ) ;
132 
133         stack.pop() ;
134         stack.decode( new Integer(0) ) ;
135         assertEquals( new Integer(4), history.getMostRecent() ) ;
136 
137         stack.pop() ;
138         stack.decode( new Integer(0) ) ;
139         assertEquals( new Integer(3), history.getMostRecent() ) ;
140 
141         stack.pop() ;
142         stack.decode( new Integer(0) ) ;
143         assertEquals( new Integer(2), history.getMostRecent() ) ;
144 
145         stack.pop() ;
146         stack.decode( new Integer(0) ) ;
147         assertEquals( new Integer(1), history.getMostRecent() ) ;
148 
149         stack.pop() ;
150         stack.decode( new Integer(0) ) ;
151         assertEquals( new Integer(0), history.getMostRecent() ) ;
152 
153         assertFalse( "expecting stack with passthrodecoder", stack.isEmpty() ) ;
154         
155         stack.pop() ;
156         stack.decode( new Integer(0) ) ;
157         assertEquals( new Integer(0), history.getMostRecent() ) ;
158 
159         assertTrue( "expecting empty stack after last pop", stack.isEmpty() ) ;
160         
161         stack.pop() ;
162         stack.decode( new Integer(0) ) ;
163         assertEquals( new Integer(0), history.getMostRecent() ) ;
164 
165         assertTrue( "expecting empty stack after empty pop", stack.isEmpty() ) ;
166     }
167     
168     
169     public void testFailure() throws Exception
170     {
171         DecoderStack stack = new DecoderStack() ;
172         CallbackHistory history = new CallbackHistory() ;
173         stack.setCallback( history ) ;
174         assertNotNull( stack ) ;
175         assertTrue( "expecting empty stack after creation", stack.isEmpty() ) ;
176         PassThroDecoder decoder = new PassThroDecoder() ;
177         stack.push( decoder ) ;
178         
179         stack.push( new FaultingDecoder() ) ;
180         
181         try
182         {
183             stack.decode( new Object() ) ;
184             fail( "should never reach here due to exception throws" ) ;
185         }
186         catch( RuntimeException e )
187         {
188             assertNotNull( e ) ;
189             assertTrue( "testing keyword should be in the message",
190                     e.getMessage().indexOf("testing") > 0 ) ;
191             assertTrue( "RuntimeException cause should be a DecoderException",
192                     e.getCause().getClass().equals( DecoderException.class ) ) ;
193         }
194     }
195     
196     
197     /***
198      * A do nothing decoder.
199      */
200     class PassThroDecoder extends AbstractStatefulDecoder
201     {
202         public void decode( Object encoded ) throws DecoderException
203         {
204             super.decodeOccurred( encoded ) ;
205         }
206     }
207 
208 
209     /***
210      * A decoder that increments an Integer passed in as an argument.  We're 
211      * using this for verifying the additive (hehe) effects of decoder chaining.
212      */
213     class IncrementingDecoder extends AbstractStatefulDecoder
214     {
215         public void decode( Object encoded ) throws DecoderException
216         {
217             Integer value = ( Integer ) encoded ;
218             value = new Integer( value.intValue() + 1 ) ;
219             super.decodeOccurred( value ) ;
220         }
221     }
222 
223 
224     /***
225      * A decoder that throws an exception on decode calls.  We're using this 
226      * for verifying the failure of the chain.
227      */
228     class FaultingDecoder extends AbstractStatefulDecoder
229     {
230         public void decode( Object encoded ) throws DecoderException
231         {
232             throw new DecoderException( "testing" ) ;
233         }
234     }
235 }