/* * Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. */ package javax.microedition.sensor; import com.sun.javame.sensor.TestingSensor; import com.sun.midp.i3test.TestCase; public class TestSensorManager extends TestCase { private final static SensorInfo DUMMY_SENSOR_INFO = new SensorInfo() { public ChannelInfo[] getChannelInfos() { return null; } public int getConnectionType() { return 0; } public String getContextType() { return null; } public String getDescription() { return null; } public int getMaxBufferSize() { return 0; } public String getModel() { return null; } public Object getProperty(String name) { return null; } public String[] getPropertyNames() { return null; } public String getQuantity() { return null; } public String getUrl() { return null; } public boolean isAvailabilityPushSupported() { return false; } public boolean isAvailable() { return false; } public boolean isConditionPushSupported() { return false; } }; private final static SensorListener DUMMY_SENSOR_LISTENER = new SensorListener() { public void sensorAvailable(SensorInfo info) { } public void sensorUnavailable(SensorInfo info) { } }; private void testAddSensorListenerThrowsNullPointerException() { // Just to remove the ERROR message in i3test assertTrue(true); // NullPointerException - if either of the parameters is null try { SensorManager.addSensorListener(null, (SensorInfo) null); fail("NullPointerException expected"); } catch (NullPointerException ignore) { } try { SensorManager.addSensorListener(null, DUMMY_SENSOR_INFO); fail("NullPointerException expected"); } catch (NullPointerException ignore) { } try { SensorManager.addSensorListener(DUMMY_SENSOR_LISTENER, (SensorInfo) null); fail("NullPointerException expected"); } catch (NullPointerException ignore) { } // NullPointerException - if the listener, or the quantity is null try { SensorManager.addSensorListener(null, (String) null); fail("NullPointerException expected"); } catch (NullPointerException ignore) { } try { SensorManager.addSensorListener(DUMMY_SENSOR_LISTENER, (String) null); fail("NullPointerException expected"); } catch (NullPointerException ignore) { } try { SensorManager.addSensorListener(null, ""); fail("NullPointerException expected"); } catch (NullPointerException ignore) { } } private void testAddSensorListenerThrowsIllegalArgumentException() { // Just to remove the ERROR message in i3test assertTrue(true); // IllegalArgumentException - if info does not match to any of the // provided sensors try { SensorManager.addSensorListener(DUMMY_SENSOR_LISTENER, DUMMY_SENSOR_INFO); fail("IllegalArgumentException expected"); } catch (IllegalArgumentException ignore) { } } private void testRemoveSensorListenerThrowsNull() { // Just to remove the ERROR message in i3test assertTrue(true); try { SensorManager.removeSensorListener(null); fail("NullPointerException expected"); } catch (NullPointerException ignore) { } } private void testRemoveNonExistingSensorListener() { // Just to remove the ERROR message in i3test assertTrue(true); // We call this two times to be sure the listener is not registered SensorManager.removeSensorListener(DUMMY_SENSOR_LISTENER); SensorManager.removeSensorListener(DUMMY_SENSOR_LISTENER); } class MockSensorListener implements SensorListener { private int available; private int unavailable; private boolean isavailable; public void sensorAvailable(SensorInfo info) { incAvailable(); } public void sensorUnavailable(SensorInfo info) { incUnAvailable(); } private synchronized void incAvailable() { available++; isavailable = true; } private synchronized void incUnAvailable() { unavailable++; isavailable = false; } // Mock validation methods private int expectedAvailable; private int expectedUnavailable; private boolean expectedIsavailable; synchronized void validate() { assertEquals("Available calls count should equal", expectedAvailable, available); assertEquals("Unavailable calls count should equal", expectedUnavailable, unavailable); assertTrue("Availability should equal", expectedIsavailable == isavailable); } synchronized public void expectCallback(boolean available) { if (available) { expectedAvailable++; } else { expectedUnavailable++; } expectedIsavailable = available; } } class MalliciousMockSensorListener extends MockSensorListener { /** To avoid throwing from the addSensorListener method. */ private volatile boolean firstTime = true; public void sensorAvailable(SensorInfo info) { super.sensorAvailable(info); if (!firstTime) { throw new RuntimeException("Mallicious throw"); } } public void sensorUnavailable(SensorInfo info) { super.sensorUnavailable(info); if (!firstTime) { throw new RuntimeException("Mallicious throw"); } firstTime = false; } } private void testMultipleAddSensorListenerCalls(boolean available, MockSensorListener listener) { SensorInfo[] infos = SensorManager.findSensors("sensor:sensor_tester"); assertTrue(infos.length > 0); // Retrieve the internal class TestingSensor sensor = TestingSensor.tryGetInstance(); // Test the initial listener state listener.validate(); sensor.setAvailable(available); assertTrue(available == infos[0].isAvailable()); listener.validate(); try { // Add listener and test changed state SensorManager.addSensorListener(listener, infos[0]); listener.expectCallback(available); listener.validate(); // This call should be ignored, check state SensorManager.addSensorListener(listener, infos[0]); listener.validate(); } finally { SensorManager.removeSensorListener(listener); } } private void testSwapAvailabilityState(long timeout, boolean async, boolean nativeAsync, MockSensorListener listener) throws InterruptedException { SensorInfo[] infos = SensorManager.findSensors("sensor:sensor_tester"); assertTrue(infos.length > 0); // Retrieve and setup the internal class TestingSensor sensor = TestingSensor.tryGetInstance(); sensor.setNotificationEnabled(async); sensor.setNativeAvailability(nativeAsync); boolean state = false; listener.validate(); try { // Add listener, counters are incremented immediately SensorManager.addSensorListener(listener, infos[0]); listener.expectCallback(state); // Check and swap several times for (int i = 0; i < 10; i++) { listener.validate(); // Swap state state = !state; sensor.setAvailable(state); assertTrue("Info should be updated immediately", state == infos[0].isAvailable()); listener.expectCallback(state); // Wait for poller action Thread.sleep(timeout); } } finally { SensorManager.removeSensorListener(listener); } // Swap state without attached listener for (int i = 0; i < 10; i++) { sensor.setAvailable(!infos[0].isAvailable()); } // Wait for poller action Thread.sleep(timeout); // Check that listener state was not changed after removal listener.validate(); } public void runTests() throws Exception { declare("testAddSensorListenerThrowsNullPointerException"); testAddSensorListenerThrowsNullPointerException(); declare("testAddSensorListenerThrowsIllegalArgumentException"); testAddSensorListenerThrowsIllegalArgumentException(); declare("testRemoveSensorListenerThrowsNull"); testRemoveSensorListenerThrowsNull(); declare("testRemoveNonExistingSensorListener"); testRemoveNonExistingSensorListener(); // Tests with broken listeners are called first to know whether they // broke something declare("testMultipleAddSensorListenerCalls: available=true, mallicious"); testMultipleAddSensorListenerCalls(true, new MalliciousMockSensorListener()); declare("testMultipleAddSensorListenerCalls: available=false, mallicious"); testMultipleAddSensorListenerCalls(false, new MalliciousMockSensorListener()); declare("testSwapAvailabilityState: sync, mallicious"); testSwapAvailabilityState(2000, false, false, new MalliciousMockSensorListener()); declare("testSwapAvailabilityState: async, nativeAsync=false, mallicious"); testSwapAvailabilityState(100, true, false, new MalliciousMockSensorListener()); declare("testSwapAvailabilityState: async, nativeAsync=true, mallicious"); testSwapAvailabilityState(100, true, true, new MalliciousMockSensorListener()); // Tests with ordinary listeners declare("testMultipleAddSensorListenerCalls: available=true"); testMultipleAddSensorListenerCalls(true, new MockSensorListener()); declare("testMultipleAddSensorListenerCalls: available=false"); testMultipleAddSensorListenerCalls(false, new MockSensorListener()); declare("testSwapAvailabilityState: sync"); testSwapAvailabilityState(2000, false, false, new MockSensorListener()); declare("testSwapAvailabilityState: async, nativeAsync=false"); testSwapAvailabilityState(100, true, false, new MockSensorListener()); declare("testSwapAvailabilityState: async, nativeAsync=true"); testSwapAvailabilityState(100, true, true, new MockSensorListener()); } }