blob: 411743c7c359fb72d9ffd058ece4ee2c7e4a64d4 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.felix.cm.file;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class FilePersistenceManagerTest
{
private File file = new File( System.getProperty( "java.io.tmpdir" ), "config" );
private FilePersistenceManager fpm;
@Before
public void setUp() throws Exception
{
fpm = new FilePersistenceManager( file.getAbsolutePath() );
}
@After
public void tearDown() throws Exception
{
File[] children = file.listFiles();
for ( int i = 0; children != null && i < children.length; i++ )
{
children[i].delete();
}
file.delete();
}
@Test
public void testPidPlain()
{
assertEquals( "plain", fpm.encodePid( "plain" ) );
assertEquals( "plain" + File.separatorChar + "path", fpm.encodePid( "plain.path" ) );
assertEquals( "encod%00e8", fpm.encodePid( "encod\u00E8" ) );
assertEquals( "encod%00e8" + File.separatorChar + "path", fpm.encodePid( "encod\u00E8/path" ) );
assertEquals( "encode" + File.separatorChar + "%1234" + File.separatorChar + "path",
fpm.encodePid( "encode/\u1234/path" ) );
assertEquals( "encode" + File.separatorChar + " %0025 " + File.separatorChar + "path",
fpm.encodePid( "encode/ % /path" ) );
}
@Test
public void testPidEncodingCollision() {
// assert a == encode(a) ==> encode(a) == encode(encode(a))
final String plain = "plain";
assertEquals( plain, fpm.encodePid( plain ) );
assertEquals( fpm.encodePid( plain ), fpm.encodePid( fpm.encodePid( plain ) ) );
assertEquals( plain, fpm.encodePid( fpm.encodePid( plain ) ) );
// assert a != encode(a) ==> encode(a) != encode(encode(a))
final String encode = "encod\u00E8";
final String encoded = "encod%00e8";
assertEquals( encoded, fpm.encodePid( encode ) );
assertFalse( encode.equals( fpm.encodePid( encode ) ) );
assertFalse( fpm.encodePid( encode ).equals( fpm.encodePid( fpm.encodePid( encode ) ) ) );
assertFalse( encode.equals( fpm.encodePid( fpm.encodePid( encode ) ) ) );
}
@Test
public void testPidDeviceNameEncodingWindows() {
// assert proper encoding of windows device file names (FELIX-4302)
String oldOsName = System.getProperty( "os.name" );
try {
System.setProperty("os.name", "Windows for testing");
FilePersistenceManager winFpm = new FilePersistenceManager( file.getAbsolutePath() );
assertEquals("%004cPT1", winFpm.encodePid( "LPT1" ));
assertEquals("%006cpt1", winFpm.encodePid( "lpt1" ));
assertEquals("%0043ON", winFpm.encodePid( "CON" ));
assertEquals("%0050RN", winFpm.encodePid( "PRN" ));
assertEquals("%0041UX", winFpm.encodePid( "AUX" ));
assertEquals("CLOCK%0024", winFpm.encodePid( "CLOCK$" ));
assertEquals("%004eUL", winFpm.encodePid( "NUL" ));
assertEquals("%0043OM6", winFpm.encodePid( "COM6" ));
} finally {
System.setProperty( "os.name", oldOsName );
}
}
@Test
public void testPidDeviceNameEncodingNonWindows() {
// assert no encoding of windows device file names (FELIX-4302)
String oldOsName = System.getProperty( "os.name" );
try {
System.setProperty("os.name", "Unix for testing");
FilePersistenceManager winFpm = new FilePersistenceManager( file.getAbsolutePath() );
assertEquals("LPT1", winFpm.encodePid( "LPT1" ));
assertEquals("lpt1", winFpm.encodePid( "lpt1" ));
assertEquals("CON", winFpm.encodePid( "CON" ));
assertEquals("PRN", winFpm.encodePid( "PRN" ));
assertEquals("AUX", winFpm.encodePid( "AUX" ));
assertEquals("CLOCK%0024", winFpm.encodePid( "CLOCK$" ));
assertEquals("NUL", winFpm.encodePid( "NUL" ));
assertEquals("COM6", winFpm.encodePid( "COM6" ));
} finally {
System.setProperty( "os.name", oldOsName );
}
}
@Test
public void testCreateDir()
{
assertTrue( file.isDirectory() );
}
@Test
public void testSimple() throws IOException
{
check( "String", "String Value" );
check( "Integer", new Integer( 2 ) );
check( "Long", new Long( 2 ) );
check( "Float", new Float( 2 ) );
check( "Double", new Double( 2 ) );
check( "Byte", new Byte( ( byte ) 2 ) );
check( "Short", new Short( ( short ) 2 ) );
check( "Character", new Character( 'a' ) );
check( "Boolean", Boolean.TRUE );
}
@Test
public void testQuoting() throws IOException
{
check( "QuotingSeparators", "\\()[]{}.,=\"\"''" );
check( "QuotingWellKnown", "BSP:\b, TAB:\t, LF:\n, FF:\f, CR:\r" );
check( "QuotingControl", new String( new char[]
{ 5, 10, 32, 64 } ) );
}
@Test
public void testArray() throws IOException
{
check( "StringArray", new String[]
{ "one", "two", "three" } );
check( "IntArray", new int[]
{ 0, 1, 2 } );
check( "IntegerArray", new Integer[]
{ new Integer( 0 ), new Integer( 1 ), new Integer( 2 ) } );
}
@Test
public void testEmptyArray() throws IOException
{
check( "StringArray", new String[0] );
check( "IntArray", new int[0] );
check( "CharArray", new char[0] );
check( "ShortArray", new short[0] );
}
@Test
public void testVector() throws IOException
{
check( "StringVector", new Vector<>( Arrays.asList( new String[]
{ "one", "two", "three" } ) ) );
check( "IntegerVector", new Vector<>( Arrays.asList( new Integer[]
{ new Integer( 0 ), new Integer( 1 ), new Integer( 2 ) } ) ) );
}
@Test
public void testEmptyVector() throws IOException
{
check( "StringArray", new Vector<String>() );
check( "IntArray", new Vector<Integer>() );
check( "CharArray", new Vector<Character>() );
check( "ShortArray", new Vector<Short>() );
}
@Test
public void testList() throws IOException
{
check( "StringList", Arrays.asList( new String[]
{ "one", "two", "three" } ) );
check( "IntegerList", Arrays.asList( new Integer[]
{ new Integer( 0 ), new Integer( 1 ), new Integer( 2 ) } ) );
}
@Test
public void testEmptyList() throws IOException
{
check( "StringArray", new ArrayList<String>(0) );
check( "IntArray", new ArrayList<Integer>(0) );
check( "CharArray", new ArrayList<Character>(0) );
check( "ShortArray", new ArrayList<Short>(0) );
}
@Test
public void testMultiValue() throws IOException
{
Dictionary<String, Object> props = new Hashtable<>();
props.put( "String", "String Value" );
props.put( "Integer", new Integer( 2 ) );
props.put( "Long", new Long( 2 ) );
props.put( "Float", new Float( 2 ) );
props.put( "Double", new Double( 2 ) );
props.put( "Byte", new Byte( ( byte ) 2 ) );
props.put( "Short", new Short( ( short ) 2 ) );
props.put( "Character", new Character( 'a' ) );
props.put( "Boolean", Boolean.TRUE );
props.put( "Array", new boolean[]
{ true, false } );
check( "MultiValue", props );
}
// test configuration keys not conforming to the recommended specification
// for configuration keys in OSGi CM 1.3, 104.4.2, Configuration Properties
@Test
public void testNonSpecKeys() throws IOException {
check( "with\ttab", "the value" );
check( "with blank", "the value" );
check( "\\()[]{}.,=\"\"''", "quoted key" );
check( "\"with quotes\"", "key with quotes" );
check( "=leading equals", "leading equals" );
}
// Test expected to always succeed on non-Windows platforms. It may
// break if FilePersistenceManager.encode does not cope properly
// with Windows device names (see FELIX-4302)
@Test
public void testWindowsSpecialNames() throws IOException
{
check( "prefixLPT1", "lpt1" );
check( "prefix.prefix2.LPT1.suffix", "lpt1" );
check( "prefix.LPT1.suffix", "lpt1" );
check( "prefix.LPT1", "lpt1" );
check( "LPT1", "lpt1" );
}
@Test
public void testKeyOrderInFile() throws IOException
{
Dictionary<String, Object> props = new Hashtable<>();
// The following keys are stored as "c, a, b" in HashTable based
// due to their hash code
props.put( "a_first", "a" );
props.put( "b_second", "b" );
props.put( "c_third", "c" );
String pid = "keyOrderInFile";
fpm.store( pid, props );
File configFile = new File( file, fpm.encodePid( pid ) + ".config" );
FileReader reader = new FileReader( configFile );
BufferedReader breader = new BufferedReader(reader);
try
{
String previousLine = breader.readLine();
while ( previousLine != null)
{
String line = breader.readLine();
if (line != null) {
assertTrue( previousLine.compareTo( line ) < 0 );
}
previousLine = line;
}
}
finally
{
breader.close();
}
}
private void check( String name, Object value ) throws IOException
{
Dictionary<String, Object> props = new Hashtable<>();
props.put( name, value );
check( name, props );
}
private void check( String pid, Dictionary<String, Object> props ) throws IOException
{
fpm.store( pid, props );
assertTrue( new File( file, fpm.encodePid( pid ) + ".config" ).exists() );
@SuppressWarnings("unchecked")
Dictionary<String, Object> loaded = fpm.load( pid );
assertNotNull( loaded );
assertEquals( props.size(), loaded.size() );
for ( Enumeration<String> pe = props.keys(); pe.hasMoreElements(); )
{
String key = pe.nextElement();
checkValues( props.get( key ), loaded.get( key ) );
}
}
private void checkValues( Object value1, Object value2 )
{
assertNotNull( value2 );
if ( value1.getClass().isArray() )
{
assertTrue( value2.getClass().isArray() );
assertEquals( value1.getClass().getComponentType(), value2.getClass().getComponentType() );
assertEquals( Array.getLength( value1 ), Array.getLength( value2 ) );
for ( int i = 0; i < Array.getLength( value1 ); i++ )
{
assertEquals( Array.get( value1, i ), Array.get( value2, i ) );
}
}
else
{
assertEquals( value1, value2 );
}
}
}