1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.server.core.entry;
21  
22  
23  import java.io.ByteArrayInputStream;
24  import java.io.ByteArrayOutputStream;
25  import java.io.IOException;
26  import java.io.ObjectInputStream;
27  import java.io.ObjectOutputStream;
28  import java.util.Arrays;
29  
30  import javax.naming.NamingException;
31  
32  import org.apache.directory.shared.ldap.schema.AttributeType;
33  import org.apache.directory.shared.ldap.schema.ByteArrayComparator;
34  import org.apache.directory.shared.ldap.schema.Normalizer;
35  import org.apache.directory.shared.ldap.schema.syntax.AcceptAllSyntaxChecker;
36  import org.apache.directory.shared.ldap.util.StringTools;
37  
38  import static org.junit.Assert.assertEquals;
39  import static org.junit.Assert.assertFalse;
40  import static org.junit.Assert.assertNotSame;
41  import static org.junit.Assert.assertNull;
42  import static org.junit.Assert.assertTrue;
43  import static org.junit.Assert.fail;
44  
45  import org.junit.Before;
46  import org.junit.Test;
47  
48  
49  /**
50   * Tests that the ServerBinaryValue class works properly as expected.
51   *
52   * Some notes while conducting tests:
53   *
54   * <ul>
55   *   <li>comparing values with different types - how does this behave</li>
56   *   <li>exposing access to at from value or to a comparator?</li>
57   * </ul>
58   *
59   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
60   * @version $Rev$, $Date$
61   */
62  public class ServerBinaryValueTest
63  {
64      private TestServerEntryUtils.S s;
65      private TestServerEntryUtils.AT at;
66      private TestServerEntryUtils.MR mr;
67      
68      private static final byte[] BYTES1 = new byte[]{0x01, 0x02, 0x03, 0x04};
69      private static final byte[] BYTES2 = new byte[]{(byte)0x81, (byte)0x82, (byte)0x83, (byte)0x84};
70  
71      /**
72       * Initialize an AttributeType and the associated MatchingRule 
73       * and Syntax
74       */
75      @Before public void initAT()
76      {
77          s = new TestServerEntryUtils.S( "1.1.1.1", false );
78          s.setSyntaxChecker( new AcceptAllSyntaxChecker( "1.1.1.1" ) );
79          mr = new TestServerEntryUtils.MR( "1.1.2.1" );
80          mr.syntax = s;
81          mr.comparator = new ByteArrayComparator();
82          mr.normalizer = new Normalizer()
83          {
84              private static final long serialVersionUID = 1L;
85              
86              public Object normalize( Object value ) throws NamingException
87              {
88                  if ( value instanceof byte[] )
89                  {
90                      byte[] val = (byte[])value;
91                      // each byte will be changed to be > 0, and spaces will be trimmed
92                      byte[] newVal = new byte[ val.length ];
93                      int i = 0;
94                      
95                      for ( byte b:val )
96                      {
97                          newVal[i++] = (byte)(b & 0x007F); 
98                      }
99                      
100                     return StringTools.trim( newVal );
101                 }
102 
103                 throw new IllegalStateException( "expected byte[] to normalize" );
104             }
105         };
106         at = new TestServerEntryUtils.AT( "1.1.3.1" );
107         at.setEquality( mr );
108         at.setOrdering( mr );
109         at.setSubstr( mr );
110         at.setSyntax( s );
111     }
112     
113     
114     /**
115      * Serialize a ServerBinaryValue
116      */
117     private ByteArrayOutputStream serializeValue( ServerBinaryValue value ) throws IOException
118     {
119         ObjectOutputStream oOut = null;
120         ByteArrayOutputStream out = new ByteArrayOutputStream();
121 
122         try
123         {
124             oOut = new ObjectOutputStream( out );
125             value.serialize( oOut );
126         }
127         catch ( IOException ioe )
128         {
129             throw ioe;
130         }
131         finally
132         {
133             try
134             {
135                 if ( oOut != null )
136                 {
137                     oOut.flush();
138                     oOut.close();
139                 }
140             }
141             catch ( IOException ioe )
142             {
143                 throw ioe;
144             }
145         }
146         
147         return out;
148     }
149     
150     
151     /**
152      * Deserialize a ServerBinaryValue
153      */
154     private ServerBinaryValue deserializeValue( ByteArrayOutputStream out, AttributeType at ) throws IOException, ClassNotFoundException
155     {
156         ObjectInputStream oIn = null;
157         ByteArrayInputStream in = new ByteArrayInputStream( out.toByteArray() );
158 
159         try
160         {
161             oIn = new ObjectInputStream( in );
162 
163             ServerBinaryValue value = new ServerBinaryValue( at );
164             value.deserialize( oIn );
165 
166             return value;
167         }
168         catch ( IOException ioe )
169         {
170             throw ioe;
171         }
172         finally
173         {
174             try
175             {
176                 if ( oIn != null )
177                 {
178                     oIn.close();
179                 }
180             }
181             catch ( IOException ioe )
182             {
183                 throw ioe;
184             }
185         }
186     }
187     
188     
189     /**
190      * Test the constructor with bad AttributeType
191      */
192     @Test public void testBadConstructor()
193     {
194         try
195         {
196             new ServerBinaryValue( null );
197             fail();
198         }
199         catch ( IllegalArgumentException iae )
200         {
201             // Expected...
202         }
203         
204         // create a AT without any syntax
205         AttributeType attribute = new TestServerEntryUtils.AT( "1.1.3.1" );
206         
207         try
208         {
209             new ServerBinaryValue( attribute );
210             fail();
211         }
212         catch ( IllegalArgumentException ae )
213         {
214             // Expected...
215         }
216     }
217 
218 
219     /**
220      * Test the constructor with a null value
221      */
222     @Test public void testServerBinaryValueNullValue()
223     {
224         AttributeType attribute = TestServerEntryUtils.getBytesAttributeType();
225         
226         ServerBinaryValue value = new ServerBinaryValue( attribute, null );
227         
228         assertNull( value.getReference() );
229         assertTrue( value.isNull() );
230     }
231     
232     
233     /**
234      * Test the constructor with an empty value
235      */
236     @Test public void testServerBinaryValueEmptyValue()
237     {
238         AttributeType attribute = TestServerEntryUtils.getBytesAttributeType();
239         
240         ServerBinaryValue value = new ServerBinaryValue( attribute, StringTools.EMPTY_BYTES );
241         
242         assertEquals( StringTools.EMPTY_BYTES, value.getReference() );
243         assertFalse( value.isNull() );
244     }
245     
246     
247     /**
248      * Test the constructor with a value
249      */
250     @Test public void testServerBinaryValueNoValue()
251     {
252         AttributeType attribute = TestServerEntryUtils.getBytesAttributeType();
253         byte[] val = new byte[]{0x01};
254         ServerBinaryValue value = new ServerBinaryValue( attribute );
255         
256         value.set( val );
257         assertTrue( Arrays.equals( val, value.getReference() ) );
258         assertFalse( value.isNull() );
259         assertTrue( Arrays.equals( val, value.getCopy() ) );
260     }
261     
262     
263     /**
264      * Test the constructor with a value
265      */
266     @Test public void testServerBinaryValue()
267     {
268         AttributeType attribute = TestServerEntryUtils.getBytesAttributeType();
269         byte[] val = new byte[]{0x01};
270         ServerBinaryValue value = new ServerBinaryValue( attribute, val );
271         
272         assertTrue( Arrays.equals( val, value.getReference() ) );
273         assertFalse( value.isNull() );
274         assertTrue( Arrays.equals( val, value.getCopy() ) );
275     }
276     
277     
278     /**
279      * Test the clone method
280      */
281     @Test
282     public void testClone() throws NamingException
283     {
284         AttributeType at1 = TestServerEntryUtils.getBytesAttributeType();
285         ServerBinaryValue sbv = new ServerBinaryValue( at1, null );
286         
287         ServerBinaryValue sbv1 = sbv.clone();
288         
289         assertEquals( sbv, sbv1 );
290         
291         sbv.set( StringTools.EMPTY_BYTES );
292         
293         assertNotSame( sbv, sbv1 );
294         assertTrue( Arrays.equals( StringTools.EMPTY_BYTES, sbv.get() ) );
295         
296         sbv.set(  BYTES2 );
297         sbv1 = sbv.clone();
298         
299         assertEquals( sbv, sbv1 );
300         
301         sbv.normalize();
302         
303         // Even if we didn't normalized sbv2, it should be equal to sbv,
304         // as if they have the same AT, and the same value, they are equal.
305         assertEquals( sbv, sbv1 );
306     }
307     
308 
309     /**
310      * Test the equals method
311      */
312     @Test public void testEquals()
313     {
314         AttributeType at1 = TestServerEntryUtils.getBytesAttributeType();
315         
316         ServerBinaryValue value1 = new ServerBinaryValue( at1, new byte[]{0x01, (byte)0x02} );
317         ServerBinaryValue value2 = new ServerBinaryValue( at1, new byte[]{0x01, (byte)0x02} );
318         ServerBinaryValue value3 = new ServerBinaryValue( at1, new byte[]{0x01, (byte)0x82} );
319         ServerBinaryValue value4 = new ServerBinaryValue( at1, new byte[]{0x01} );
320         ServerBinaryValue value5 = new ServerBinaryValue( at1, null );
321         ServerBinaryValue value6 = new ServerBinaryValue( at, new byte[]{0x01, 0x02} );
322         ServerStringValue value7 = new ServerStringValue( TestServerEntryUtils.getIA5StringAttributeType(), 
323             "test" );
324         
325         assertTrue( value1.equals( value1 ) );
326         assertTrue( value1.equals( value2 ) );
327         assertTrue( value1.equals( value3 ) );
328         assertFalse( value1.equals( value4 ) );
329         assertFalse( value1.equals( value5 ) );
330         assertFalse( value1.equals( "test" ) );
331         assertFalse( value1.equals( null ) );
332         
333         assertFalse( value1.equals( value6 ) );
334         assertFalse( value1.equals( value7 ) );
335     }
336 
337     
338     /**
339      * Test the getNormalizedValue method
340      */
341     @Test public void testGetNormalizedValue()
342     {
343         AttributeType attribute = TestServerEntryUtils.getBytesAttributeType();
344         
345         ServerBinaryValue value = new ServerBinaryValue( attribute, null );
346         assertNull( value.getNormalizedValue() );
347 
348         value = new ServerBinaryValue( attribute, StringTools.EMPTY_BYTES );
349         assertTrue( Arrays.equals(  StringTools.EMPTY_BYTES, value.getNormalizedValue() ) );
350 
351         value = new ServerBinaryValue( attribute, BYTES2 );
352         assertTrue( Arrays.equals( BYTES1, value.getNormalizedValue() ) );
353     }
354     
355     
356     /**
357      * Test the getNormalizedValue method
358      */
359     @Test public void testGetNormalizedValueCopy()
360     {
361         AttributeType attribute = TestServerEntryUtils.getBytesAttributeType();
362         
363         ServerBinaryValue value = new ServerBinaryValue( attribute, null );
364         assertNull( value.getNormalizedValueCopy() );
365 
366         value = new ServerBinaryValue( attribute, StringTools.EMPTY_BYTES );
367         assertTrue( Arrays.equals(  StringTools.EMPTY_BYTES, value.getNormalizedValueCopy() ) );
368 
369         value = new ServerBinaryValue( attribute, BYTES2 );
370         assertTrue( Arrays.equals( BYTES1, value.getNormalizedValueCopy() ) );
371     }
372     
373     
374     /**
375      * Test the getNormalizedValue method
376      */
377     @Test public void testGetNormalizedValueReference()
378     {
379         AttributeType attribute = TestServerEntryUtils.getBytesAttributeType();
380         
381         ServerBinaryValue value = new ServerBinaryValue( attribute, null );
382         assertNull( value.getNormalizedValueReference() );
383 
384         value = new ServerBinaryValue( attribute, StringTools.EMPTY_BYTES );
385         assertTrue( Arrays.equals(  StringTools.EMPTY_BYTES, value.getNormalizedValueReference() ) );
386 
387         value = new ServerBinaryValue( attribute, BYTES2 );
388         assertTrue( Arrays.equals( BYTES1, value.getNormalizedValueReference() ) );
389     }
390     
391     
392     /**
393      * Test the getAttributeType method
394      */
395     @Test
396     public void testgetAttributeType()
397     {
398         AttributeType attribute = TestServerEntryUtils.getBytesAttributeType();
399         ServerBinaryValue sbv = new ServerBinaryValue( attribute );
400         
401         assertEquals( attribute, sbv.getAttributeType() );
402     }    
403 
404     
405     /**
406      * Test the isValid method
407      * 
408      * The SyntaxChecker does not accept values longer than 5 chars.
409      */
410     @Test public void testIsValid()
411     {
412         AttributeType attribute = TestServerEntryUtils.getBytesAttributeType();
413         
414         ServerBinaryValue value = new ServerBinaryValue( attribute, null );
415         assertTrue( value.isValid() );
416         
417         value = new ServerBinaryValue( attribute, StringTools.EMPTY_BYTES );
418         assertTrue( value.isValid() );
419 
420         value = new ServerBinaryValue( attribute, new byte[]{0x01, 0x02} );
421         assertTrue( value.isValid() );
422 
423         value = new ServerBinaryValue( attribute, new byte[]{0x01, 0x02, 0x03, 0x04, 0x05, 0x06} );
424         assertFalse( value.isValid() );
425     }
426     
427     
428     /**
429      * Tests to make sure the hashCode method is working properly.
430      * @throws Exception on errors
431      */
432     @Test public void testHashCode()
433     {
434         AttributeType attribute = TestServerEntryUtils.getBytesAttributeType();
435         ServerBinaryValue v0 = new ServerBinaryValue( attribute, new byte[]{0x01, 0x02} );
436         ServerBinaryValue v1 = new ServerBinaryValue( attribute, new byte[]{(byte)0x81, (byte)0x82} );
437         ServerBinaryValue v2 = new ServerBinaryValue( attribute, new byte[]{0x01, 0x02} );
438         assertEquals( v0.hashCode(), v1.hashCode() );
439         assertEquals( v1.hashCode(), v2.hashCode() );
440         assertEquals( v0.hashCode(), v2.hashCode() );
441         assertEquals( v0, v1 );
442         assertEquals( v0, v2 );
443         assertEquals( v1, v2 );
444         assertTrue( v0.isValid() );
445         assertTrue( v1.isValid() );
446         assertTrue( v2.isValid() );
447 
448         ServerBinaryValue v3 = new ServerBinaryValue( attribute, new byte[]{0x01, 0x03} );
449         assertFalse( v3.equals( v0 ) );
450         assertFalse( v3.equals( v1 ) );
451         assertFalse( v3.equals( v2 ) );
452         assertTrue( v3.isValid() );
453     }
454 
455 
456     /**
457      * Test the same method
458      */
459     @Test
460     public void testSame() throws NamingException
461     {
462         AttributeType attribute = TestServerEntryUtils.getBytesAttributeType();
463         ServerBinaryValue sbv = new ServerBinaryValue( attribute );
464 
465         sbv.normalize();
466         assertTrue( sbv.isSame() );
467         
468         sbv.set( StringTools.EMPTY_BYTES );
469         sbv.normalize();
470         assertTrue( sbv.isSame() );
471 
472         sbv.set( BYTES1 );
473         sbv.normalize();
474         assertTrue( sbv.isSame() );
475 
476         sbv.set( BYTES2 );
477         sbv.normalize();
478         assertFalse( sbv.isSame() );
479     }
480     
481     
482     /**
483      * Test the instanceOf method
484      */
485     @Test
486     public void testInstanceOf() throws NamingException
487     {
488         AttributeType attribute = TestServerEntryUtils.getBytesAttributeType();
489         ServerBinaryValue sbv = new ServerBinaryValue( attribute );
490         
491         assertTrue( sbv.instanceOf( attribute ) );
492         
493         attribute = TestServerEntryUtils.getIA5StringAttributeType();
494         
495         assertFalse( sbv.instanceOf( attribute ) );
496     }    
497     
498 
499     /**
500      * Test the normalize method
501      */
502     @Test
503     public void testNormalize() throws NamingException
504     {
505         AttributeType attribute = TestServerEntryUtils.getBytesAttributeType();
506         ServerBinaryValue sbv = new ServerBinaryValue( attribute );
507 
508         sbv.normalize();
509         assertEquals( null, sbv.getNormalizedValue() );
510         
511         sbv.set( StringTools.EMPTY_BYTES );
512         sbv.normalize();
513         assertTrue( Arrays.equals( StringTools.EMPTY_BYTES, sbv.getNormalizedValue() ) );
514 
515         sbv.set( BYTES2 );
516         sbv.normalize();
517         assertTrue( Arrays.equals( BYTES1, sbv.getNormalizedValue() ) );
518     }
519     
520 
521     /**
522      * Test the compareTo method
523      */
524     @Test
525     public void testCompareTo()
526     {
527         AttributeType at1 = TestServerEntryUtils.getBytesAttributeType();
528         ServerBinaryValue v0 = new ServerBinaryValue( at1, BYTES1 );
529         ServerBinaryValue v1 = new ServerBinaryValue( at1, BYTES2 );
530         
531         assertEquals( 0, v0.compareTo( v1 ) );
532         assertEquals( 0, v1.compareTo( v0 ) );
533 
534         ServerBinaryValue v2 = new ServerBinaryValue( at1, null );
535         
536         assertEquals( 1, v0.compareTo( v2 ) );
537         assertEquals( -1, v2.compareTo( v0 ) );
538     }
539 
540 
541     /**
542      * Test serialization of a BinaryValue which has a normalized value
543      */
544     @Test public void testNormalizedBinaryValueSerialization() throws NamingException, IOException, ClassNotFoundException
545     {
546         byte[] v1 = StringTools.getBytesUtf8( "  Test   Test  " );
547         byte[] v1Norm = StringTools.getBytesUtf8( "Test   Test" );
548         
549         // First check with a value which will be normalized
550         ServerBinaryValue sbv = new ServerBinaryValue( at, v1 );
551         
552         sbv.normalize();
553         byte[] normalized = sbv.getNormalizedValueReference();
554         
555         assertTrue( Arrays.equals( v1Norm, normalized ) );
556         assertTrue( Arrays.equals( v1, sbv.getReference() ) );
557         
558         ServerBinaryValue sbvSer = deserializeValue( serializeValue( sbv ), at );
559         
560         assertEquals( sbv, sbvSer );
561     }
562 
563 
564     /**
565      * Test serialization of a BinaryValue which normalized value is the same
566      * than the value
567      */
568     @Test public void testNormalizedBinarySameValueSerialization() throws NamingException, IOException, ClassNotFoundException
569     {
570         byte[] v1 = StringTools.getBytesUtf8( "Test   Test" );
571         
572         // First check with a value which will be normalized
573         ServerBinaryValue sbv = new ServerBinaryValue( at, v1 );
574         
575         ServerBinaryValue sbvSer = deserializeValue( serializeValue( sbv ), at );
576         
577         assertEquals( sbv, sbvSer );
578     }
579 
580 
581     /**
582      * Test serialization of a BinaryValue which does not have a normalized value
583      */
584     @Test public void testNoNormalizedBinaryValueSerialization() throws NamingException, IOException, ClassNotFoundException
585     {
586         byte[] v1 = StringTools.getBytesUtf8( "test" );
587         byte[] v1Norm = StringTools.getBytesUtf8( "test" );
588 
589         // First check with a value which will be normalized
590         ServerBinaryValue sbv = new ServerBinaryValue( at, v1 );
591         
592         sbv.normalize();
593         byte[] normalized = sbv.getNormalizedValueReference();
594         
595         assertTrue( Arrays.equals( v1Norm, normalized ) );
596         assertTrue( Arrays.equals( v1, sbv.get() ) );
597         
598         ServerBinaryValue sbvSer = deserializeValue( serializeValue( sbv ), at );
599         
600         assertEquals( sbv, sbvSer );
601    }
602 
603 
604     /**
605      * Test serialization of a null BinaryValue
606      */
607     @Test public void testNullBinaryValueSerialization() throws NamingException, IOException, ClassNotFoundException
608     {
609         // First check with a value which will be normalized
610         ServerBinaryValue sbv = new ServerBinaryValue( at );
611         
612         sbv.normalize();
613         byte[] normalized = sbv.getNormalizedValueReference();
614         
615         assertEquals( null, normalized );
616         assertEquals( null, sbv.get() );
617         
618         ServerBinaryValue sbvSer = deserializeValue( serializeValue( sbv ), at );
619         
620         assertEquals( sbv, sbvSer );
621    }
622 
623 
624     /**
625      * Test serialization of an empty BinaryValue
626      */
627     @Test public void testEmptyBinaryValueSerialization() throws NamingException, IOException, ClassNotFoundException
628     {
629         // First check with a value which will be normalized
630         ServerBinaryValue sbv = new ServerBinaryValue( at, StringTools.EMPTY_BYTES );
631         
632         sbv.normalize();
633         byte[] normalized = sbv.getNormalizedValueReference();
634         
635         assertTrue( Arrays.equals( StringTools.EMPTY_BYTES, normalized ) );
636         assertTrue( Arrays.equals( StringTools.EMPTY_BYTES, sbv.get() ) );
637         
638         ServerBinaryValue sbvSer = deserializeValue( serializeValue( sbv ), at );
639         
640         assertEquals( sbv, sbvSer );
641    }
642 
643 
644     /**
645      * Test serialization of a BinaryValue which is the same than the value
646      */
647     @Test public void testSameNormalizedBinaryValueSerialization() throws NamingException, IOException, ClassNotFoundException
648     {
649         byte[] v1 = StringTools.getBytesUtf8( "test" );
650         byte[] v1Norm = StringTools.getBytesUtf8( "test" );
651 
652         // First check with a value which will be normalized
653         ServerBinaryValue sbv = new ServerBinaryValue( at, v1 );
654         
655         sbv.normalize();
656         byte[] normalized = sbv.getNormalizedValueReference();
657         
658         assertTrue( Arrays.equals( v1Norm, normalized ) );
659         assertTrue( Arrays.equals( v1, sbv.get() ) );
660         
661         ServerBinaryValue sbvSer = deserializeValue( serializeValue( sbv ), at );
662         
663         assertEquals( sbv, sbvSer );
664    }
665 }