001    // Copyright 2004, 2005 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    //     http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    
015    package org.apache.tapestry.junit.utils;
016    
017    import java.io.File;
018    import java.io.Serializable;
019    import java.lang.reflect.Constructor;
020    import java.math.BigDecimal;
021    import java.net.URL;
022    import java.net.URLClassLoader;
023    import java.util.HashMap;
024    import java.util.Map;
025    
026    import org.apache.hivemind.ApplicationRuntimeException;
027    import org.apache.hivemind.ClassResolver;
028    import org.apache.hivemind.impl.DefaultClassResolver;
029    import org.apache.hivemind.util.PropertyUtils;
030    import org.apache.tapestry.BaseComponentTestCase;
031    import org.apache.tapestry.services.DataSqueezer;
032    import org.apache.tapestry.util.ComponentAddress;
033    import org.apache.tapestry.util.io.DataSqueezerImpl;
034    import org.apache.tapestry.util.io.DataSqueezerUtil;
035    import org.apache.tapestry.util.io.SerializableAdaptor;
036    import org.apache.tapestry.util.io.SqueezeAdaptor;
037    import org.testng.annotations.Test;
038    
039    /**
040     * A series of tests for {@link DataSqueezerImpl} and friends.
041     * 
042     * @author Howard Lewis Ship
043     */
044    @Test
045    public class TestDataSqueezer extends BaseComponentTestCase
046    {
047        private DataSqueezerImpl ds = DataSqueezerUtil.createUnitTestSqueezer();
048    
049        public TestDataSqueezer(String name)
050        {
051        }
052    
053        private void attempt(Object input, String expectedEncoding)
054        {
055            attempt(input, expectedEncoding, ds);
056        }
057    
058        private void attempt(Object input, String expectedEncoding, DataSqueezer squeezer)
059    
060        {
061            String encoding = squeezer.squeeze(input);
062    
063            assertEquals(expectedEncoding, encoding);
064    
065            Object output = squeezer.unsqueeze(encoding);
066    
067            assertEquals(input, output);
068        }
069    
070        public void testBoolean()
071        {
072            attempt(Boolean.TRUE, "T");
073            attempt(Boolean.FALSE, "F");
074        }
075    
076        public void testNull()
077        {
078            attempt(null, "X");
079        }
080    
081        public void testByte()
082        {
083            attempt(new Byte((byte) 0), "b0");
084            attempt(new Byte((byte) -5), "b-5");
085            attempt(new Byte((byte) 72), "b72");
086        }
087    
088        public void testFloat()
089        {
090            attempt(new Float(0), "f0.0");
091            attempt(new Float(3.1459), "f3.1459");
092            attempt(new Float(-37.23), "f-37.23");
093        }
094    
095        public void testDouble()
096        {
097            attempt(new Double(0), "d0.0");
098            attempt(new Double(3.1459), "d3.1459");
099            attempt(new Double(-37.23), "d-37.23");
100        }
101    
102        public void testInteger()
103        {
104            attempt(new Integer(0), "0");
105            attempt(new Integer(205), "205");
106            attempt(new Integer(-173), "-173");
107        }
108    
109        public void testLong()
110        {
111            attempt(new Long(0), "l0");
112            attempt(new Long(800400300l), "l800400300");
113            attempt(new Long(-987654321l), "l-987654321");
114        }
115    
116        public void testShort()
117        {
118            attempt(new Short((short) 0), "s0");
119            attempt(new Short((short) -10), "s-10");
120            attempt(new Short((short) 57), "s57");
121        }
122    
123        /** @since 2.2 * */
124    
125        public void testCharacter()
126        {
127            attempt(new Character('a'), "ca");
128            attempt(new Character('Z'), "cZ");
129        }
130    
131        public void test_Empty_Value()
132        {
133            Object output = ds.unsqueeze("");
134            
135            assert output == null;
136        }
137        
138        public void testString()
139        {
140            attempt("Now is the time for all good men ...", "SNow is the time for all good men ...");
141            attempt("X marks the spot!", "SX marks the spot!");
142            attempt("So long, sucker!", "SSo long, sucker!");
143        }
144    
145        public void testComponentAddress()
146        {
147            ComponentAddress objAddress = new ComponentAddress("framework:DirectLink",
148                    "component.subcomponent");
149            attempt(objAddress, "Aframework:DirectLink,component.subcomponent");
150    
151            objAddress = new ComponentAddress("framework:DirectLink", null);
152            attempt(objAddress, "Aframework:DirectLink,");
153        }
154    
155        public void testArray()
156        {
157            Object[] input =
158            { new Short((short) -82), "Time to encode an array.", new Long(38383833273789l), null,
159                    Boolean.TRUE, new Double(22. / 7.) };
160    
161            String[] encoded = ds.squeeze(input);
162    
163            assertEquals(input.length, encoded.length);
164    
165            Object[] output = ds.unsqueeze(encoded);
166    
167            assertEquals(input.length, output.length);
168    
169            for (int i = 0; i < input.length; i++)
170            {
171                assertEquals(input[i], output[i]);
172            }
173        }
174    
175        public void testNullArray()
176        {
177            Object[] input = null;
178    
179            String[] encoded = ds.squeeze(input);
180    
181            assertNull(encoded);
182    
183            Object[] output = ds.unsqueeze(encoded);
184    
185            assertNull(output);
186        }
187    
188        private void attempt(Serializable s, DataSqueezer squeezer)
189        {
190            String encoded = squeezer.squeeze(s);
191    
192            Object output = squeezer.unsqueeze(encoded);
193    
194            assertEquals(s, output);
195        }
196    
197        public void testSerializableShort()
198        {
199            attempt(new StringHolder("X"), ds);
200        }
201    
202        public void testSerializableLong()
203        {
204    
205            Map map = new HashMap();
206    
207            map.put("alpha", Boolean.TRUE);
208            map.put("beta", new StringHolder("FredFlintstone"));
209            map.put("gamma", new BigDecimal(
210                    "2590742358742358972.234592348957230948578975248972390857490725"));
211    
212            attempt((Serializable) map, ds);
213        }
214    
215        public static class BooleanHolder
216        {
217            private boolean value;
218    
219            public BooleanHolder()
220            {
221            }
222    
223            public BooleanHolder(boolean value)
224            {
225                this.value = value;
226            }
227    
228            public boolean getValue()
229            {
230                return value;
231            }
232    
233            public void setValue(boolean value)
234            {
235                this.value = value;
236            }
237    
238            public boolean equals(Object other)
239            {
240                if (other == null)
241                    return false;
242    
243                if (this == other)
244                    return true;
245    
246                if (!(other instanceof BooleanHolder))
247                    return false;
248    
249                BooleanHolder otherHolder = (BooleanHolder) other;
250    
251                return value == otherHolder.value;
252            }
253        }
254    
255        public static class BHSqueezer implements SqueezeAdaptor
256        {
257            private final String prefix_;
258    
259            private final Class dataClass_;
260    
261            private static final String TRUE = "BT";
262    
263            private static final String FALSE = "BF";
264    
265            public BHSqueezer()
266            {
267                this("B", BooleanHolder.class);
268            }
269    
270            public BHSqueezer(String prefix)
271            {
272                this(prefix, BooleanHolder.class);
273            }
274    
275            public BHSqueezer(String prefix, Class dataClass)
276            {
277                prefix_ = prefix;
278                dataClass_ = dataClass;
279            }
280    
281            public String getPrefix()
282            {
283                return prefix_;
284            }
285    
286            public Class getDataClass()
287            {
288                return dataClass_;
289            }
290    
291            public String squeeze(DataSqueezer squeezer, Object data)
292            {
293                BooleanHolder h = (BooleanHolder) data;
294    
295                return h.getValue() ? TRUE : FALSE;
296            }
297    
298            public Object unsqueeze(DataSqueezer squeezer, String string)
299            {
300                if (string.equals(TRUE))
301                    return new BooleanHolder(true);
302    
303                if (string.equals(FALSE))
304                    return new BooleanHolder(false);
305    
306                throw new ApplicationRuntimeException("Unexpected value.");
307            }
308    
309        }
310    
311        public void testCustom()
312        {
313            DataSqueezerImpl squeezer = DataSqueezerUtil.createUnitTestSqueezer();
314            squeezer.register(new BHSqueezer());
315    
316            attempt(new BooleanHolder(true), "BT", squeezer);
317            attempt(new BooleanHolder(false), "BF", squeezer);
318    
319            attempt("BooleanHolder", "SBooleanHolder", squeezer);
320        }
321    
322        public void testRegisterShortPrefix()
323        {
324            try
325            {
326                ds.register(new BHSqueezer(""));
327    
328                throw new AssertionError("Null prefix should be invalid.");
329            }
330            catch (IllegalArgumentException ex)
331            {
332            }
333        }
334    
335        public void testRegisterInvalidPrefix()
336        {
337            try
338            {
339                ds.register(new BHSqueezer("\n"));
340    
341                throw new AssertionError("Prefix should be invalid.");
342            }
343            catch (IllegalArgumentException ex)
344            {
345            }
346        }
347    
348        public void testRegisterDupePrefix()
349        {
350            try
351            {
352                ds.register(new BHSqueezer("b"));
353    
354                throw new AssertionError("Duplicate prefix should be invalid.");
355            }
356            catch (IllegalArgumentException ex)
357            {
358            }
359        }
360    
361        public void testRegisterNullClass()
362        {
363            try
364            {
365                ds.register(new BHSqueezer("B", null));
366    
367                throw new AssertionError("Null data class should be invalid.");
368            }
369            catch (IllegalArgumentException ex)
370            {
371            }
372        }
373    
374        public void testRegisterNullSqueezer()
375        {
376            try
377            {
378                ds.register(null);
379    
380                throw new AssertionError("Null squeezer should be invalid.");
381            }
382            catch (IllegalArgumentException ex)
383            {
384            }
385        }
386    
387        public void testClassLoader() throws Exception
388        {
389            File springJAR = new File("tapestry-framework/src/test-data/spring-1.1.jar");
390            if (!springJAR.exists())
391                springJAR = new File("src/test-data/spring-1.1.jar");
392            
393            if (!springJAR.exists())
394                throw new RuntimeException("File " + springJAR
395                        + " does not exist; this should have been downloaded by the Ant build scripts.");
396    
397            ClassResolver resolver = newClassResolver(springJAR);
398    
399            Class propertyValueClass = resolver.findClass("org.springframework.beans.PropertyValue");
400            Constructor constructor = propertyValueClass.getConstructor(new Class[]
401            { String.class, Object.class });
402    
403            Serializable instance = (Serializable) constructor.newInstance(new Object[]
404            { "fred", "flintstone" });
405    
406            assertEquals("fred", PropertyUtils.read(instance, "name"));
407            assertEquals("flintstone", PropertyUtils.read(instance, "value"));
408    
409            DataSqueezer dsq = newDataSqueezer(resolver);
410    
411            String encoded = dsq.squeeze(instance);
412    
413            // OK; build a whole new class loader & stack to decode that
414            // string back into an object.
415    
416            ClassResolver resolver2 = newClassResolver(springJAR);
417    
418            DataSqueezer ds2 = newDataSqueezer(resolver2);
419    
420            Object output = ds2.unsqueeze(encoded);
421    
422            assertEquals("fred", PropertyUtils.read(output, "name"));
423            assertEquals("flintstone", PropertyUtils.read(output, "value"));
424        }
425    
426        private ClassResolver newClassResolver(File jarFile) throws Exception
427        {
428            URLClassLoader classLoader = new URLClassLoader(new URL[]
429            { jarFile.toURL() });
430    
431            return new DefaultClassResolver(classLoader);
432    
433        }
434    
435        private DataSqueezer newDataSqueezer(ClassResolver resolver)
436        {
437            DataSqueezerImpl dsq = new DataSqueezerImpl();
438            SerializableAdaptor adaptor = new SerializableAdaptor();
439            adaptor.setResolver(resolver);
440    
441            dsq.register(adaptor);
442            return dsq;
443        }
444    }