diff options
Diffstat (limited to 'tests/src/org/lineageos')
37 files changed, 5005 insertions, 0 deletions
diff --git a/tests/src/org/lineageos/tests/LineageOSTestApplication.java b/tests/src/org/lineageos/tests/LineageOSTestApplication.java new file mode 100644 index 00000000..0eb754e9 --- /dev/null +++ b/tests/src/org/lineageos/tests/LineageOSTestApplication.java @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2016, The CyanogenMod Project + * + * Licensed 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.lineageos.tests; + +import android.app.Application; +import android.content.Context; + +/** + * Created by adnan on 2/4/16. + */ +public class LineageOSTestApplication extends Application { + private static Context sApplicationContext; + + @Override + public void onCreate() { + super.onCreate(); + sApplicationContext = getApplicationContext(); + } + + public static Context getStaticApplicationContext() { + return sApplicationContext; + } +} diff --git a/tests/src/org/lineageos/tests/TestActivity.java b/tests/src/org/lineageos/tests/TestActivity.java new file mode 100644 index 00000000..9c8d8604 --- /dev/null +++ b/tests/src/org/lineageos/tests/TestActivity.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed 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.lineageos.tests; + +import android.app.ListActivity; +import android.os.Bundle; + +import android.view.View; +import android.widget.ArrayAdapter; +import android.widget.ListView; + +public abstract class TestActivity extends ListActivity +{ + Test[] mTests; + + protected abstract String tag(); + protected abstract Test[] tests(); + + protected abstract class Test { + protected String name; + protected Test(String n) { + name = n; + } + protected abstract void run(); + } + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + mTests = tests(); + + String[] labels = new String[mTests.length]; + for (int i=0; i<mTests.length; i++) { + labels[i] = mTests[i].name; + } + + setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, labels)); + } + + @Override + public void onListItemClick(ListView l, View v, int position, long id) + { + Test t = mTests[position]; + android.util.Log.d(tag(), "Test: " + t.name); + t.run(); + } + +}
\ No newline at end of file diff --git a/tests/src/org/lineageos/tests/common/MockIBinderStubForInterface.java b/tests/src/org/lineageos/tests/common/MockIBinderStubForInterface.java new file mode 100644 index 00000000..79c61744 --- /dev/null +++ b/tests/src/org/lineageos/tests/common/MockIBinderStubForInterface.java @@ -0,0 +1,59 @@ +/** + * Copyright (c) 2016, The CyanogenMod Project + * + * Licensed 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.lineageos.tests.common; + +import android.os.IBinder; +import android.os.IInterface; +import android.os.RemoteCallbackList; +import org.junit.Assert; +import org.mockito.Mockito; + +import java.lang.reflect.Field; + +/** + * Helper class to mock stubs for IInterfaces + * Ensures that when querying the local interface + * we return the instance itself as to preserve the mock instance + */ +public final class MockIBinderStubForInterface { + private MockIBinderStubForInterface() {} + + private static <T extends IBinder> String getStubDescriptor(Class<T> stubClass) { + String descriptor = null; + try { + Field f = stubClass.getDeclaredField("DESCRIPTOR"); + f.setAccessible(true); + descriptor = (String) f.get(stubClass); + } catch (NoSuchFieldException | IllegalAccessException e) { + Assert.fail(e.getMessage()); + } + return descriptor; + } + + public static <T extends IBinder> T getMockInterface(Class<T> stub) { + String descriptor = getStubDescriptor(stub); + T mockInterface = Mockito.mock(stub); + Mockito.doReturn(mockInterface) + .when(mockInterface) + .queryLocalInterface(descriptor == null ? + Mockito.anyString() : Mockito.eq(descriptor)); + Mockito.doReturn(Mockito.mock(IBinder.class)) + .when((IInterface) mockInterface) + .asBinder(); + return mockInterface; + } +} diff --git a/tests/src/org/lineageos/tests/common/ThreadServiceTestCase.java b/tests/src/org/lineageos/tests/common/ThreadServiceTestCase.java new file mode 100644 index 00000000..55807c5c --- /dev/null +++ b/tests/src/org/lineageos/tests/common/ThreadServiceTestCase.java @@ -0,0 +1,200 @@ +package org.lineageos.tests.common; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; + +import android.app.Service; +import android.content.Intent; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.IBinder; +import android.os.Looper; +import android.test.InstrumentationTestCase; +import android.test.ServiceTestCase; + +/** + * Tests a service in its own Thread. + * + * + * <p> + * The {@link ServiceTestCase} class creates the service in the same thread the + * test is running. In consequence Handlers and other constructs that depend on + * the fact that the service methods are always run on the <em>main thread</em> + * won't work. + * </p> + * + * <p> + * To circumvent this, this test class creates a {@link HandlerThread} on setup + * to simulate the main tread and provides helper constructs to ease the + * communication between the Service and the test class : + * </p> + * + * <ul> + * <li>The {@link #runOnServiceThread(Runnable)} methods allows to run code on + * the service pseudo-main thread.</li> + * <li>The {@link #startService(boolean, ServiceRunnable)} mehod allows starting + * the service in its own thread with some additional initialization code.</li> + * </ul> + * + * + * @author Antoine Martin + * + */ +public abstract class ThreadServiceTestCase<T extends Service> extends ServiceTestCase<T> { + + /** Typical maximum wait time for something to happen on the service */ + public static final long WAIT_TIME = 5 * 1000; + + /* + * This class provides final mutable values through indirection + */ + static class Holder<H> { + H value; + } + + protected Handler serviceHandler; + protected Looper serviceLooper; + /* + * Got to catch this again because of damn package visibility of + * mServiceClass in base class. + */ + protected Class<T> serviceClass; + + public ThreadServiceTestCase(Class<T> serviceClass) { + super(serviceClass); + this.serviceClass = serviceClass; + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + // Setup service thread + HandlerThread serviceThread = new HandlerThread("[" + serviceClass.getSimpleName() + "Thread]"); + serviceThread.start(); + serviceLooper = serviceThread.getLooper(); + serviceHandler = new Handler(serviceLooper); + } + + @Override + public void testServiceTestCaseSetUpProperly() throws Exception { + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + // teardown service thread + if (serviceLooper != null) + serviceLooper.quit(); + serviceHandler = null; + } + + /** + * Runs the specified runnable on the service tread and waits for its + * completion. + * + * @see InstrumentationTestCase#runTestOnUiThread(Runnable) + * @param r + * The runnable to run on the pseudo-main thread. + */ + protected void runOnServiceThread(final Runnable r) { + final CountDownLatch serviceSignal = new CountDownLatch(1); + serviceHandler.post(new Runnable() { + + @Override + public void run() { + r.run(); + serviceSignal.countDown(); + } + }); + + try { + serviceSignal.await(); + } catch (InterruptedException ie) { + fail("The Service thread has been interrupted"); + } + } + + /** + * Runnable interface allowing service initialization personalization. + * + * @author Antoine Martin + * + */ + protected interface ServiceRunnable { + public void run(Service service); + } + + /** + * Initialize the service in its own thread and returns it. + * + * @param bound + * if {@code true}, the service will be created as if it was + * bound by a client. if {@code false}, it will be created by a + * {@code startService} call. + * @param r + * {@link ServiceRunnable} instance that will be called with the + * created service. + * @return The created service. + */ + protected T startService(final ServiceRunnable r) { + final Holder<T> serviceHolder = new Holder<T>(); + + // I want to create my service in its own 'Main thread' + // So it can use its handler + runOnServiceThread(new Runnable() { + + @Override + public void run() { + T service = null; + startService(new Intent(getContext(), serviceClass)); + service = getService(); + if (r != null) + r.run(service); + serviceHolder.value = service; + } + }); + + return serviceHolder.value; + } + + protected IBinder bindService(final ServiceRunnable r) { + final Holder<IBinder> serviceHolder = new Holder<IBinder>(); + + // I want to create my service in its own 'Main thread' + // So it can use its handler + runOnServiceThread(new Runnable() { + + @Override + public void run() { + T service = null; + IBinder binder = bindService(new Intent(getContext(), serviceClass)); + service = getService(); + if (r != null) + r.run(service); + serviceHolder.value = binder; + } + }); + + return serviceHolder.value; + } + + public static class ServiceSyncHelper { + // The semaphore will wakeup clients + protected final Semaphore semaphore = new Semaphore(0); + + /** + * Waits for some response coming from the service. + * + * @param timeout + * The maximum time to wait. + * @throws InterruptedException + * if the Thread is interrupted or reaches the timeout. + */ + public synchronized void waitListener(long timeout) throws InterruptedException { + if (!semaphore.tryAcquire(timeout, TimeUnit.MILLISECONDS)) + throw new InterruptedException(); + } + } + +}
\ No newline at end of file diff --git a/tests/src/org/lineageos/tests/hardware/LineageHardwareTest.java b/tests/src/org/lineageos/tests/hardware/LineageHardwareTest.java new file mode 100644 index 00000000..6d247473 --- /dev/null +++ b/tests/src/org/lineageos/tests/hardware/LineageHardwareTest.java @@ -0,0 +1,388 @@ +/** + * Copyright (c) 2015-2016, The CyanogenMod Project + * + * Licensed 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.lineageos.tests.hardware; + +import android.os.Bundle; + +import android.widget.Toast; + +import java.util.Arrays; +import java.util.List; + +import lineageos.hardware.LineageHardwareManager; +import lineageos.hardware.DisplayMode; + +import org.lineageos.tests.TestActivity; + +/** + * Created by adnan on 8/31/15. + */ +public class LineageHardwareTest extends TestActivity { + private LineageHardwareManager mHardwareManager; + + private static final List<Integer> FEATURES = Arrays.asList( + LineageHardwareManager.FEATURE_ADAPTIVE_BACKLIGHT, + LineageHardwareManager.FEATURE_COLOR_ENHANCEMENT, + LineageHardwareManager.FEATURE_DISPLAY_COLOR_CALIBRATION, + LineageHardwareManager.FEATURE_DISPLAY_GAMMA_CALIBRATION, + LineageHardwareManager.FEATURE_HIGH_TOUCH_SENSITIVITY, + LineageHardwareManager.FEATURE_KEY_DISABLE, + LineageHardwareManager.FEATURE_LONG_TERM_ORBITS, + LineageHardwareManager.FEATURE_SERIAL_NUMBER, + LineageHardwareManager.FEATURE_SUNLIGHT_ENHANCEMENT, + LineageHardwareManager.FEATURE_TOUCH_HOVERING, + LineageHardwareManager.FEATURE_AUTO_CONTRAST, + LineageHardwareManager.FEATURE_DISPLAY_MODES, + LineageHardwareManager.FEATURE_PERSISTENT_STORAGE + ); + + private static final List<String> FEATURE_STRINGS = Arrays.asList( + "FEATURE_ADAPTIVE_BACKLIGHT", + "FEATURE_COLOR_ENHANCEMENT", + "FEATURE_DISPLAY_COLOR_CALIBRATION", + "FEATURE_DISPLAY_GAMMA_CALIBRATION", + "FEATURE_HIGH_TOUCH_SENSITIVITY", + "FEATURE_KEY_DISABLE", + "FEATURE_LONG_TERM_ORBITS", + "FEATURE_SERIAL_NUMBER", + "FEATURE_SUNLIGHT_ENHANCEMENT", + "FEATURE_TOUCH_HOVERING", + "FEATURE_AUTO_CONTRAST", + "FEATURE_DISPLAY_MODES", + "FEATURE_PERSISTENT_STORAGE" + ); + + private static final List<Integer> BOOLEAN_FEATURES = Arrays.asList( + LineageHardwareManager.FEATURE_ADAPTIVE_BACKLIGHT, + LineageHardwareManager.FEATURE_COLOR_ENHANCEMENT, + LineageHardwareManager.FEATURE_HIGH_TOUCH_SENSITIVITY, + LineageHardwareManager.FEATURE_KEY_DISABLE, + LineageHardwareManager.FEATURE_SUNLIGHT_ENHANCEMENT, + LineageHardwareManager.FEATURE_TOUCH_HOVERING, + LineageHardwareManager.FEATURE_AUTO_CONTRAST + ); + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + mHardwareManager = LineageHardwareManager.getInstance(this); + } + + @Override + protected String tag() { + return null; + } + + @Override + protected Test[] tests() { + return mTests; + } + + private boolean vibratorSupported() { + if (mHardwareManager.isSupported(LineageHardwareManager.FEATURE_VIBRATOR)) { + return true; + } else { + Toast.makeText(LineageHardwareTest.this, "Vibrator not supported", + Toast.LENGTH_SHORT).show(); + return false; + } + } + + private boolean displayColorCalibrationSupported() { + if (mHardwareManager.isSupported(LineageHardwareManager.FEATURE_DISPLAY_COLOR_CALIBRATION)) { + return true; + } else { + Toast.makeText(LineageHardwareTest.this, "Display Color Calibration not supported", + Toast.LENGTH_SHORT).show(); + return false; + } + } + + private boolean ltoSupported() { + if (mHardwareManager.isSupported(LineageHardwareManager.FEATURE_LONG_TERM_ORBITS)) { + return true; + } else { + Toast.makeText(LineageHardwareTest.this, "Long Term Orbits not supported", + Toast.LENGTH_SHORT).show(); + return false; + } + } + + private boolean serialSupported() { + if (mHardwareManager.isSupported(LineageHardwareManager.FEATURE_SERIAL_NUMBER)) { + return true; + } else { + Toast.makeText(LineageHardwareTest.this, "Serial number not supported", + Toast.LENGTH_SHORT).show(); + return false; + } + } + + private boolean uniqueDeviceIdSupported() { + if (mHardwareManager.isSupported(LineageHardwareManager.FEATURE_UNIQUE_DEVICE_ID)) { + return true; + } else { + Toast.makeText(LineageHardwareTest.this, "Unique device ID not supported", + Toast.LENGTH_SHORT).show(); + return false; + } + } + + private boolean displayModesSupported() { + if (mHardwareManager.isSupported(LineageHardwareManager.FEATURE_DISPLAY_MODES)) { + return true; + } else { + Toast.makeText(LineageHardwareTest.this, "Display modes not supported", + Toast.LENGTH_SHORT).show(); + return false; + } + } + + private boolean persistentStorageSupported() { + if (mHardwareManager.isSupported(LineageHardwareManager.FEATURE_PERSISTENT_STORAGE)) { + return true; + } else { + Toast.makeText(LineageHardwareTest.this, "Persistent storage not supported", + Toast.LENGTH_SHORT).show(); + return false; + } + } + + private Test[] mTests = new Test[] { + new Test("Test get supported features") { + public void run() { + Toast.makeText(LineageHardwareTest.this, "Supported features " + + mHardwareManager.getSupportedFeatures(), + Toast.LENGTH_SHORT).show(); + } + }, + new Test("Test features supported") { + @Override + protected void run() { + StringBuilder builder = new StringBuilder(); + int i = 0; + for (int feature : FEATURES) { + boolean supported = mHardwareManager.isSupported(feature); + if (mHardwareManager.isSupported(FEATURE_STRINGS.get(i)) != supported) { + throw new RuntimeException("Internal error, feature string lookup failed"); + } + i++; + builder.append("Feature " + feature + "\n") + .append("is supported " + supported + "\n"); + } + Toast.makeText(LineageHardwareTest.this, "Supported features " + + builder.toString(), + Toast.LENGTH_SHORT).show(); + } + }, + new Test("Test boolean features enabled") { + @Override + protected void run() { + StringBuilder builder = new StringBuilder(); + for (int feature : BOOLEAN_FEATURES) { + builder.append("Feature " + feature + "\n") + .append("is enabled " + mHardwareManager.isSupported(feature) + + "\n"); + } + Toast.makeText(LineageHardwareTest.this, "Features " + + builder.toString(), + Toast.LENGTH_SHORT).show(); + } + }, + new Test("Test get vibrator intensity") { + @Override + protected void run() { + if (vibratorSupported()) { + Toast.makeText(LineageHardwareTest.this, "Vibrator intensity " + + mHardwareManager.getVibratorIntensity(), + Toast.LENGTH_SHORT).show(); + } + } + }, + new Test("Test get vibrator default intensity") { + @Override + protected void run() { + if (vibratorSupported()) { + Toast.makeText(LineageHardwareTest.this, "Vibrator default intensity " + + mHardwareManager.getVibratorDefaultIntensity(), + Toast.LENGTH_SHORT).show(); + } + } + }, + new Test("Test get vibrator max intensity") { + @Override + protected void run() { + if (vibratorSupported()) { + Toast.makeText(LineageHardwareTest.this, "Vibrator max intensity " + + mHardwareManager.getVibratorMaxIntensity(), + Toast.LENGTH_SHORT).show(); + } + } + }, + new Test("Test get vibrator min intensity") { + @Override + protected void run() { + if (vibratorSupported()) { + Toast.makeText(LineageHardwareTest.this, "Vibrator min intensity " + + mHardwareManager.getVibratorMinIntensity(), + Toast.LENGTH_SHORT).show(); + } + } + }, + new Test("Test get vibrator min intensity") { + @Override + protected void run() { + if (vibratorSupported()) { + Toast.makeText(LineageHardwareTest.this, "Vibrator min intensity " + + mHardwareManager.getVibratorWarningIntensity(), + Toast.LENGTH_SHORT).show(); + } + } + }, + new Test("Test Display Color Calibration") { + @Override + protected void run() { + if (displayColorCalibrationSupported()) { + Toast.makeText(LineageHardwareTest.this, "Display Color Calibration " + + mHardwareManager.getDisplayColorCalibration(), + Toast.LENGTH_SHORT).show(); + } + } + }, + new Test("Test Default Display Color Calibration") { + @Override + protected void run() { + if (displayColorCalibrationSupported()) { + Toast.makeText(LineageHardwareTest.this, "Default Display Color Calibration " + + mHardwareManager.getDisplayColorCalibrationDefault(), + Toast.LENGTH_SHORT).show(); + } + } + }, + new Test("Test Display Color Calibration Max") { + @Override + protected void run() { + if (displayColorCalibrationSupported()) { + Toast.makeText(LineageHardwareTest.this, "Display Color Calibration Max " + + mHardwareManager.getDisplayColorCalibrationMax(), + Toast.LENGTH_SHORT).show(); + } + } + }, + new Test("Test Display Color Calibration Min") { + @Override + protected void run() { + if (displayColorCalibrationSupported()) { + Toast.makeText(LineageHardwareTest.this, "Display Color Calibration Min " + + mHardwareManager.getDisplayColorCalibrationMin(), + Toast.LENGTH_SHORT).show(); + } + } + }, + new Test("Test Set Display Color Calibration") { + @Override + protected void run() { + if (displayColorCalibrationSupported()) { + mHardwareManager.setDisplayColorCalibration(new int[] {0,0,0}); + } + } + }, + new Test("Test Get Long Term Orbits Source") { + @Override + protected void run() { + if (ltoSupported()) { + Toast.makeText(LineageHardwareTest.this, "Long Term Orbit Source " + + mHardwareManager.getLtoSource(), + Toast.LENGTH_SHORT).show(); + } + } + }, + new Test("Test Get Long Term Orbits Destination") { + @Override + protected void run() { + if (ltoSupported()) { + Toast.makeText(LineageHardwareTest.this, "Long Term Orbit Destination " + + mHardwareManager.getLtoDestination(), + Toast.LENGTH_SHORT).show(); + } + } + }, + new Test("Test Get Long Term Orbits Interval") { + @Override + protected void run() { + if (ltoSupported()) { + Toast.makeText(LineageHardwareTest.this, "Long Term Orbit Download Interval " + + mHardwareManager.getLtoDownloadInterval(), + Toast.LENGTH_SHORT).show(); + } + } + }, + new Test("Test Get Serial Number") { + @Override + protected void run() { + if (serialSupported()) { + Toast.makeText(LineageHardwareTest.this, "Serial number " + + mHardwareManager.getSerialNumber(), + Toast.LENGTH_SHORT).show(); + } + } + }, + new Test("Test Get Unique Device ID") { + @Override + protected void run() { + if (uniqueDeviceIdSupported()) { + Toast.makeText(LineageHardwareTest.this, "Unique Device ID " + + mHardwareManager.getUniqueDeviceId(), + Toast.LENGTH_SHORT).show(); + } + } + }, + new Test("Test Get Display Modes") { + @Override + protected void run() { + if (displayModesSupported()) { + StringBuilder builder = new StringBuilder(); + for (DisplayMode displayMode : mHardwareManager.getDisplayModes()) { + builder.append("Display mode " + displayMode.name + "\n"); + } + Toast.makeText(LineageHardwareTest.this, "Display modes: \n" + + builder.toString(), Toast.LENGTH_SHORT).show(); + } + } + }, + new Test("Test Get Current Display Mode") { + @Override + protected void run() { + if (displayModesSupported()) { + Toast.makeText(LineageHardwareTest.this, "Default Display Mode " + + mHardwareManager.getCurrentDisplayMode(), + Toast.LENGTH_SHORT).show(); + } + } + }, + new Test("Test Get Default Display Mode") { + @Override + protected void run() { + if (displayModesSupported()) { + Toast.makeText(LineageHardwareTest.this, "Default Display Mode " + + mHardwareManager.getCurrentDisplayMode(), + Toast.LENGTH_SHORT).show(); + } + } + }, + }; +} diff --git a/tests/src/org/lineageos/tests/hardware/unit/DisplayModeTest.java b/tests/src/org/lineageos/tests/hardware/unit/DisplayModeTest.java new file mode 100644 index 00000000..01a24771 --- /dev/null +++ b/tests/src/org/lineageos/tests/hardware/unit/DisplayModeTest.java @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2015, The CyanogenMod Project + * + * Licensed 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.lineageos.tests.hardware.unit; + +import android.os.Parcel; +import android.test.AndroidTestCase; + +import android.test.suitebuilder.annotation.SmallTest; +import lineageos.app.LineageContextConstants; +import lineageos.hardware.DisplayMode; + +/** + * Created by adnan on 9/1/15. + */ +public class DisplayModeTest extends AndroidTestCase { + @Override + protected void setUp() throws Exception { + super.setUp(); + // Only run this if we support hardware abstraction + org.junit.Assume.assumeTrue(mContext.getPackageManager().hasSystemFeature( + LineageContextConstants.Features.HARDWARE_ABSTRACTION)); + } + + @SmallTest + public void testDisplayModeUnravelFromParcel() { + int expectedId = 1337; + String expectedName = "test"; + DisplayMode expectedDisplayMode = new DisplayMode(expectedId, expectedName); + // Write to parcel + Parcel parcel = Parcel.obtain(); + expectedDisplayMode.writeToParcel(parcel, 0); + + // Rewind + parcel.setDataPosition(0); + + // Verify data when unraveling + DisplayMode fromParcel = DisplayMode.CREATOR.createFromParcel(parcel); + + assertNotNull(expectedDisplayMode.id); + assertNotNull(expectedDisplayMode.name); + + assertEquals(expectedDisplayMode.id, fromParcel.id ); + assertEquals(expectedDisplayMode.name, + fromParcel.name); + } +} diff --git a/tests/src/org/lineageos/tests/hardware/unit/LineageHardwareManagerTest.java b/tests/src/org/lineageos/tests/hardware/unit/LineageHardwareManagerTest.java new file mode 100644 index 00000000..01a8145f --- /dev/null +++ b/tests/src/org/lineageos/tests/hardware/unit/LineageHardwareManagerTest.java @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2015, The CyanogenMod Project + * + * Licensed 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.lineageos.tests.hardware.unit; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +import lineageos.app.LineageContextConstants; +import lineageos.hardware.LineageHardwareManager; +import lineageos.hardware.ILineageHardwareService; + +/** + * Created by adnan on 9/1/15. + */ +public class LineageHardwareManagerTest extends AndroidTestCase { + private LineageHardwareManager mLineageHardwareManager; + @Override + protected void setUp() throws Exception { + super.setUp(); + // Only run this if we support hardware abstraction + org.junit.Assume.assumeTrue(mContext.getPackageManager().hasSystemFeature( + LineageContextConstants.Features.HARDWARE_ABSTRACTION)); + mLineageHardwareManager = LineageHardwareManager.getInstance(mContext); + } + + @SmallTest + public void testManagerExists() { + assertNotNull(mLineageHardwareManager); + } + + @SmallTest + public void testManagerServiceIsAvailable() { + ILineageHardwareService ilineageStatusBarManager = mLineageHardwareManager.getService(); + assertNotNull(ilineageStatusBarManager); + } +} diff --git a/tests/src/org/lineageos/tests/hardware/unit/LiveDisplayManagerTest.java b/tests/src/org/lineageos/tests/hardware/unit/LiveDisplayManagerTest.java new file mode 100644 index 00000000..2f0eec9c --- /dev/null +++ b/tests/src/org/lineageos/tests/hardware/unit/LiveDisplayManagerTest.java @@ -0,0 +1,152 @@ +package org.lineageos.tests.hardware.unit; + +import android.content.Context; +import android.os.PowerManager; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +import org.junit.Assume; + +import lineageos.app.LineageContextConstants; +import lineageos.hardware.LineageHardwareManager; +import lineageos.hardware.ILiveDisplayService; +import lineageos.hardware.LiveDisplayConfig; +import lineageos.hardware.LiveDisplayManager; +import lineageos.util.ColorUtils; + +public class LiveDisplayManagerTest extends AndroidTestCase { + + private static final String TAG = "LiveDisplayManagerTest"; + + private LiveDisplayManager mLiveDisplay; + private LineageHardwareManager mHardware; + + private PowerManager mPower; + private PowerManager.WakeLock mWakeLock; + + private LiveDisplayConfig mConfig; + private int mInitialMode; + + @SuppressWarnings("deprecation") + @Override + protected void setUp() throws Exception { + super.setUp(); + + Assume.assumeTrue(mContext.getPackageManager().hasSystemFeature( + LineageContextConstants.Features.LIVEDISPLAY)); + + mLiveDisplay = LiveDisplayManager.getInstance(mContext); + if (mLiveDisplay.getConfig().hasModeSupport()) { + mInitialMode = mLiveDisplay.getMode(); + } + mConfig = mLiveDisplay.getConfig(); + + mHardware = LineageHardwareManager.getInstance(mContext); + mPower = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); + mWakeLock = mPower.newWakeLock( + PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.SCREEN_DIM_WAKE_LOCK, TAG); + mWakeLock.acquire(); + } + + @Override + protected void tearDown() { + mLiveDisplay.setMode(mInitialMode); + mWakeLock.release(); + } + + @SmallTest + public void testManagerExists() { + assertNotNull(mLiveDisplay); + } + + @SmallTest + public void testManagerServiceIsAvailable() { + ILiveDisplayService service = LiveDisplayManager.getService(); + assertNotNull(service); + } + + @SmallTest + public void testConfig() { + assertNotNull(mConfig); + + // at least GPU mode should be available + assertTrue(mConfig.isAvailable()); + } + + @SmallTest + public void testNightMode() throws Exception { + Assume.assumeTrue(mConfig.hasModeSupport()); + + int day = mLiveDisplay.getDayColorTemperature(); + int night = mLiveDisplay.getNightColorTemperature(); + + mLiveDisplay.setMode(LiveDisplayManager.MODE_NIGHT); + assertColorTemperature(night); + + // custom value + mLiveDisplay.setNightColorTemperature(3300); + assertColorTemperature(3300); + + // "default" + mLiveDisplay.setNightColorTemperature(mConfig.getDefaultNightTemperature()); + assertColorTemperature(mConfig.getDefaultNightTemperature()); + + mLiveDisplay.setNightColorTemperature(night); + + // day should not have changed + assertEquals(day, mLiveDisplay.getDayColorTemperature()); + } + + @SmallTest + public void testDayMode() throws Exception { + Assume.assumeTrue(mConfig.hasModeSupport()); + + int day = mLiveDisplay.getDayColorTemperature(); + int night = mLiveDisplay.getNightColorTemperature(); + + mLiveDisplay.setMode(LiveDisplayManager.MODE_DAY); + assertColorTemperature(day); + + // custom value + mLiveDisplay.setDayColorTemperature(8000); + assertColorTemperature(8000); + + // "default" + mLiveDisplay.setDayColorTemperature(mConfig.getDefaultDayTemperature()); + assertColorTemperature(mConfig.getDefaultDayTemperature()); + + mLiveDisplay.setDayColorTemperature(day); + + // night should not have changed + assertEquals(night, mLiveDisplay.getNightColorTemperature()); + } + + @SmallTest + public void testOutdoorMode() throws Exception { + Assume.assumeTrue(mConfig.hasFeature(LiveDisplayManager.MODE_OUTDOOR)); + + assertTrue(mHardware.isSupported(LineageHardwareManager.FEATURE_SUNLIGHT_ENHANCEMENT)); + + mLiveDisplay.setMode(LiveDisplayManager.MODE_OUTDOOR); + Thread.sleep(1000); + assertTrue(mHardware.get(LineageHardwareManager.FEATURE_SUNLIGHT_ENHANCEMENT)); + + mLiveDisplay.setMode(LiveDisplayManager.MODE_OFF); + Thread.sleep(1000); + assertFalse(mHardware.get(LineageHardwareManager.FEATURE_SUNLIGHT_ENHANCEMENT)); + } + + private void assertColorTemperature(int degK) throws Exception { + Thread.sleep(2000); + assertEquals(degK, LiveDisplayManager.getService().getColorTemperature()); + checkHardwareValue(ColorUtils.temperatureToRGB(degK)); + } + + private void checkHardwareValue(float[] expected) { + int[] hardware = mHardware.getDisplayColorCalibration(); + int max = mHardware.getDisplayColorCalibrationMax(); + assertEquals((int)Math.floor(expected[0] * max), hardware[0]); + assertEquals((int)Math.floor(expected[1] * max), hardware[1]); + assertEquals((int)Math.floor(expected[2] * max), hardware[2]); + } +} diff --git a/tests/src/org/lineageos/tests/media/unit/LineageAudioManagerTest.java b/tests/src/org/lineageos/tests/media/unit/LineageAudioManagerTest.java new file mode 100644 index 00000000..e35d3c88 --- /dev/null +++ b/tests/src/org/lineageos/tests/media/unit/LineageAudioManagerTest.java @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2016 The CyanogenMod Project + * + * Licensed 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.lineageos.tests.media.unit; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.AudioFormat; +import android.media.AudioManager; +import android.media.AudioTrack; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import android.util.Log; + +import org.junit.Assume; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import lineageos.app.LineageContextConstants; +import lineageos.media.AudioSessionInfo; +import lineageos.media.LineageAudioManager; +import lineageos.media.ILineageAudioService; + +public class LineageAudioManagerTest extends AndroidTestCase { + + private static final String TAG = "LineageAudioManagerTest"; + + private LineageAudioManager mLineageAudioManager; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + Assume.assumeTrue(mContext.getPackageManager().hasSystemFeature( + LineageContextConstants.Features.AUDIO)); + + mLineageAudioManager = LineageAudioManager.getInstance(mContext); + } + + /** + * EXPECT: The platform should return a valid manager instance. + */ + @SmallTest + public void testManagerExists() { + assertNotNull(mLineageAudioManager); + } + + /** + * EXPECT: The service in the manager should also be valid. + */ + @SmallTest + public void testManagerServiceIsAvailable() { + ILineageAudioService service = LineageAudioManager.getService(); + assertNotNull(service); + } + + /** + * EXPECT: listAudioSessions should be populated when a new stream is + * created, and it's session ID should match what AudioTrack says it is. + * + * We simply create an audio track, and query the policy for sessions. + */ + @SmallTest + public void testSessionList() { + + AudioTrack track = createTestTrack(); + int session = track.getAudioSessionId(); + + AudioSessionInfo info = findAudioSessionInfo(session); + assertNotNull(info); + assertEquals(session, info.getSessionId()); + assertEquals(3, info.getChannelMask()); + + track.release(); + + info = findAudioSessionInfo(session); + assertNull(info); + } + + /** + * EXPECT: LineageAudioManager.ACTION_AUDIO_SESSIONS_CHANGED should be broadcast when + * audio sessions are opened and closed. + * + * We register a receiver for the broadcast, create an AudioTrack, and wait to + * observe both the open and close session events. The info in the returned + * AudioSessionInfo should match our expectations. + */ + @SmallTest + public void testSessionInfoBroadcast() throws Exception { + + IntentFilter filter = new IntentFilter(LineageAudioManager.ACTION_AUDIO_SESSIONS_CHANGED); + AudioSessionReceiver receiver = new AudioSessionReceiver(2); + mContext.registerReceiver(receiver, filter); + + AudioTrack track = createTestTrack(); + track.play(); + track.release(); + + receiver.waitForSessions(); + + mContext.unregisterReceiver(receiver); + + assertEquals(1, receiver.getNumAdded()); + assertEquals(1, receiver.getNumRemoved()); + + assertEquals(1, receiver.getSessions().size()); + + AudioSessionInfo info = receiver.getSessions().get(0); + assertNotNull(info); + assertNotNull(info.toString()); + assertEquals(track.getAudioSessionId(), info.getSessionId()); + assertEquals(3, info.getChannelMask()); + assertEquals(AudioManager.STREAM_MUSIC, info.getStream()); + + } + + private static final int SESSIONS = 50; + + /** + * EXPECT: The ACTION_AUDIO_SESSIONS_CHANGED broadcast and associated backend should + * be resilent to multithreaded and/or aggressive/destructive usage. A single add + * and a single remove event should be broadcast for the lifecycle of a stream. + * + * We register a receiver for session events, spawn a small thread pool, and create + * up to SESSIONS AudioTracks and play + release them on the thread. A small delay + * is inserted to prevent AudioFlinger from running out of tracks. Once the expected + * number of sessions arrives, we verify our expectation regarding event counts, + * and additionally verify that all the session ids we saw when creating our + * AudioTracks were returned in the AudioSessionInfo broadcasts. + */ + @SmallTest + public void testSymphonyOfDestruction() throws Exception { + IntentFilter filter = new IntentFilter(LineageAudioManager.ACTION_AUDIO_SESSIONS_CHANGED); + AudioSessionReceiver receiver = new AudioSessionReceiver(SESSIONS * 2); + mContext.registerReceiver(receiver, filter); + + final List<Integer> sessions = new ArrayList<Integer>(); + + ExecutorService sexecutioner = Executors.newFixedThreadPool(5); + for (int i = 0; i < SESSIONS; i++) { + sexecutioner.submit(new Runnable() { + @Override + public void run() { + AudioTrack track = createTestTrack(); + synchronized (sessions) { + sessions.add(track.getAudioSessionId()); + } + track.play(); + track.release(); + } + }); + if ((i % 2) == 0) { + Thread.sleep(100); + } + } + + receiver.waitForSessions(); + sexecutioner.shutdown(); + + assertEquals(SESSIONS, sessions.size()); + assertEquals(SESSIONS, receiver.getNumAdded()); + assertEquals(SESSIONS, receiver.getNumRemoved()); + + for (AudioSessionInfo info : receiver.getSessions()) { + assertTrue(sessions.contains(info.getSessionId())); + } + } + + private static class AudioSessionReceiver extends BroadcastReceiver { + + private int mAdded = 0; + private int mRemoved = 0; + + private final CountDownLatch mLatch; + + private List<AudioSessionInfo> mSessions = new ArrayList<AudioSessionInfo>(); + + public AudioSessionReceiver(int count) { + mLatch = new CountDownLatch(count); + } + + @Override + public void onReceive(Context context, Intent intent) { + assertNotNull(intent); + + boolean added = intent.getBooleanExtra(LineageAudioManager.EXTRA_SESSION_ADDED, false); + + AudioSessionInfo info = intent.getParcelableExtra(LineageAudioManager.EXTRA_SESSION_INFO); + Log.d(TAG, "onReceive: " + info); + + assertNotNull(info); + + synchronized (mSessions) { + if (added) { + mAdded++; + mSessions.add(info); + } else { + mRemoved++; + } + } + + mLatch.countDown(); + } + + public int getNumAdded() { + return mAdded; + } + + public int getNumRemoved() { + return mRemoved; + } + + public List<AudioSessionInfo> getSessions() { + return mSessions; + } + + public void waitForSessions() throws InterruptedException { + mLatch.await(60, TimeUnit.SECONDS); + } + }; + + private AudioSessionInfo findAudioSessionInfo(int sessionId) { + List<AudioSessionInfo> infos = mLineageAudioManager.listAudioSessions(AudioManager.STREAM_MUSIC); + for (AudioSessionInfo info : infos) { + if (info.getSessionId() == sessionId) { + return info; + } + } + return null; + } + + private AudioTrack createTestTrack() { + int bytes = 2 * 44100 / 1000; + AudioTrack track = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, + AudioFormat.CHANNEL_OUT_STEREO, + AudioFormat.ENCODING_PCM_16BIT, + bytes, + AudioTrack.STATE_INITIALIZED); + return track; + } +} diff --git a/tests/src/org/lineageos/tests/power/unit/PerfomanceManagerTest.java b/tests/src/org/lineageos/tests/power/unit/PerfomanceManagerTest.java new file mode 100644 index 00000000..4259ef62 --- /dev/null +++ b/tests/src/org/lineageos/tests/power/unit/PerfomanceManagerTest.java @@ -0,0 +1,111 @@ +/** + * Copyright (c) 2016, The CyanogenMod Project + * + * Licensed 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.lineageos.tests.power.unit; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +import lineageos.app.LineageContextConstants; +import lineageos.power.IPerformanceManager; +import lineageos.power.PerformanceManager; +import lineageos.power.PerformanceProfile; + +/** + * Code coverage for public facing {@link PerformanceManager} interfaces. + * The test below will save and restore the current performance profile to + * not impact successive tests. + */ +public class PerfomanceManagerTest extends AndroidTestCase { + private static final String TAG = PerfomanceManagerTest.class.getSimpleName(); + private static final int IMPOSSIBLE_POWER_PROFILE = -1; + private PerformanceManager mLineagePerformanceManager; + private PerformanceProfile mSavedPerfProfile; + + @Override + protected void setUp() throws Exception { + super.setUp(); + // Only run this if we support performance abstraction + org.junit.Assume.assumeTrue(mContext.getPackageManager().hasSystemFeature( + LineageContextConstants.Features.PERFORMANCE)); + mLineagePerformanceManager = PerformanceManager.getInstance(mContext); + // Save the perf profile for later restore. + mSavedPerfProfile = mLineagePerformanceManager.getPowerProfile( + mLineagePerformanceManager.getPowerProfile()); + } + + @SmallTest + public void testManagerExists() { + assertNotNull(mLineagePerformanceManager); + } + + @SmallTest + public void testManagerServiceIsAvailable() { + IPerformanceManager ilineageStatusBarManager = mLineagePerformanceManager.getService(); + assertNotNull(ilineageStatusBarManager); + } + + @SmallTest + public void testPowerProfileCantBeSetIfNoneSupported() { + // Assert that if we attempt to set a power profile if none supported + // then we receive a failed response from the service. + if (mLineagePerformanceManager.getNumberOfProfiles() == 0) { + for (int powerProfile = 0; powerProfile < + PerformanceManager.POSSIBLE_POWER_PROFILES.length; powerProfile++) { + assertFalse(mLineagePerformanceManager.setPowerProfile(powerProfile)); + } + } + } + + @SmallTest + public void testGetPowerProfile() { + assertNotSame(IMPOSSIBLE_POWER_PROFILE, mSavedPerfProfile); + } + + @SmallTest + public void testSetAndGetPowerProfile() { + // Identify what power profiles are supported. The api currently returns + // the total number of profiles supported in an ordered manner, thus we can + // assume what they are and if we can set everything correctly. + // TODO: Don't skip powersave. Skipped due to powersave being ignored while device plugged + for (int powerProfile = 1; powerProfile < + PerformanceManager.POSSIBLE_POWER_PROFILES.length; powerProfile++) { + if (powerProfile < mLineagePerformanceManager.getNumberOfProfiles()) { + //It is supported, set it and test if it was set + if (mLineagePerformanceManager.getPowerProfile() != powerProfile) { + mLineagePerformanceManager.setPowerProfile(powerProfile); + // Verify that it was set correctly. + assertEquals(powerProfile, mLineagePerformanceManager.getPowerProfile()); + } + } else { + assertFalse(mLineagePerformanceManager.setPowerProfile(powerProfile)); + } + } + } + + @SmallTest + public void testGetPerfProfileHasAppProfiles() { + // No application has power save by default + assertEquals(false, mLineagePerformanceManager.getProfileHasAppProfiles( + PerformanceManager.PROFILE_POWER_SAVE)); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + // Reset + mLineagePerformanceManager.setPowerProfile(mSavedPerfProfile.getId()); + } +} diff --git a/tests/src/org/lineageos/tests/profiles/ProfileTest.java b/tests/src/org/lineageos/tests/profiles/ProfileTest.java new file mode 100644 index 00000000..1e77538d --- /dev/null +++ b/tests/src/org/lineageos/tests/profiles/ProfileTest.java @@ -0,0 +1,185 @@ +/** + * Copyright (c) 2015, The CyanogenMod Project + * + * Licensed 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.lineageos.tests.profiles; + +import android.media.AudioManager; +import android.os.Bundle; + +import lineageos.app.Profile; +import lineageos.app.Profile.Type; + +import lineageos.app.ProfileManager; +import lineageos.profiles.AirplaneModeSettings; +import lineageos.profiles.BrightnessSettings; +import lineageos.profiles.ConnectionSettings; +import lineageos.profiles.LockSettings; +import lineageos.profiles.RingModeSettings; +import lineageos.profiles.StreamSettings; +import org.lineageos.tests.TestActivity; + +import java.util.ArrayList; +import java.util.UUID; + +/** + * Created by adnan on 6/26/15. + */ +public class ProfileTest extends TestActivity { + private ProfileManager mProfileManager; + private ArrayList<UUID> mProfileUuidList; + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + mProfileManager = ProfileManager.getInstance(this); + mProfileUuidList = new ArrayList<UUID>(); + } + + @Override + protected Test[] tests() { + return mTests; + } + + @Override + protected String tag() { + return null; + } + + private Test[] mTests = new Test[] { + new Test("test create random Profile") { + public void run() { + Profile profile = new Profile("Test Profile"); + profile.setProfileType(Type.TOGGLE); + profile.setExpandedDesktopMode(Profile.ExpandedDesktopMode.ENABLE); + profile.setDozeMode(Profile.DozeMode.DEFAULT); + profile.setScreenLockMode(new LockSettings(Profile.LockMode.DISABLE)); + mProfileUuidList.add(profile.getUuid()); + mProfileManager.addProfile(profile); + } + }, + new Test("test add static Profile") { + public void run() { + Profile profile = new Profile("Test Profile-Active", + 0, UUID.fromString("65cd0d0c-1c42-11e5-9a21-1697f925ec7b")); + profile.setProfileType(Type.TOGGLE); + profile.setExpandedDesktopMode(Profile.ExpandedDesktopMode.ENABLE); + profile.setDozeMode(Profile.DozeMode.DEFAULT); + profile.setScreenLockMode(new LockSettings(Profile.LockMode.DISABLE)); + mProfileUuidList.add(profile.getUuid()); + mProfileManager.addProfile(profile); + mProfileManager.setActiveProfile(profile.getUuid()); + } + }, + new Test("test remove static Profile") { + public void run() { + mProfileManager.removeProfile( + mProfileManager.getProfile("65cd0d0c-1c42-11e5-9a21-1697f925ec7b")); + } + }, + new Test("test create Profile and Set Active") { + public void run() { + Profile profile = new Profile("Test Profile-Active"); + profile.setProfileType(Type.TOGGLE); + profile.setExpandedDesktopMode(Profile.ExpandedDesktopMode.ENABLE); + profile.setDozeMode(Profile.DozeMode.DEFAULT); + profile.setScreenLockMode(new LockSettings(Profile.LockMode.DISABLE)); + mProfileUuidList.add(profile.getUuid()); + mProfileManager.addProfile(profile); + mProfileManager.setActiveProfile(profile.getUuid()); + } + }, + new Test("test create Profile, override airplane settings, and set active") { + @Override + protected void run() { + Profile profile = new Profile("Test Profile-Override-AIR-Active"); + profile.setProfileType(Type.TOGGLE); + AirplaneModeSettings airplaneModeSettings = + new AirplaneModeSettings( + AirplaneModeSettings.BooleanState.STATE_ENABLED, true); + profile.setAirplaneMode(airplaneModeSettings); + mProfileUuidList.add(profile.getUuid()); + mProfileManager.addProfile(profile); + mProfileManager.setActiveProfile(profile.getUuid()); + } + }, + new Test("test create Profile, override ring stream settings, and set active") { + @Override + protected void run() { + Profile profile = new Profile("Test Profile-Override-RNG-Active"); + profile.setProfileType(Type.TOGGLE); + StreamSettings streamSettings = + new StreamSettings(AudioManager.STREAM_RING, 0, true); + profile.setStreamSettings(streamSettings); + mProfileUuidList.add(profile.getUuid()); + mProfileManager.addProfile(profile); + mProfileManager.setActiveProfile(profile.getUuid()); + } + }, + new Test("test create Profile, override BT connection settings, and set active") { + @Override + protected void run() { + Profile profile = new Profile("Test Profile-Override-CNNCT-Active"); + profile.setProfileType(Type.TOGGLE); + ConnectionSettings connectionSettings = + new ConnectionSettings(ConnectionSettings.PROFILE_CONNECTION_BLUETOOTH, + ConnectionSettings.BooleanState.STATE_ENABLED, true); + profile.setConnectionSettings(connectionSettings); + mProfileUuidList.add(profile.getUuid()); + mProfileManager.addProfile(profile); + mProfileManager.setActiveProfile(profile.getUuid()); + } + }, + new Test("test create Profile, override brightness settings, and set active") { + @Override + protected void run() { + Profile profile = new Profile("Test Profile-Override-BRGHT-Active"); + profile.setProfileType(Type.TOGGLE); + BrightnessSettings brightnessSettings = + new BrightnessSettings(0, true); + profile.setBrightness(brightnessSettings); + mProfileUuidList.add(profile.getUuid()); + mProfileManager.addProfile(profile); + mProfileManager.setActiveProfile(profile.getUuid()); + } + }, + new Test("test create Profile, override ringmode settings, and set active") { + @Override + protected void run() { + Profile profile = new Profile("Test Profile-Override-RNGMD-Active"); + profile.setProfileType(Type.TOGGLE); + RingModeSettings ringSettings = new RingModeSettings( + RingModeSettings.RING_MODE_MUTE, true); + profile.setRingMode(ringSettings); + mProfileUuidList.add(profile.getUuid()); + mProfileManager.addProfile(profile); + mProfileManager.setActiveProfile(profile.getUuid()); + } + }, + new Test("Reset All") { + @Override + protected void run() { + // make sure we remove our own + for (UUID uuid: mProfileUuidList) { + Profile profile = mProfileManager.getProfile(uuid); + if (profile != null) { + mProfileManager.removeProfile(profile); + } + } + mProfileManager.resetAll(); + } + } + }; +} diff --git a/tests/src/org/lineageos/tests/profiles/unit/AirplaneModeSettingsTest.java b/tests/src/org/lineageos/tests/profiles/unit/AirplaneModeSettingsTest.java new file mode 100644 index 00000000..25a0fb1e --- /dev/null +++ b/tests/src/org/lineageos/tests/profiles/unit/AirplaneModeSettingsTest.java @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2016, The CyanogenMod Project + * + * Licensed 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.lineageos.tests.profiles.unit; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import lineageos.profiles.AirplaneModeSettings; + +public class AirplaneModeSettingsTest extends AndroidTestCase { + + @SmallTest + public void testConstructWholly() { + AirplaneModeSettings airplaneModeSettings = + new AirplaneModeSettings( + AirplaneModeSettings.BooleanState.STATE_ENABLED, true); + assertEquals(AirplaneModeSettings.BooleanState.STATE_ENABLED, airplaneModeSettings.getValue()); + assertEquals(true, airplaneModeSettings.isOverride()); + } + + @SmallTest + public void testVerifyOverride() { + AirplaneModeSettings airplaneModeSettings = + new AirplaneModeSettings( + AirplaneModeSettings.BooleanState.STATE_ENABLED, true); + airplaneModeSettings.setOverride(false); + assertEquals(false, airplaneModeSettings.isOverride()); + } + + @SmallTest + public void testVerifyValue() { + int expectedValue = AirplaneModeSettings.BooleanState.STATE_DISALED; + AirplaneModeSettings airplaneModeSettings = + new AirplaneModeSettings( + AirplaneModeSettings.BooleanState.STATE_ENABLED, true); + airplaneModeSettings.setValue(expectedValue); + assertEquals(expectedValue, airplaneModeSettings.getValue()); + } +} diff --git a/tests/src/org/lineageos/tests/profiles/unit/BrightnessSettingsTest.java b/tests/src/org/lineageos/tests/profiles/unit/BrightnessSettingsTest.java new file mode 100644 index 00000000..73814d88 --- /dev/null +++ b/tests/src/org/lineageos/tests/profiles/unit/BrightnessSettingsTest.java @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2016, The CyanogenMod Project + * + * Licensed 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.lineageos.tests.profiles.unit; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import lineageos.profiles.BrightnessSettings; + +public class BrightnessSettingsTest extends AndroidTestCase { + + @SmallTest + public void testConstructWholly() { + BrightnessSettings brightnessSettings = + new BrightnessSettings(0, true); + assertEquals(0, brightnessSettings.getValue()); + assertEquals(true, brightnessSettings.isOverride()); + } + + @SmallTest + public void testVerifyOverride() { + BrightnessSettings brightnessSettings = + new BrightnessSettings(0, true); + brightnessSettings.setOverride(false); + assertEquals(false, brightnessSettings.isOverride()); + } + + @SmallTest + public void testVerifyValue() { + int expectedValue = 30; + BrightnessSettings brightnessSettings = + new BrightnessSettings(0, true); + brightnessSettings.setValue(expectedValue); + assertEquals(expectedValue, brightnessSettings.getValue()); + } +} diff --git a/tests/src/org/lineageos/tests/profiles/unit/ConnectionSettingsTest.java b/tests/src/org/lineageos/tests/profiles/unit/ConnectionSettingsTest.java new file mode 100644 index 00000000..4564727e --- /dev/null +++ b/tests/src/org/lineageos/tests/profiles/unit/ConnectionSettingsTest.java @@ -0,0 +1,71 @@ +/** + * Copyright (c) 2016, The CyanogenMod Project + * + * Licensed 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.lineageos.tests.profiles.unit; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import lineageos.profiles.ConnectionSettings; + +public class ConnectionSettingsTest extends AndroidTestCase { + + @SmallTest + public void testConstructManually() { + ConnectionSettings connectionSettings = new ConnectionSettings( + ConnectionSettings.PROFILE_CONNECTION_GPS); + assertEquals(ConnectionSettings.PROFILE_CONNECTION_GPS, + connectionSettings.getConnectionId()); + assertNotNull(connectionSettings); + } + + @SmallTest + public void testConstructWholly() { + ConnectionSettings connectionSettings = + new ConnectionSettings(ConnectionSettings.PROFILE_CONNECTION_GPS, + ConnectionSettings.BooleanState.STATE_DISALED, true); + assertEquals(true, connectionSettings.isOverride()); + assertEquals(ConnectionSettings.BooleanState.STATE_DISALED, + connectionSettings.getValue()); + assertEquals(ConnectionSettings.PROFILE_CONNECTION_GPS, + connectionSettings.getConnectionId()); + assertNotNull(connectionSettings); + } + + @SmallTest + public void testVerifyOverride() { + ConnectionSettings connectionSettings = new ConnectionSettings( + ConnectionSettings.PROFILE_CONNECTION_GPS); + connectionSettings.setOverride(true); + assertEquals(true, connectionSettings.isOverride()); + } + + @SmallTest + public void testVerifySubId() { + int expectedSubId = 2; + ConnectionSettings connectionSettings = new ConnectionSettings( + ConnectionSettings.PROFILE_CONNECTION_2G3G4G); + connectionSettings.setSubId(expectedSubId); + assertEquals(expectedSubId, connectionSettings.getSubId()); + } + + @SmallTest + public void testVerifyValue() { + int expectedValue = ConnectionSettings.BooleanState.STATE_DISALED; + ConnectionSettings connectionSettings = new ConnectionSettings( + ConnectionSettings.PROFILE_CONNECTION_2G3G4G); + connectionSettings.setValue(expectedValue); + assertEquals(expectedValue, connectionSettings.getValue()); + } +} diff --git a/tests/src/org/lineageos/tests/profiles/unit/LockSettingsTest.java b/tests/src/org/lineageos/tests/profiles/unit/LockSettingsTest.java new file mode 100644 index 00000000..f3a47570 --- /dev/null +++ b/tests/src/org/lineageos/tests/profiles/unit/LockSettingsTest.java @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2016, The CyanogenMod Project + * + * Licensed 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.lineageos.tests.profiles.unit; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import lineageos.app.Profile; +import lineageos.profiles.LockSettings; + +public class LockSettingsTest extends AndroidTestCase { + + @SmallTest + public void testConstructWholly() { + LockSettings lockSettings = new LockSettings(Profile.LockMode.INSECURE); + assertEquals(Profile.LockMode.INSECURE, lockSettings.getValue()); + } + + @SmallTest + public void testVerifyValue() { + int expectedValue = Profile.LockMode.DEFAULT; + LockSettings lockSettings = new LockSettings(Profile.LockMode.INSECURE); + lockSettings.setValue(expectedValue); + assertEquals(expectedValue, lockSettings.getValue()); + } +} diff --git a/tests/src/org/lineageos/tests/profiles/unit/ProfileManagerTest.java b/tests/src/org/lineageos/tests/profiles/unit/ProfileManagerTest.java new file mode 100644 index 00000000..c507e80b --- /dev/null +++ b/tests/src/org/lineageos/tests/profiles/unit/ProfileManagerTest.java @@ -0,0 +1,225 @@ +/** + * Copyright (c) 2015, The CyanogenMod Project + * + * Licensed 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.lineageos.tests.profiles.unit; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import android.util.Log; +import lineageos.app.LineageContextConstants; +import lineageos.app.Profile; +import lineageos.app.ProfileManager; +import lineageos.app.IProfileManager; +import lineageos.providers.LineageSettings; + +import java.util.Arrays; +import java.util.UUID; +import java.util.concurrent.CountDownLatch; + +public class ProfileManagerTest extends AndroidTestCase { + private static final String TAG = ProfileManagerTest.class.getSimpleName(); + private static final int COUNTDOWN = 1; + private ProfileManager mProfileManager; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mProfileManager = ProfileManager.getInstance(mContext); + // Only run this if we support profiles service + org.junit.Assume.assumeTrue(mContext.getPackageManager().hasSystemFeature( + LineageContextConstants.Features.PROFILES)); + } + + @SmallTest + public void testManagerExists() { + assertNotNull(mProfileManager); + } + + @SmallTest + public void testManagerServiceIsAvailable() { + IProfileManager iProfileManager = mProfileManager.getService(); + assertNotNull(iProfileManager); + } + + @SmallTest + public void testManagerProfileIsEnabled() { + // first enable profiles + final String enabledValue = "1"; + assertTrue(LineageSettings.System.putString(getContext().getContentResolver(), + LineageSettings.System.SYSTEM_PROFILES_ENABLED, enabledValue)); + + // check that we successfully enabled them via system setting + assertEquals(enabledValue, LineageSettings.System.getString(getContext().getContentResolver(), + LineageSettings.System.SYSTEM_PROFILES_ENABLED)); + + // check that profile manger returns true + assertTrue(mProfileManager.isProfilesEnabled()); + + // now disable the setting + final String disabledValue = "0"; + assertTrue(LineageSettings.System.putString(getContext().getContentResolver(), + LineageSettings.System.SYSTEM_PROFILES_ENABLED, disabledValue)); + + // check that we successfully disable them via system setting + assertEquals(disabledValue, LineageSettings.System.getString(getContext().getContentResolver(), + LineageSettings.System.SYSTEM_PROFILES_ENABLED)); + + assertFalse(mProfileManager.isProfilesEnabled()); + } + + private void ensureProfilesEnabled() { + final String enabledValue = "1"; + assertTrue(LineageSettings.System.putString(getContext().getContentResolver(), + LineageSettings.System.SYSTEM_PROFILES_ENABLED, enabledValue)); + } + + @SmallTest + public void testGetActiveProfile() { + ensureProfilesEnabled(); + final CountDownLatch signal = new CountDownLatch(COUNTDOWN); + final Profile expectedActiveProfile = new Profile("TEST ACTIVE PROFILE"); + mProfileManager.addProfile(expectedActiveProfile); + + BroadcastReceiver intentReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + signal.countDown(); + } + }; + + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(ProfileManager.INTENT_ACTION_PROFILE_SELECTED); + intentFilter.addAction(ProfileManager.INTENT_ACTION_PROFILE_UPDATED); + + mContext.registerReceiver(intentReceiver, intentFilter); + + mProfileManager.setActiveProfile(expectedActiveProfile.getName()); + + // Lock + try { + signal.await(); + } catch (InterruptedException e) { + throw new AssertionError(e); + } + + assertEquals(expectedActiveProfile.getName(), + mProfileManager.getActiveProfile().getName()); + mProfileManager.resetAll(); + + mContext.unregisterReceiver(intentReceiver); + } + + @SmallTest + public void testGetProfileNames() { + ensureProfilesEnabled(); + String[] expectedProfileNames = new String[5]; + // These defaults are pulled from the default xml in the lineage platform resource package + Profile expectedProfile1 = mProfileManager.getProfile( + UUID.fromString("6a181391-12ef-4f43-a701-32b11ed69449")); + Profile expectedProfile2 = mProfileManager.getProfile( + UUID.fromString("0230226d-0d05-494a-a9bd-d222a1117655")); + Profile expectedProfile3 = mProfileManager.getProfile( + UUID.fromString("e4e77d03-82ce-4417-9257-7d6c9ffb8fd1")); + + // Add extras + Profile expectedProfile4 = new Profile("PROFILE 1"); + Profile expectedProfile5 = new Profile("PROFILE 2"); + + expectedProfileNames[0] = expectedProfile1.getName(); + expectedProfileNames[1] = expectedProfile2.getName(); + expectedProfileNames[2] = expectedProfile3.getName(); + expectedProfileNames[3] = expectedProfile4.getName(); + expectedProfileNames[4] = expectedProfile5.getName(); + + mProfileManager.addProfile(expectedProfile1); + mProfileManager.addProfile(expectedProfile2); + + String[] actualProfileNames = mProfileManager.getProfileNames(); + for (int i = 0; i < actualProfileNames.length; i++) { + assertEquals(expectedProfileNames[i], actualProfileNames[i]); + } + mProfileManager.resetAll(); + } + + @SmallTest + public void testGetProfiles() { + ensureProfilesEnabled(); + Profile[] expectedProfiles = new Profile[5]; + // These defaults are pulled from the default xml in the lineage platform resource package + Profile expectedProfile1 = mProfileManager.getProfile( + UUID.fromString("6a181391-12ef-4f43-a701-32b11ed69449")); + Profile expectedProfile2 = mProfileManager.getProfile( + UUID.fromString("0230226d-0d05-494a-a9bd-d222a1117655")); + Profile expectedProfile3 = mProfileManager.getProfile( + UUID.fromString("e4e77d03-82ce-4417-9257-7d6c9ffb8fd1")); + + // Add extras + Profile expectedProfile4 = new Profile("PROFILE 1"); + Profile expectedProfile5 = new Profile("PROFILE 2"); + + expectedProfiles[0] = expectedProfile1; + expectedProfiles[1] = expectedProfile2; + expectedProfiles[2] = expectedProfile3; + expectedProfiles[3] = expectedProfile4; + expectedProfiles[4] = expectedProfile5; + + // The actual results come back in alphabetical order, :/ + Arrays.sort(expectedProfiles); + + mProfileManager.addProfile(expectedProfile4); + mProfileManager.addProfile(expectedProfile5); + + Profile[] actualProfiles = mProfileManager.getProfiles(); + for (int i = 0; i < actualProfiles.length; i++) { + assertEquals(expectedProfiles[i].getName(), actualProfiles[i].getName()); + } + mProfileManager.resetAll(); + } + + @SmallTest + public void testProfileExists() { + ensureProfilesEnabled(); + assertTrue(mProfileManager.profileExists( + UUID.fromString("6a181391-12ef-4f43-a701-32b11ed69449"))); + assertTrue(mProfileManager.profileExists( + UUID.fromString("0230226d-0d05-494a-a9bd-d222a1117655"))); + assertTrue(mProfileManager.profileExists( + UUID.fromString("e4e77d03-82ce-4417-9257-7d6c9ffb8fd1"))); + String expectedProfileName = "PROFILE 1"; + Profile expectedProfile = new Profile(expectedProfileName); + mProfileManager.addProfile(expectedProfile); + assertTrue(mProfileManager.profileExists(expectedProfileName)); + mProfileManager.resetAll(); + } + + @SmallTest + public void testUpdateProfile() { + ensureProfilesEnabled(); + String originalProfileName = "PROFILE 1"; + String expectedProfileName = "PROFILE 2"; + Profile expectedProfile = new Profile(originalProfileName); + mProfileManager.addProfile(expectedProfile); + expectedProfile.setName(expectedProfileName); + mProfileManager.updateProfile(expectedProfile); + assertNotSame(originalProfileName, expectedProfile.getName()); + assertEquals(expectedProfileName, expectedProfile.getName()); + mProfileManager.resetAll(); + } +} diff --git a/tests/src/org/lineageos/tests/profiles/unit/ProfileTest.java b/tests/src/org/lineageos/tests/profiles/unit/ProfileTest.java new file mode 100644 index 00000000..899b0066 --- /dev/null +++ b/tests/src/org/lineageos/tests/profiles/unit/ProfileTest.java @@ -0,0 +1,539 @@ +/** + * Copyright (c) 2015, The CyanogenMod Project + * + * Licensed 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.lineageos.tests.profiles.unit; + +import android.media.AudioManager; +import android.os.Parcel; +import android.test.AndroidTestCase; + +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.SmallTest; + +import lineageos.app.LineageContextConstants; +import lineageos.app.Profile; +import lineageos.profiles.AirplaneModeSettings; +import lineageos.profiles.BrightnessSettings; +import lineageos.profiles.ConnectionSettings; +import lineageos.profiles.LockSettings; +import lineageos.profiles.RingModeSettings; +import lineageos.profiles.StreamSettings; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; + +public class ProfileTest extends AndroidTestCase { + + @Override + protected void setUp() throws Exception { + super.setUp(); + // Only run this if we support profiles service + org.junit.Assume.assumeTrue(mContext.getPackageManager().hasSystemFeature( + LineageContextConstants.Features.PROFILES)); + } + + @MediumTest + public void testProfileConnectionSettingsUnravelFromParcel() { + Profile profile = new Profile("Connection Profile"); + ConnectionSettings expectedConnectionSettings = + new ConnectionSettings(ConnectionSettings.PROFILE_CONNECTION_GPS, + ConnectionSettings.BooleanState.STATE_DISALED, true); + profile.setConnectionSettings(expectedConnectionSettings); + + // Write to parcel + Parcel parcel = Parcel.obtain(); + profile.writeToParcel(parcel, 0); + + // Rewind + parcel.setDataPosition(0); + + // Verify data when unraveling + Profile fromParcel = Profile.CREATOR.createFromParcel(parcel); + + assertNotNull(fromParcel); + ConnectionSettings actualConnectionSettings = fromParcel.getSettingsForConnection( + expectedConnectionSettings.getConnectionId()); + + assertEquals(expectedConnectionSettings.getConnectionId(), + actualConnectionSettings.getConnectionId()); + assertEquals(expectedConnectionSettings.getValue(), + actualConnectionSettings.getValue()); + assertEquals(expectedConnectionSettings.isDirty(), + actualConnectionSettings.isDirty()); + assertEquals(expectedConnectionSettings.isOverride(), + actualConnectionSettings.isOverride()); + } + + @MediumTest + public void testProfileAirplaneModeSettingsUnravelFromParcel() { + Profile profile = new Profile("AirplaneMode Profile"); + AirplaneModeSettings expectedAirplaneModeSettings = + new AirplaneModeSettings(AirplaneModeSettings.BooleanState.STATE_ENABLED, true); + profile.setAirplaneMode(expectedAirplaneModeSettings); + + // Write to parcel + Parcel parcel = Parcel.obtain(); + profile.writeToParcel(parcel, 0); + + // Rewind + parcel.setDataPosition(0); + + // Verify data when unraveling + Profile fromParcel = Profile.CREATOR.createFromParcel(parcel); + + assertNotNull(fromParcel); + AirplaneModeSettings actualAirplaneModeSettings = fromParcel.getAirplaneMode(); + + assertEquals(expectedAirplaneModeSettings.getValue(), + actualAirplaneModeSettings.getValue()); + assertEquals(expectedAirplaneModeSettings.isDirty(), + actualAirplaneModeSettings.isDirty()); + assertEquals(expectedAirplaneModeSettings.isOverride(), + expectedAirplaneModeSettings.isOverride()); + } + + @MediumTest + public void testProfileBrightnessSettingsUnravelFromParcel() { + Profile profile = new Profile("Brightness Profile"); + BrightnessSettings expectedBrightnessSettings = new BrightnessSettings(0, true); + profile.setBrightness(expectedBrightnessSettings); + + // Write to parcel + Parcel parcel = Parcel.obtain(); + profile.writeToParcel(parcel, 0); + + // Rewind + parcel.setDataPosition(0); + + // Verify data when unraveling + Profile fromParcel = Profile.CREATOR.createFromParcel(parcel); + + assertNotNull(fromParcel); + BrightnessSettings actualBrightnessSettings = fromParcel.getBrightness(); + + assertEquals(expectedBrightnessSettings.getValue(), actualBrightnessSettings.getValue()); + assertEquals(expectedBrightnessSettings.isOverride(), + actualBrightnessSettings.isOverride()); + assertEquals(expectedBrightnessSettings.isDirty(), actualBrightnessSettings.isDirty()); + } + + @MediumTest + public void testProfileRingmodeSettingsUnravelFromParcel() { + Profile profile = new Profile("Ringmode Profile"); + RingModeSettings expectedRingModeSettings = + new RingModeSettings(RingModeSettings.RING_MODE_MUTE, true); + profile.setRingMode(expectedRingModeSettings); + + // Write to parcel + Parcel parcel = Parcel.obtain(); + profile.writeToParcel(parcel, 0); + + // Rewind + parcel.setDataPosition(0); + + // Verify data when unraveling + Profile fromParcel = Profile.CREATOR.createFromParcel(parcel); + + RingModeSettings actualRingModeSettings = fromParcel.getRingMode(); + + assertNotNull(fromParcel); + assertEquals(expectedRingModeSettings.getValue(), actualRingModeSettings.getValue()); + assertEquals(expectedRingModeSettings.isDirty(), actualRingModeSettings.isDirty()); + assertEquals(expectedRingModeSettings.isOverride(), actualRingModeSettings.isOverride()); + } + + @MediumTest + public void testProfileStreamSettingsUnravelFromParcel() { + Profile profile = new Profile("Stream Profile"); + StreamSettings expectedStreamSettings = + new StreamSettings(AudioManager.STREAM_RING, 0, true); + profile.setStreamSettings(expectedStreamSettings); + + // Write to parcel + Parcel parcel = Parcel.obtain(); + profile.writeToParcel(parcel, 0); + + // Rewind + parcel.setDataPosition(0); + + // Verify data when unraveling + Profile fromParcel = Profile.CREATOR.createFromParcel(parcel); + + StreamSettings actualStreamSettings = fromParcel.getSettingsForStream( + expectedStreamSettings.getStreamId()); + + assertNotNull(fromParcel); + assertEquals(expectedStreamSettings.getValue(), actualStreamSettings.getValue()); + assertEquals(expectedStreamSettings.isOverride(), actualStreamSettings.isOverride()); + assertEquals(expectedStreamSettings.isDirty(), actualStreamSettings.isDirty()); + } + + @MediumTest + public void testProfileLockSettingsUnravelFromParcel() { + Profile profile = new Profile("Lock Profile"); + LockSettings expectedLockSettings = new LockSettings(Profile.LockMode.INSECURE); + profile.setScreenLockMode(expectedLockSettings); + + // Write to parcel + Parcel parcel = Parcel.obtain(); + profile.writeToParcel(parcel, 0); + + // Rewind + parcel.setDataPosition(0); + + // Verify data when unraveling + Profile fromParcel = Profile.CREATOR.createFromParcel(parcel); + + LockSettings actualLockSettings = fromParcel.getScreenLockMode(); + + assertNotNull(fromParcel); + assertEquals(expectedLockSettings.getValue(), actualLockSettings.getValue()); + assertEquals(expectedLockSettings.isDirty(), actualLockSettings.isDirty()); + } + + @MediumTest + public void testProfileUnravelFromParcel() { + Profile profile = new Profile("Single Profile"); + profile.setProfileType(Profile.Type.TOGGLE); + profile.setDozeMode(Profile.DozeMode.ENABLE); + profile.setStatusBarIndicator(true); + + // Write to parcel + Parcel parcel = Parcel.obtain(); + profile.writeToParcel(parcel, 0); + + // Rewind + parcel.setDataPosition(0); + + // Verify data when unraveling + Profile fromParcel = Profile.CREATOR.createFromParcel(parcel); + + assertNotNull(fromParcel); + assertEquals(profile.getName(), fromParcel.getName()); + assertEquals(profile.getProfileType(), fromParcel.getProfileType()); + assertEquals(profile.getDozeMode(), fromParcel.getDozeMode()); + assertEquals(profile.getStatusBarIndicator(), fromParcel.getStatusBarIndicator()); + } + + private static final int EXPECTED_PROFILE_TRIGGER_TYPE = Profile.TriggerType.WIFI; + private static final String EXPECTED_PROFILE_TRIGGER_ID = "1337"; + private static final int EXPECTED_PROFILE_TRIGGER_STATE = Profile.TriggerState.ON_CONNECT; + private static final String EXPECTED_PROFILE_TRIGGER_NAME = "ON_CONNECT_WIFI_TRIGGER"; + private Profile.ProfileTrigger createSampleProfileTrigger() { + return new Profile.ProfileTrigger(EXPECTED_PROFILE_TRIGGER_TYPE, + EXPECTED_PROFILE_TRIGGER_ID, EXPECTED_PROFILE_TRIGGER_STATE, + EXPECTED_PROFILE_TRIGGER_NAME); + } + + @SmallTest + public void testProfileTriggerId() { + Profile.ProfileTrigger profileTrigger = createSampleProfileTrigger(); + assertEquals(EXPECTED_PROFILE_TRIGGER_ID, profileTrigger.getId()); + } + + @SmallTest + public void testProfileTriggerName() { + Profile.ProfileTrigger profileTrigger = createSampleProfileTrigger(); + assertEquals(EXPECTED_PROFILE_TRIGGER_NAME, profileTrigger.getName()); + } + + @SmallTest + public void testProfileTriggerState() { + Profile.ProfileTrigger profileTrigger = createSampleProfileTrigger(); + assertEquals(EXPECTED_PROFILE_TRIGGER_STATE, profileTrigger.getState()); + } + + @SmallTest + public void testProfileTriggerType() { + Profile.ProfileTrigger profileTrigger = createSampleProfileTrigger(); + assertEquals(EXPECTED_PROFILE_TRIGGER_STATE, profileTrigger.getType()); + } + + @SmallTest + public void testProfileConstructor() { + String expectedName = "PROFILE_NAME"; + Profile profile = new Profile(expectedName); + assertEquals(expectedName, profile.getName()); + } + + @SmallTest + public void testProfileAddSecondaryUuid() { + UUID[] expectedUUIDs = new UUID[2]; + UUID expectedUUID1 = UUID.randomUUID(); + UUID expectedUUID2 = UUID.randomUUID(); + expectedUUIDs[0] = expectedUUID1; + expectedUUIDs[1] = expectedUUID2; + + Profile profile = new Profile("Single Profile"); + profile.addSecondaryUuid(expectedUUID1); + profile.addSecondaryUuid(expectedUUID2); + + UUID[] actualUUIDs = profile.getSecondaryUuids(); + for (int i = 0; i < actualUUIDs.length; i++) { + assertEquals(actualUUIDs[i], expectedUUIDs[i]); + } + + profile.setSecondaryUuids(Arrays.asList(expectedUUIDs)); + for (int i = 0; i < actualUUIDs.length; i++) { + assertEquals(actualUUIDs[i], expectedUUIDs[i]); + } + } + + @SmallTest + public void testProfileGetAirplaneMode() { + Profile profile = new Profile("AirplaneMode Profile"); + AirplaneModeSettings expectedAirplaneModeSettings = + new AirplaneModeSettings(AirplaneModeSettings.BooleanState.STATE_ENABLED, true); + profile.setAirplaneMode(expectedAirplaneModeSettings); + + AirplaneModeSettings actualAirplaneModeSettings = profile.getAirplaneMode(); + assertEquals(expectedAirplaneModeSettings.getValue(), + actualAirplaneModeSettings.getValue()); + assertEquals(expectedAirplaneModeSettings.isOverride(), + actualAirplaneModeSettings.isOverride()); + } + + @SmallTest + public void testProfileGetBrightness() { + Profile profile = new Profile("Brightness Profile"); + BrightnessSettings expectedBrightnessSettings = new BrightnessSettings(0, true); + profile.setBrightness(expectedBrightnessSettings); + + BrightnessSettings actualBrightnessSettings = profile.getBrightness(); + assertEquals(expectedBrightnessSettings.getValue(), actualBrightnessSettings.getValue()); + assertEquals(expectedBrightnessSettings.isOverride(), actualBrightnessSettings.isOverride()); + } + + @SmallTest + public void testProfileGetConnectionSettingsWithSubId() { + int targetSubId = 0; + Profile profile = new Profile("Connection Sub Id Profile"); + ConnectionSettings expectedConnectionSettings = new ConnectionSettings( + ConnectionSettings.PROFILE_CONNECTION_2G3G4G, + ConnectionSettings.BooleanState.STATE_ENABLED, true); + expectedConnectionSettings.setSubId(targetSubId); + profile.setConnectionSettings(expectedConnectionSettings); + + ConnectionSettings actualConnectionSettings = + profile.getConnectionSettingWithSubId(targetSubId); + assertEquals(expectedConnectionSettings.getConnectionId(), + actualConnectionSettings.getConnectionId()); + assertEquals(expectedConnectionSettings.getValue(), actualConnectionSettings.getValue()); + assertEquals(expectedConnectionSettings.isOverride(), + actualConnectionSettings.isOverride()); + } + + @SmallTest + public void testProfileGetConnectionSettings() { + Profile profile = new Profile("Connection Profile"); + + ConnectionSettings expectedConnectionSettings1 = new ConnectionSettings( + ConnectionSettings.PROFILE_CONNECTION_2G3G4G, + ConnectionSettings.BooleanState.STATE_ENABLED, true); + profile.setConnectionSettings(expectedConnectionSettings1); + ConnectionSettings expectedConnectionSettings2 = new ConnectionSettings( + ConnectionSettings.PROFILE_CONNECTION_BLUETOOTH, + ConnectionSettings.BooleanState.STATE_DISALED, false); + profile.setConnectionSettings(expectedConnectionSettings2); + + List<ConnectionSettings> expectedConnectionSettings = new ArrayList<>(); + // inverted because the backing structure does it this way :/ + expectedConnectionSettings.add(expectedConnectionSettings2); + expectedConnectionSettings.add(expectedConnectionSettings1); + + List<ConnectionSettings> actualConnectionSettings = new ArrayList<>( + profile.getConnectionSettings()); + for (int i = 0; i < actualConnectionSettings.size(); i++) { + ConnectionSettings expectedConnectionSetting = expectedConnectionSettings.get(i); + ConnectionSettings actualConnectionSetting = actualConnectionSettings.get(i); + assertEquals(expectedConnectionSetting.getConnectionId(), + actualConnectionSetting.getConnectionId()); + assertEquals(expectedConnectionSetting.getValue(), actualConnectionSetting.getValue()); + assertEquals(expectedConnectionSetting.isOverride(), + actualConnectionSetting.isOverride()); + } + } + + @SmallTest + public void testProfileGetDozeMode() { + int expectedDozeMode = Profile.DozeMode.ENABLE; + Profile profile = new Profile("Doze Mode Profile"); + profile.setDozeMode(expectedDozeMode); + assertEquals(expectedDozeMode, profile.getDozeMode()); + } + + @SmallTest + public void testProfileGetExpandedDesktopMode() { + int expectedExpandedDesktopMode = Profile.ExpandedDesktopMode.ENABLE; + Profile profile = new Profile("Desktop Mode Profile"); + profile.setExpandedDesktopMode(expectedExpandedDesktopMode); + assertEquals(expectedExpandedDesktopMode, profile.getExpandedDesktopMode()); + } + + @SmallTest + public void testProfileGetNotificationLightMode() { + int expectedNotificationLightMode = Profile.NotificationLightMode.ENABLE; + Profile profile = new Profile("Notification Light Mode Profile"); + profile.setNotificationLightMode(expectedNotificationLightMode); + assertEquals(expectedNotificationLightMode, profile.getNotificationLightMode()); + } + + @SmallTest + public void testProfileGetProfileType() { + int expectedProfileType = Profile.Type.CONDITIONAL; + Profile profile = new Profile("Profile Type Profile"); + profile.setProfileType(expectedProfileType); + assertEquals(expectedProfileType, profile.getProfileType()); + } + + @SmallTest + public void testProfileGetRingMode() { + Profile profile = new Profile("Ringmode Profile"); + RingModeSettings expectedRingModeSettings = + new RingModeSettings(RingModeSettings.RING_MODE_MUTE, true); + profile.setRingMode(expectedRingModeSettings); + + RingModeSettings actualRingModeSettings = profile.getRingMode(); + assertEquals(expectedRingModeSettings.getValue(), actualRingModeSettings.getValue()); + assertEquals(expectedRingModeSettings.isDirty(), actualRingModeSettings.isDirty()); + assertEquals(expectedRingModeSettings.isOverride(), actualRingModeSettings.isOverride()); + } + + @SmallTest + public void testProfileGetLockScreenMode() { + Profile profile = new Profile("Lock Profile"); + LockSettings expectedLockSettings = new LockSettings(Profile.LockMode.INSECURE); + profile.setScreenLockMode(expectedLockSettings); + + LockSettings actualLockSettings = profile.getScreenLockMode(); + assertEquals(expectedLockSettings.getValue(), actualLockSettings.getValue()); + assertEquals(expectedLockSettings.isDirty(), actualLockSettings.isDirty()); + } + + @SmallTest + public void testProfileGetSettingForConnection() { + Profile profile = new Profile("Connection Profile"); + ConnectionSettings expectedConnectionSettings = new ConnectionSettings( + ConnectionSettings.PROFILE_CONNECTION_2G3G4G, + ConnectionSettings.BooleanState.STATE_ENABLED, true); + profile.setConnectionSettings(expectedConnectionSettings); + + ConnectionSettings actualConnectionSettings = + profile.getSettingsForConnection(ConnectionSettings.PROFILE_CONNECTION_2G3G4G); + assertEquals(expectedConnectionSettings.getConnectionId(), + actualConnectionSettings.getConnectionId()); + assertEquals(expectedConnectionSettings.getValue(), actualConnectionSettings.getValue()); + assertEquals(expectedConnectionSettings.isOverride(), + actualConnectionSettings.isOverride()); + } + + @SmallTest + public void testProfileGetSettingForStream() { + Profile profile = new Profile("Stream Profile"); + StreamSettings expectedStreamSettings = + new StreamSettings(AudioManager.STREAM_RING, 0, true); + profile.setStreamSettings(expectedStreamSettings); + + StreamSettings actualStreamSettings = profile.getSettingsForStream( + expectedStreamSettings.getStreamId()); + + assertEquals(expectedStreamSettings.getValue(), actualStreamSettings.getValue()); + assertEquals(expectedStreamSettings.isOverride(), actualStreamSettings.isOverride()); + assertEquals(expectedStreamSettings.isDirty(), actualStreamSettings.isDirty()); + } + + @SmallTest + public void testProfileGetStreamSettings() { + Profile profile = new Profile("Stream Profile"); + StreamSettings expectedStreamSettings1 = + new StreamSettings(AudioManager.STREAM_RING, 0, true); + profile.setStreamSettings(expectedStreamSettings1); + StreamSettings expectedStreamSettings2 = + new StreamSettings(AudioManager.STREAM_RING, 0, true); + profile.setStreamSettings(expectedStreamSettings2); + + List<StreamSettings> expectedStreamSettings = new ArrayList<>(); + expectedStreamSettings.add(expectedStreamSettings1); + expectedStreamSettings.add(expectedStreamSettings2); + + List<StreamSettings> actualStreamSettings = new ArrayList<>( + profile.getStreamSettings()); + + for (int i = 0; i < actualStreamSettings.size(); i++) { + StreamSettings expectedStreamSetting = actualStreamSettings.get(i); + StreamSettings actualStreamSetting = actualStreamSettings.get(i); + assertEquals(expectedStreamSetting.getStreamId(), + actualStreamSetting.getStreamId()); + assertEquals(expectedStreamSetting.getValue(), actualStreamSetting.getValue()); + assertEquals(expectedStreamSetting.isOverride(), + actualStreamSetting.isOverride()); + } + } + + @SmallTest + public void testProfileGetTriggerState() { + Profile profile = new Profile("ProfileTrigger Profile"); + Profile.ProfileTrigger profileTrigger = createSampleProfileTrigger(); + profile.setTrigger(profileTrigger); + assertEquals(EXPECTED_PROFILE_TRIGGER_STATE, + profile.getTriggerState(EXPECTED_PROFILE_TRIGGER_TYPE, + EXPECTED_PROFILE_TRIGGER_ID)); + } + + @SmallTest + public void testProfileGetTriggersFromType() { + Profile profile = new Profile("ProfileTrigger Profile"); + Profile.ProfileTrigger profileTrigger1 = createSampleProfileTrigger(); + Profile.ProfileTrigger profileTrigger2 = createSampleProfileTrigger(); + profile.setTrigger(profileTrigger1); + profile.setTrigger(profileTrigger2); + + List<Profile.ProfileTrigger> expectedProfileTriggers = new ArrayList<>(); + expectedProfileTriggers.add(profileTrigger1); + expectedProfileTriggers.add(profileTrigger2); + + List<Profile.ProfileTrigger> actualProfileTriggers = new ArrayList<>( + profile.getTriggersFromType(EXPECTED_PROFILE_TRIGGER_TYPE)); + + for (int i = 0; i < actualProfileTriggers.size(); i++) { + Profile.ProfileTrigger expectedProfileTrigger = expectedProfileTriggers.get(i); + Profile.ProfileTrigger actualProfileTrigger = expectedProfileTriggers.get(i); + assertEquals(expectedProfileTrigger.getId(), actualProfileTrigger.getId()); + assertEquals(expectedProfileTrigger.getName(), actualProfileTrigger.getName()); + assertEquals(expectedProfileTrigger.getState(), actualProfileTrigger.getState()); + assertEquals(expectedProfileTrigger.getType(), actualProfileTrigger.getType()); + } + } + + @SmallTest + public void testProfileIsConditionalType() { + Profile profile = new Profile("Mutable Profile"); + profile.setProfileType(Profile.Type.TOGGLE); + assertFalse(profile.isConditionalType()); + profile.setProfileType(Profile.Type.CONDITIONAL); + assertTrue(profile.isConditionalType()); + } + + @SmallTest + public void testProfileSetName() { + String expectedProfileName = "MUTABLE Profile"; + Profile profile = new Profile("Mutable Profile"); + profile.setName(expectedProfileName); + assertEquals(expectedProfileName, profile.getName()); + } +} diff --git a/tests/src/org/lineageos/tests/profiles/unit/RingModeSettingsTest.java b/tests/src/org/lineageos/tests/profiles/unit/RingModeSettingsTest.java new file mode 100644 index 00000000..4c1bfd6e --- /dev/null +++ b/tests/src/org/lineageos/tests/profiles/unit/RingModeSettingsTest.java @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2016, The CyanogenMod Project + * + * Licensed 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.lineageos.tests.profiles.unit; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import lineageos.profiles.RingModeSettings; + +public class RingModeSettingsTest extends AndroidTestCase { + + @SmallTest + public void testConstructWholly() { + RingModeSettings ringSettings = new RingModeSettings( + RingModeSettings.RING_MODE_MUTE, true); + assertEquals(RingModeSettings.RING_MODE_MUTE, ringSettings.getValue()); + assertEquals(true, ringSettings.isOverride()); + } + + @SmallTest + public void testVerifyOverride() { + RingModeSettings ringSettings = new RingModeSettings( + RingModeSettings.RING_MODE_MUTE, true); + ringSettings.setOverride(false); + assertEquals(false, ringSettings.isOverride()); + } + + @SmallTest + public void testVerifyValue() { + String expectedValue = RingModeSettings.RING_MODE_NORMAL; + RingModeSettings ringSettings = new RingModeSettings( + RingModeSettings.RING_MODE_MUTE, true); + ringSettings.setValue(expectedValue); + assertEquals(expectedValue, ringSettings.getValue()); + } +} diff --git a/tests/src/org/lineageos/tests/profiles/unit/StreamSettingsTest.java b/tests/src/org/lineageos/tests/profiles/unit/StreamSettingsTest.java new file mode 100644 index 00000000..783d293e --- /dev/null +++ b/tests/src/org/lineageos/tests/profiles/unit/StreamSettingsTest.java @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2016, The CyanogenMod Project + * + * Licensed 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.lineageos.tests.profiles.unit; + +import android.media.AudioManager; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import lineageos.profiles.StreamSettings; + +public class StreamSettingsTest extends AndroidTestCase { + + @SmallTest + public void testConstructManually() { + StreamSettings streamSettings = + new StreamSettings(AudioManager.STREAM_RING); + assertEquals(AudioManager.STREAM_RING, streamSettings.getStreamId()); + } + + @SmallTest + public void testConstructWholly() { + StreamSettings streamSettings = + new StreamSettings(AudioManager.STREAM_RING, 0, true); + assertEquals(AudioManager.STREAM_RING, streamSettings.getStreamId()); + assertEquals(0, streamSettings.getValue()); + assertEquals(true, streamSettings.isOverride()); + } + + @SmallTest + public void testVerifyOverride() { + StreamSettings streamSettings = + new StreamSettings(AudioManager.STREAM_RING); + streamSettings.setOverride(true); + assertEquals(true, streamSettings.isOverride()); + } + + @SmallTest + public void testVerifyValue() { + int expectedValue = AudioManager.STREAM_ALARM; + StreamSettings streamSettings = + new StreamSettings(AudioManager.STREAM_RING); + streamSettings.setValue(expectedValue); + assertEquals(expectedValue, streamSettings.getValue()); + } +} diff --git a/tests/src/org/lineageos/tests/providers/LineageSettingsTest.java b/tests/src/org/lineageos/tests/providers/LineageSettingsTest.java new file mode 100644 index 00000000..d6f61e80 --- /dev/null +++ b/tests/src/org/lineageos/tests/providers/LineageSettingsTest.java @@ -0,0 +1,177 @@ +/** + * Copyright (c) 2015, The CyanogenMod Project + * + * Licensed 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.lineageos.tests.providers; + +import android.content.ContentResolver; +import android.database.ContentObserver; +import android.net.Uri; +import android.os.Handler; +import android.os.UserHandle; +import android.provider.Settings; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.MediumTest; +import lineageos.providers.LineageSettings; + +public class LineageSettingsTest extends AndroidTestCase{ + private ContentResolver mContentResolver; + private LineageSettingsTestObserver mTestObserver; + + private static boolean sIsOnChangedCalled = false; + private static Uri sExpectedUriChange = null; + + @Override + public void setUp() { + mContentResolver = getContext().getContentResolver(); + mTestObserver = new LineageSettingsTestObserver(null); + } + + @Override + public void tearDown() { + mContentResolver.unregisterContentObserver(mTestObserver); + } + + @MediumTest + public void testPutAndGetSystemString() { + final String key = LineageSettings.System.__MAGICAL_TEST_PASSING_ENABLER; + + // put + final String expectedValue = "1"; + boolean isPutSuccessful = LineageSettings.System.putString(mContentResolver, key, expectedValue); + assertTrue(isPutSuccessful); + + // get + String actualValue = LineageSettings.System.getString(mContentResolver, key); + assertEquals(expectedValue, actualValue); + + // setup observer + sIsOnChangedCalled = false; + sExpectedUriChange = LineageSettings.System.getUriFor(key); + mContentResolver.registerContentObserver(sExpectedUriChange, false, mTestObserver, + UserHandle.USER_ALL); + + // replace + final String expectedReplaceValue = "0"; + isPutSuccessful = LineageSettings.System.putString(mContentResolver, key, expectedReplaceValue); + assertTrue(isPutSuccessful); + + // get + actualValue = LineageSettings.System.getString(mContentResolver, key); + assertEquals(expectedReplaceValue, actualValue); + + // delete to clean up + int rowsAffected = mContentResolver.delete(LineageSettings.System.CONTENT_URI, + Settings.NameValueTable.NAME + " = ?", new String[]{ key }); + assertEquals(1, rowsAffected); + + if (!sIsOnChangedCalled) { + fail("On change was never called or was called with the wrong uri"); + } + } + + @MediumTest + public void testPutAndGetSecureString() { + /* TODO: FIXME + final String key = LineageSettings.Secure.__MAGICAL_TEST_PASSING_ENABLER; + + // put + final String expectedValue = "0"; + boolean isPutSuccessful = LineageSettings.Secure.putString(mContentResolver, key, expectedValue); + assertTrue(isPutSuccessful); + + // get + String actualValue = LineageSettings.Secure.getString(mContentResolver, key); + assertEquals(expectedValue, actualValue); + + // setup observer + sIsOnChangedCalled = false; + sExpectedUriChange = LineageSettings.Secure.getUriFor(key); + mContentResolver.registerContentObserver(sExpectedUriChange, false, mTestObserver, + UserHandle.USER_ALL); + + // replace + final String expectedReplaceValue = "1"; + isPutSuccessful = LineageSettings.Secure.putString(mContentResolver, key, expectedReplaceValue); + assertTrue(isPutSuccessful); + + // get + actualValue = LineageSettings.Secure.getString(mContentResolver, key); + assertEquals(expectedReplaceValue, actualValue); + + // delete to clean up + int rowsAffected = mContentResolver.delete(LineageSettings.Secure.CONTENT_URI, + Settings.NameValueTable.NAME + " = ?", new String[]{ key }); + assertEquals(1, rowsAffected); + + if (!sIsOnChangedCalled) { + fail("On change was never called or was called with the wrong uri"); + } */ + } + + @MediumTest + public void testPutAndGetGlobalString() { + final String key = "key"; + + // put + final String expectedValue = "globalTestValue1"; + boolean isPutSuccessful = LineageSettings.Global.putString(mContentResolver, key, expectedValue); + assertTrue(isPutSuccessful); + + // get + String actualValue = LineageSettings.Global.getString(mContentResolver, key); + assertEquals(expectedValue, actualValue); + + // setup observer + sIsOnChangedCalled = false; + sExpectedUriChange = LineageSettings.Global.getUriFor(key); + mContentResolver.registerContentObserver(sExpectedUriChange, false, mTestObserver, + UserHandle.USER_OWNER); + + // replace + final String expectedReplaceValue = "globalTestValue2"; + isPutSuccessful = LineageSettings.Global.putString(mContentResolver, key, expectedReplaceValue); + assertTrue(isPutSuccessful); + + // get + actualValue = LineageSettings.Global.getString(mContentResolver, key); + assertEquals(expectedReplaceValue, actualValue); + + // delete to clean up + int rowsAffected = mContentResolver.delete(LineageSettings.Global.CONTENT_URI, + Settings.NameValueTable.NAME + " = ?", new String[]{ key }); + assertEquals(1, rowsAffected); + + if (!sIsOnChangedCalled) { + fail("On change was never called or was called with the wrong uri"); + } + } + + private class LineageSettingsTestObserver extends ContentObserver { + + public LineageSettingsTestObserver(Handler handler) { + super(handler); + } + + @Override + public void onChange(boolean selfChange, Uri uri) { + if (sExpectedUriChange.equals(uri)) { + sIsOnChangedCalled = true; + } + } + } + + // TODO Add tests for other users +} diff --git a/tests/src/org/lineageos/tests/util/ColorUtilTest.java b/tests/src/org/lineageos/tests/util/ColorUtilTest.java new file mode 100644 index 00000000..9ce91f96 --- /dev/null +++ b/tests/src/org/lineageos/tests/util/ColorUtilTest.java @@ -0,0 +1,123 @@ +/** + * Copyright (c) 2016, The CyanogenMod Project + * + * Licensed 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.lineageos.tests.util; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.ColorDrawable; +import android.test.AndroidTestCase; +import lineageos.util.ColorUtils; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +public class ColorUtilTest extends AndroidTestCase { + private ColorUtils mColorUtils; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mColorUtils = new ColorUtils(); + } + + public void testDropAlpha() { + // With pre-existing alpha + int color = 0xBBCCDD; + int alpha = 0xAA000000; + int result = mColorUtils.dropAlpha(color | alpha); + // Assert alpha was removed + assertEquals(Color.alpha(result), 0); + // Ensure color is preserved + assertEquals(result & color, color); + + // Without pre-existing alpha + color = Color.argb(0, 100, 200 ,300); + result = mColorUtils.dropAlpha(color); + // Assert alpha was removed + assertEquals(Color.alpha(result), 0); + // Ensure color is preserved + assertEquals(result, color); + } + + public void testGenerateAlertColorFromDrawable() { + // Test null drawable + int color = mColorUtils.generateAlertColorFromDrawable(null); + assertEquals(color, Color.BLACK); + + Bitmap bitmap = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888); + BitmapDrawable bitmapDrawable = new BitmapDrawable(bitmap); + bitmapDrawable.setBounds(0, 0, 10, 10); + Canvas canvas = new Canvas(bitmap); + canvas.drawColor(Color.RED); + + // Test fully red bitmap + color = mColorUtils.generateAlertColorFromDrawable(bitmapDrawable); + assertEquals(color, Color.RED); + color = mColorUtils.generateAlertColorFromDrawable( + getColorDrawableFromBitmapDrawable(bitmapDrawable)); + assertEquals(color, Color.RED); + + // Test blue/red bitmap with blue dominating + Paint p = new Paint(); + p.setColor(Color.BLUE); + p.setStyle(Paint.Style.FILL_AND_STROKE); + canvas.drawRect(0, 0, 8, 8, p); + color = mColorUtils.generateAlertColorFromDrawable(bitmapDrawable); + assertEquals(color, Color.BLUE); + color = mColorUtils.generateAlertColorFromDrawable( + getColorDrawableFromBitmapDrawable(bitmapDrawable)); + assertEquals(color, Color.BLUE); + + // Test large white + small blue scenario + canvas.drawColor(Color.WHITE); + canvas.drawRect(0, 0, 2, 2, p); + color = mColorUtils.generateAlertColorFromDrawable(bitmapDrawable); + assertEquals(color, Color.BLUE); + color = mColorUtils.generateAlertColorFromDrawable( + getColorDrawableFromBitmapDrawable(bitmapDrawable)); + assertEquals(color, Color.BLUE); + + // Test large white + small black scenario + canvas.drawColor(Color.WHITE); + p.setColor(Color.BLACK); + canvas.drawRect(0, 0, 2, 2, p); + color = mColorUtils.generateAlertColorFromDrawable(bitmapDrawable); + assertEquals(color, Color.WHITE); + color = mColorUtils.generateAlertColorFromDrawable( + getColorDrawableFromBitmapDrawable(bitmapDrawable)); + assertEquals(color, Color.WHITE); + + assertEquals(bitmap.isRecycled(), false); + bitmap.recycle(); + } + + private ColorDrawable getColorDrawableFromBitmapDrawable(final BitmapDrawable bitmapDrawable) { + ColorDrawable colorDrawable = Mockito.mock(ColorDrawable.class); + Mockito.doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + Canvas canvas = (Canvas) invocation.getArguments()[0]; + bitmapDrawable.draw(canvas); + return null; + } + }).when(colorDrawable).draw(Mockito.any(Canvas.class)); + return colorDrawable; + } +} diff --git a/tests/src/org/lineageos/tests/versioning/VersioningTest.java b/tests/src/org/lineageos/tests/versioning/VersioningTest.java new file mode 100644 index 00000000..9cbf2752 --- /dev/null +++ b/tests/src/org/lineageos/tests/versioning/VersioningTest.java @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2015, The CyanogenMod Project + * + * Licensed 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.lineageos.tests.versioning; + +import android.widget.Toast; +import lineageos.os.Build; + +import org.lineageos.tests.TestActivity; + +public class VersioningTest extends TestActivity { + @Override + protected String tag() { + return null; + } + + @Override + protected Test[] tests() { + return mTests; + } + + private Test[] mTests = new Test[] { + new Test("test retrieve version") { + public void run() { + Toast.makeText(VersioningTest.this, + "Current API version is " + Build.LINEAGE_VERSION.SDK_INT + " which is " + + Build.getNameForSDKInt(Build.LINEAGE_VERSION.SDK_INT), + Toast.LENGTH_SHORT).show(); + } + }, + new Test("test target version larger") { + public void run() { + int currentapiVersion = Build.LINEAGE_VERSION.SDK_INT; + if (currentapiVersion >= Build.LINEAGE_VERSION_CODES.APRICOT){ + Toast.makeText(VersioningTest.this, + "Current API version is greater or equal to " + + Build.getNameForSDKInt(Build.LINEAGE_VERSION_CODES.APRICOT), + Toast.LENGTH_LONG).show(); + } else{ + Toast.makeText(VersioningTest.this, + "Current API version is below target SKD version " + + Build.LINEAGE_VERSION_CODES.APRICOT, + Toast.LENGTH_SHORT).show(); + } + } + } + }; +} diff --git a/tests/src/org/lineageos/tests/versioning/unit/BinderTransactionTest.java b/tests/src/org/lineageos/tests/versioning/unit/BinderTransactionTest.java new file mode 100644 index 00000000..47032bd1 --- /dev/null +++ b/tests/src/org/lineageos/tests/versioning/unit/BinderTransactionTest.java @@ -0,0 +1,206 @@ +/** + * Copyright (c) 2016, The CyanogenMod Project + * + * Licensed 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.lineageos.tests.versioning.unit; + +import android.content.Context; +import android.os.Binder; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.LargeTest; +import android.test.suitebuilder.annotation.SmallTest; +import android.util.Log; +import android.util.Pair; +import org.lineageos.tests.LineageOSTestApplication; +import org.lineageos.tests.versioning.unit.apiv2.ApiV2PriorReleaseInterfaces; +import org.lineageos.tests.versioning.unit.apiv4.ApiV4PriorReleaseInterfaces; +import org.lineageos.tests.versioning.unit.apiv5.ApiV5PriorReleaseInterfaces; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import android.support.test.runner.AndroidJUnit4; +import android.support.test.runner.AndroidJUnitRunner; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * These tests validate the enumerated binder transaction call ids per each + * release api level against the current framework. + * + * This is to validate that no interface contracts are broken in terms of binder + * call method mapping between releases. + * + * After too much searching on the internet, I found that no one was bored enough to + * spend time on this awesomely boring concept. But I am. + * + * Also this is a fun endeavour into parameterized unit testing, and by fun, I mean + * horrible and full of drinking. + * + * If you need to blame anyone for this concept, look no further than danesh@cyngn.com + */ +@RunWith(Parameterized.class) +@LargeTest +public class BinderTransactionTest extends AndroidTestCase { + private static final String TAG = BinderTransactionTest.class.getSimpleName(); + private static final String STUB_SUFFIX = "$Stub"; + private static final String LINEAGEOS_NAMESPACE = "lineageos"; + private static final String TRANSACTION_PREFIX = "TRANSACTION_"; + + private static final int NOT_FROM_PRIOR_RELEASE = -1; + + private String mField; + private int mExpectedValue; + private int mActualValue; + private static Context sContext; + + private static ArrayList<String> mKnownSdkClasses; + private static Map<String, Map<String, Integer>> mApiMethodsAndValues = + new HashMap<String, Map<String, Integer>>(); + + @Before + public void setUp() throws Exception { + super.setUp(); + } + + @Test + public void testClassLoaderGivesSDKClasses() { + /** + * Verify we can retrieve our sdk classes from this package + */ + assertNotNull(mKnownSdkClasses); + assertTrue(mKnownSdkClasses.size() > 0); + } + + private static void doSetup() { + mKnownSdkClasses = MagicalDexHelper.getLoadedClasses( + LineageOSTestApplication.getStaticApplicationContext(), LINEAGEOS_NAMESPACE); + sContext = LineageOSTestApplication.getStaticApplicationContext(); + addInterfaces(ApiV2PriorReleaseInterfaces.getInterfaces()); + addInterfaces(ApiV4PriorReleaseInterfaces.getInterfaces()); + addInterfaces(ApiV5PriorReleaseInterfaces.getInterfaces()); + } + + private static void addInterfaces(Map<String, Map<String, Integer>> mapToAdd) { + for (String key : mapToAdd.keySet()) { + if (mApiMethodsAndValues.get(key) != null) { + Map<String, Integer> internalMap = mApiMethodsAndValues.get(key); + internalMap.putAll(mapToAdd.get(key)); + } else { + Map<String, Integer> internalMap = mapToAdd.get(key); + mApiMethodsAndValues.put(key, internalMap); + } + } + } + + @Parameterized.Parameters + public static Collection<Object[]> data() { + doSetup(); + //Ughhh, lets pretend this never happened + ArrayList<Pair<String, String>> targetClassAndFields = + new ArrayList<Pair<String, String>>(); + ArrayList<Integer> actualValues = new ArrayList<Integer>(); + + for (String sClazz : mKnownSdkClasses) { + if (sClazz.endsWith(STUB_SUFFIX)) { + try { + Class clazz = MagicalDexHelper.loadClassForNameSpace(LineageOSTestApplication + .getStaticApplicationContext(), sClazz); + Field[] fields = clazz.getDeclaredFields(); + Pattern pattern = Pattern.compile("\\.([\\w]+)\\$"); + Matcher matcher = pattern.matcher(clazz.getName()); + String className = null; + if (matcher.find()) { + className = matcher.group(1).substring(0, matcher.group(1).length()); + } + + for (Field field : fields) { + if (field.getName().startsWith(TRANSACTION_PREFIX)) { + field.setAccessible(true); + String fieldName = field.getName().substring( + TRANSACTION_PREFIX.length()); + fieldName = fieldName.split("_")[0]; + Pair<String, String> classAndField = new Pair<String, String>( + className, fieldName); + Log.d(TAG, "Adding: " + classAndField.first + " with field " + + classAndField.second); + targetClassAndFields.add(classAndField); + try { + actualValues.add(field.getInt(clazz)); + } catch (IllegalAccessException e) { + throw new AssertionError("Unable to access " + field.getName()); + } + } + } + } catch (IOException e) { + throw new AssertionError("Unable to load class " + sClazz); + } + } + } + Object[][] values = new Object[targetClassAndFields.size()][3]; + + for (int i = 0; i < targetClassAndFields.size(); i++) { + Pair<String, String> targetClassAndField = targetClassAndFields.get(i); + values[i][0] = targetClassAndField.second; + values[i][1] = lookupValueForField(targetClassAndField.first, + targetClassAndField.second); + values[i][2] = actualValues.get(i); + } + return Arrays.asList(values); + } + + //Look up the target fields value from a prior release + private static Object lookupValueForField(String clazz, String fieldName) { + Log.d(TAG, "Looking up: " + clazz + " with field " + + fieldName); + Map<String, Integer> internalMap = mApiMethodsAndValues.get(clazz); + if (internalMap == null || !internalMap.containsKey(fieldName)) { + Log.d(TAG, "Internal map for " + clazz + " is null or doesn't contain entry"); + return NOT_FROM_PRIOR_RELEASE; + } + return internalMap.get(fieldName); + } + + public BinderTransactionTest(String targetField, Integer expectedValue, Integer actualValue) { + mField = targetField; + mExpectedValue = expectedValue; + mActualValue = actualValue; + } + + @Test + public void testBinderTransactionValidation() { + Log.d(TAG, "Testing: " + mField + " with expected value of " + mExpectedValue + + " and actual value of " + mActualValue); + if (mExpectedValue == NOT_FROM_PRIOR_RELEASE) { + //This is a new interface, no need to test against + return; + } + try { + assertEquals(mExpectedValue, mActualValue); + } catch (AssertionError e) { + throw new AssertionError("For the field " + mField + " expected value " + + mExpectedValue + " but got " + mActualValue); + } + } +} diff --git a/tests/src/org/lineageos/tests/versioning/unit/BuildTest.java b/tests/src/org/lineageos/tests/versioning/unit/BuildTest.java new file mode 100644 index 00000000..02bdf9a9 --- /dev/null +++ b/tests/src/org/lineageos/tests/versioning/unit/BuildTest.java @@ -0,0 +1,67 @@ +/** + * Copyright (c) 2015, The CyanogenMod Project + * + * Licensed 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.lineageos.tests.versioning.unit; + +import android.test.suitebuilder.annotation.SmallTest; +import lineageos.os.Build; + +import android.test.AndroidTestCase; +import lineageos.os.Concierge; + +/** + * Created by adnan on 7/14/15. + */ +public class BuildTest extends AndroidTestCase { + + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @SmallTest + public void testFetchSdkApiLevelExists() { + assertNotNull(Build.LINEAGE_VERSION.SDK_INT); + } + + @SmallTest + public void testSdkApiLevelCurrent() { + assertEquals(Concierge.PARCELABLE_VERSION, Build.LINEAGE_VERSION.SDK_INT); + } + + @SmallTest + public void testSdkApiLevelCanMatch() { + String apiName = Build.getNameForSDKInt(Build.LINEAGE_VERSION.SDK_INT); + assertNotNull(apiName); + assertEquals(Build.getNameForSDKInt(Concierge.PARCELABLE_VERSION), apiName); + } + + @SmallTest + public void testSdkApiLevelSkippedIfGreaterThanAllowed() { + int i = 0; + if (Build.LINEAGE_VERSION.SDK_INT > Concierge.PARCELABLE_VERSION + 1) { + i++; + } + assertEquals(0, i); + } + + @SmallTest + public void testSdkLevelRetrieveNameImpossible() { + String name = Build.getNameForSDKInt(Integer.MAX_VALUE); + assertNotNull(name); + assertEquals(Build.UNKNOWN, name); + } +} diff --git a/tests/src/org/lineageos/tests/versioning/unit/ClassPathException.java b/tests/src/org/lineageos/tests/versioning/unit/ClassPathException.java new file mode 100644 index 00000000..7acfc640 --- /dev/null +++ b/tests/src/org/lineageos/tests/versioning/unit/ClassPathException.java @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2015, The CyanogenMod Project + * + * Licensed 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.lineageos.tests.versioning.unit; + +/** + * Created by Adnan on 9/25/15. + */ +public class ClassPathException extends Exception { + + public ClassPathException(String message) { + super("should not have " + message + " !"); + } +} diff --git a/tests/src/org/lineageos/tests/versioning/unit/ClassPathTest.java b/tests/src/org/lineageos/tests/versioning/unit/ClassPathTest.java new file mode 100644 index 00000000..b5c041ed --- /dev/null +++ b/tests/src/org/lineageos/tests/versioning/unit/ClassPathTest.java @@ -0,0 +1,108 @@ +/** + * Copyright (c) 2015, The CyanogenMod Project + * + * Licensed 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.lineageos.tests.versioning.unit; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.LargeTest; +import android.test.suitebuilder.annotation.SmallTest; +import dalvik.system.DexFile; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Enumeration; + +/** + * Created by adnan on 9/22/15. + */ +public class ClassPathTest extends AndroidTestCase { + + private static final String LINEAGEOS_NAMESPACE = "lineageos"; + private static final String PATH_TO_SYSTEM_FRAMEWORK = "/system/framework"; + + private ArrayList<String> mKnownSdkClasses; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mKnownSdkClasses = MagicalDexHelper.getLoadedClasses(mContext, LINEAGEOS_NAMESPACE); + } + + @SmallTest + public void testClassLoaderGivesSDKClasses() { + /** + * Verify we can retrieve our sdk classes from this package + */ + assertNotNull(mKnownSdkClasses); + assertTrue(mKnownSdkClasses.size() > 0); + } + + @LargeTest + public void testBootClassPathIsClean() { + File path = new File(PATH_TO_SYSTEM_FRAMEWORK); + File[] files = path.listFiles(); + assertNotNull(files); + + /** + * Everything in the in the boot class path needs to not + * contain the sdk. Verify integrity of runtime below. + */ + final String bootClassPath = System.getenv("BOOTCLASSPATH"); + + ArrayList<String> classPathJars = new ArrayList<String>(); + + if (bootClassPath != null) { + String[] bootClassPathElements = bootClassPath.split(":"); + for (String element : bootClassPathElements) { + classPathJars.add(element); + } + } else { + throw new AssertionError("No BOOTCLASSPATH defined! "); + } + + for (String classPathJar : classPathJars) { + try { + File jar = new File(classPathJar); + DexFile dexFile = new DexFile(jar); + assertTrue(isJarClean(dexFile)); + } catch (IOException e) { + throw new AssertionError("Unable to find jar! " + classPathJar + + "\nException " + e.toString()); + } + } + } + + private void processAndCompare(String name) throws ClassPathException { + if (mKnownSdkClasses.contains(name)) { + throw new ClassPathException(name); + } + } + + private boolean isJarClean(DexFile dexFile) throws AssertionError { + Enumeration<String> enumeration = dexFile.entries(); + + while (enumeration.hasMoreElements()) { + try { + processAndCompare(enumeration.nextElement()); + } catch (ClassPathException e) { + throw new AssertionError("Jar file " + + dexFile.getName() + " " + e.getMessage()); + } + } + return true; + } +} diff --git a/tests/src/org/lineageos/tests/versioning/unit/MagicalDexHelper.java b/tests/src/org/lineageos/tests/versioning/unit/MagicalDexHelper.java new file mode 100644 index 00000000..ae414f38 --- /dev/null +++ b/tests/src/org/lineageos/tests/versioning/unit/MagicalDexHelper.java @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2016, The CyanogenMod Project + * + * Licensed 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.lineageos.tests.versioning.unit; + +import android.content.Context; +import dalvik.system.DexFile; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Enumeration; + +/** + * Created by adnan on 2/3/16. + */ +public class MagicalDexHelper { + + public static ArrayList<String> getLoadedClasses(Context context, String targetNameSpace) { + ArrayList<String> listOfClasses = new ArrayList<String>(); + try { + DexFile dexFile = new DexFile(new File(context.getPackageCodePath())); + Enumeration<String> enumeration = dexFile.entries(); + + while (enumeration.hasMoreElements()){ + String className = enumeration.nextElement(); + if (className.startsWith(targetNameSpace)) { + listOfClasses.add(className); + } + } + } catch (IOException e) { + e.printStackTrace(); + } + return listOfClasses; + } + + public static Class loadClassForNameSpace(Context context, + String classToLoad) throws IOException { + DexFile dexFile = new DexFile(new File(context.getPackageCodePath())); + return dexFile.loadClass(classToLoad, context.getClassLoader()); + } +} diff --git a/tests/src/org/lineageos/tests/versioning/unit/apiv2/ApiV2PriorReleaseInterfaces.java b/tests/src/org/lineageos/tests/versioning/unit/apiv2/ApiV2PriorReleaseInterfaces.java new file mode 100644 index 00000000..ce98bf6f --- /dev/null +++ b/tests/src/org/lineageos/tests/versioning/unit/apiv2/ApiV2PriorReleaseInterfaces.java @@ -0,0 +1,131 @@ +/** + * Copyright (c) 2016, The CyanogenMod Project + * + * Licensed 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.lineageos.tests.versioning.unit.apiv2; + +import java.util.HashMap; +import java.util.Map; + +/** + * Created by adnan on 2/4/16. + */ +public class ApiV2PriorReleaseInterfaces { + private static Map<String, Map<String, Integer>> mApiMethodsAndValues = + new HashMap<String, Map<String, Integer>>(); + + //Profiles Aidl (IProfileManager) + static { + Map<String, Integer> profilesMap = getInternalInterfaceMap("IProfileManager"); + // APRICOT + BOYSENBERRY + CANTALOUPE + profilesMap.put("setActiveProfile", 1); + profilesMap.put("etActiveProfileByName", 2); + profilesMap.put("getActiveProfile", 3); + profilesMap.put("addProfile", 4); + profilesMap.put("removeProfile", 5); + profilesMap.put("updateProfile", 6); + profilesMap.put("getProfile", 7); + profilesMap.put("getProfileByName", 8); + profilesMap.put("getProfiles", 9); + profilesMap.put("profileExists", 10); + profilesMap.put("profileExistsByName", 11); + profilesMap.put("notificationGroupExistsByName", 12); + profilesMap.put("getNotificationGroups", 13); + profilesMap.put("addNotificationGroup", 14); + profilesMap.put("removeNotificationGroup", 15); + profilesMap.put("updateNotificationGroup", 16); + profilesMap.put("getNotificationGroupForPackage", 17); + profilesMap.put("getNotificationGroup", 18); + profilesMap.put("resetAll", 19); + } + + //LineageHardwareManager Aidl (ILineageHardwareService) + static { + Map<String, Integer> hardwareMap = getInternalInterfaceMap("ILineageHardwareService"); + // APRICOT + BOYSENBERRY + CANTALOUPE + hardwareMap.put("getSupportedFeatures", 1); + hardwareMap.put("get", 2); + hardwareMap.put("set", 3); + hardwareMap.put("getDisplayColorCalibration", 4); + hardwareMap.put("setDisplayColorCalibration", 5); + hardwareMap.put("getNumGammaControls", 6); + hardwareMap.put("getDisplayGammaCalibration", 7); + hardwareMap.put("setDisplayGammaCalibration", 8); + hardwareMap.put("getVibratorIntensity", 9); + hardwareMap.put("setVibratorIntensity", 10); + hardwareMap.put("getLtoSource", 11); + hardwareMap.put("getLtoDestination", 12); + hardwareMap.put("getLtoDownloadInterval", 13); + hardwareMap.put("getSerialNumber", 14); + hardwareMap.put("requireAdaptiveBacklightForSunlightEnhancement", 15); + hardwareMap.put("getDisplayModes", 16); + hardwareMap.put("getCurrentDisplayMode", 17); + hardwareMap.put("getDefaultDisplayMode", 18); + hardwareMap.put("setDisplayMode", 19); + hardwareMap.put("writePersistentBytes", 20); + hardwareMap.put("readPersistentBytes", 21); + hardwareMap.put("getThermalState", 22); + hardwareMap.put("registerThermalListener", 23); + hardwareMap.put("unRegisterThermalListener", 24); + } + + //LineageStatusBarManager Aidl (ILineageStatusBarManager) + static { + Map<String, Integer> statusBarMap = getInternalInterfaceMap("ILineageStatusBarManager"); + // APRICOT + BOYSENBERRY + CANTALOUPE + statusBarMap.put("createCustomTileWithTag", 1); + statusBarMap.put("removeCustomTileWithTag", 2); + statusBarMap.put("registerListener", 3); + statusBarMap.put("unregisterListener", 4); + statusBarMap.put("removeCustomTileFromListener", 5); + } + + //AppSuggestManager Aidl (IAppSuggestManager) + static { + Map<String, Integer> suggestMap = getInternalInterfaceMap("IAppSuggestManager"); + // APRICOT + BOYSENBERRY + CANTALOUPE + suggestMap.put("handles", 1); + suggestMap.put("getSuggestions", 2); + } + + //LineageTelephonyManager Aidl (ILineageTelephonyManager) + static { + Map<String, Integer> telephonyMap = getInternalInterfaceMap("ILineageTelephonyManager"); + // APRICOT + BOYSENBERRY + CANTALOUPE + telephonyMap.put("getSubInformation", 1); + telephonyMap.put("isSubActive", 2); + telephonyMap.put("isDataConnectionSelectedOnSub", 3); + telephonyMap.put("isDataConnectionEnabled", 4); + telephonyMap.put("setSubState", 5); + telephonyMap.put("setDataConnectionSelectedOnSub", 6); + telephonyMap.put("setDataConnectionState", 7); + telephonyMap.put("setDefaultPhoneSub", 8); + telephonyMap.put("setDefaultSmsSub", 9); + } + + protected static Map<String, Integer> getInternalInterfaceMap(String targetInterface) { + Map<String, Integer> internalMap = mApiMethodsAndValues.get(targetInterface); + if (internalMap == null) { + internalMap = new HashMap<String, Integer>(); + mApiMethodsAndValues.put(targetInterface, internalMap); + return internalMap; + } + return internalMap; + } + + public static Map<String, Map<String, Integer>> getInterfaces() { + return mApiMethodsAndValues; + } +} diff --git a/tests/src/org/lineageos/tests/versioning/unit/apiv4/ApiV4PriorReleaseInterfaces.java b/tests/src/org/lineageos/tests/versioning/unit/apiv4/ApiV4PriorReleaseInterfaces.java new file mode 100644 index 00000000..3e29d58b --- /dev/null +++ b/tests/src/org/lineageos/tests/versioning/unit/apiv4/ApiV4PriorReleaseInterfaces.java @@ -0,0 +1,107 @@ +/** + * Copyright (c) 2016, The CyanogenMod Project + * + * Licensed 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.lineageos.tests.versioning.unit.apiv4; + +import java.util.HashMap; +import java.util.Map; + +public class ApiV4PriorReleaseInterfaces { + private static Map<String, Map<String, Integer>> mApiMethodsAndValues = + new HashMap<String, Map<String, Integer>>(); + + //Profiles Aidl (IProfileManager) + static { + Map<String, Integer> profilesMap = getInternalInterfaceMap("IProfileManager"); + // APRICOT + BOYSENBERRY + CANTALOUPE to 19 + // DRAGONFRUIT BEGIN + profilesMap.put("isEnabled", 20); + } + + //LineageHardwareManager Aidl (ILineageHardwareService) + static { + Map<String, Integer> hardwareMap = getInternalInterfaceMap("ILineageHardwareService"); + // APRICOT + BOYSENBERRY + CANTALOUPE to 24 + // DRAGONFRUIT BEGIN + hardwareMap.put("isSunlightEnhancementSelfManaged", 25); + hardwareMap.put("getUniqueDeviceId", 26); + } + + //LineageStatusBarManager Aidl (ILineageStatusBarManager) + static { + // APRICOT + BOYSENBERRY + CANTALOUPE to 5 + // DRAGONFRUIT BEGIN + } + + //AppSuggestManager Aidl (IAppSuggestManager) + static { + // APRICOT + BOYSENBERRY + CANTALOUPE to 2 + // DRAGONFRUIT BEGIN + } + + //LineageTelephonyManager Aidl (ILineageTelephonyManager) + static { + // APRICOT + BOYSENBERRY + CANTALOUPE to 9 + // DRAGONFRUIT BEGIN + } + + //PerformanceManager Aidl (IPerformanceManager) + static { + Map<String, Integer> perfMap = getInternalInterfaceMap("IPerformanceManager"); + // DRAGONFRUIT BEGIN + perfMap.put("cpuBoost", 1); + perfMap.put("setPowerProfile", 2); + perfMap.put("getPowerProfile", 3); + perfMap.put("getNumberOfProfiles", 4); + perfMap.put("getProfileHasAppProfiles", 5); + } + + //ExternalViewProviderFactory Aidl (IExternalViewProviderFactory) + static { + Map<String, Integer> extProviderMap = + getInternalInterfaceMap("IExternalViewProviderFactory"); + // DRAGONFRUIT BEGIN + extProviderMap.put("createExternalView", 1); + } + + //ExternalViewProvider Aidl (IExternalViewProvider) + static { + Map<String, Integer> extViewProviderMap = + getInternalInterfaceMap("IExternalViewProvider"); + // DRAGONFRUIT BEGIN + extViewProviderMap.put("onAttach", 1); + extViewProviderMap.put("onStart", 2); + extViewProviderMap.put("onResume", 3); + extViewProviderMap.put("onPause", 4); + extViewProviderMap.put("onStop", 5); + extViewProviderMap.put("onDetach", 6); + extViewProviderMap.put("alterWindow", 7); + } + + protected static Map<String, Integer> getInternalInterfaceMap(String targetInterface) { + Map<String, Integer> internalMap = mApiMethodsAndValues.get(targetInterface); + if (internalMap == null) { + internalMap = new HashMap<String, Integer>(); + mApiMethodsAndValues.put(targetInterface, internalMap); + return internalMap; + } + return internalMap; + } + + public static Map<String, Map<String, Integer>> getInterfaces() { + return mApiMethodsAndValues; + } +} diff --git a/tests/src/org/lineageos/tests/versioning/unit/apiv5/ApiV5PriorReleaseInterfaces.java b/tests/src/org/lineageos/tests/versioning/unit/apiv5/ApiV5PriorReleaseInterfaces.java new file mode 100644 index 00000000..898dbfad --- /dev/null +++ b/tests/src/org/lineageos/tests/versioning/unit/apiv5/ApiV5PriorReleaseInterfaces.java @@ -0,0 +1,113 @@ +/** + * Copyright (c) 2016, The CyanogenMod Project + * + * Licensed 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.lineageos.tests.versioning.unit.apiv5; + +import java.util.HashMap; +import java.util.Map; + +public class ApiV5PriorReleaseInterfaces { + private static Map<String, Map<String, Integer>> mApiMethodsAndValues = + new HashMap<String, Map<String, Integer>>(); + + //ExternalViewProviderFactory Aidl (IExternalViewProviderFactory) + static { + Map<String, Integer> extProviderMap = + getInternalInterfaceMap("IExternalViewProviderFactory"); + // DRAGONFRUIT TO 1 + // ELDERBERRY BEGIN + } + + //ExternalViewProvider Aidl (IExternalViewProvider) + static { + Map<String, Integer> extViewProviderMap = + getInternalInterfaceMap("IExternalViewProvider"); + // DRAGONFRUIT TO 7 + // ELDERBERRY BEGIN + } + + //LineageAudioManager Aidl (ILineageAudioService) + static { + Map<String, Integer> lineageAudioService = + getInternalInterfaceMap("ILineageAudioService"); + //ELDERBERRY BEGIN + lineageAudioService.put("listAudioSessions", 1); + } + + //LineageWeatherManager Aidl (ILineageWeatherManager) + static { + Map<String, Integer> ilineageWeatherManager = + getInternalInterfaceMap("ILineageWeatherManager"); + //ELDERBERRY BEGIN + ilineageWeatherManager.put("updateWeather", 1); + ilineageWeatherManager.put("lookupCity ", 2); + ilineageWeatherManager.put("registerWeatherServiceProviderChangeListener", 3); + ilineageWeatherManager.put("unregisterWeatherServiceProviderChangeListener", 4); + ilineageWeatherManager.put("getActiveWeatherServiceProviderLabel", 5); + ilineageWeatherManager.put("cancelRequest", 6); + } + + //RequestInfoListener Aidl (IRequestInfoListener) + static { + Map<String, Integer> requestInfoListener = + getInternalInterfaceMap("IRequestInfoListener"); + //ELDERBERRY BEGIN + requestInfoListener.put("onWeatherRequestCompleted", 1); + requestInfoListener.put("onLookupCityRequestCompleted ", 2); + } + + //WeatherServiceProviderChangeListener Aidl (IWeatherServiceProviderChangeListener) + static { + Map<String, Integer> weatherServiceProviderChangeListener = + getInternalInterfaceMap("IWeatherServiceProviderChangeListener"); + //ELDERBERRY BEGIN + weatherServiceProviderChangeListener.put("onWeatherServiceProviderChanged", 1); + } + + //WeatherProviderService Aidl (IWeatherProviderService) + static { + Map<String, Integer> weatherProviderService = + getInternalInterfaceMap("IWeatherProviderService"); + //ELDERBERRY BEGIN + weatherProviderService.put("processWeatherUpdateRequest", 1); + weatherProviderService.put("processCityNameLookupRequest ", 2); + weatherProviderService.put("setServiceClient", 3); + weatherProviderService.put("cancelOngoingRequests", 4); + weatherProviderService.put("cancelRequest", 5); + } + + //WeatherProviderServiceClient Aidl (IWeatherProviderServiceClient) + static { + Map<String, Integer> weatherProviderServiceClient = + getInternalInterfaceMap("IWeatherProviderServiceClient"); + //ELDERBERRY BEGIN + weatherProviderServiceClient.put("setServiceRequestState", 1); + } + + protected static Map<String, Integer> getInternalInterfaceMap(String targetInterface) { + Map<String, Integer> internalMap = mApiMethodsAndValues.get(targetInterface); + if (internalMap == null) { + internalMap = new HashMap<String, Integer>(); + mApiMethodsAndValues.put(targetInterface, internalMap); + return internalMap; + } + return internalMap; + } + + public static Map<String, Map<String, Integer>> getInterfaces() { + return mApiMethodsAndValues; + } +} diff --git a/tests/src/org/lineageos/tests/weather/unit/DayForecastBuilderTest.java b/tests/src/org/lineageos/tests/weather/unit/DayForecastBuilderTest.java new file mode 100644 index 00000000..70a8c7ea --- /dev/null +++ b/tests/src/org/lineageos/tests/weather/unit/DayForecastBuilderTest.java @@ -0,0 +1,108 @@ +/** + * Copyright (C) 2016 The CyanogenMod Project + * + * Licensed 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.lineageos.tests.weather.unit; + +import android.os.Parcel; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import lineageos.providers.WeatherContract; +import lineageos.weather.WeatherInfo.DayForecast; + +public class DayForecastBuilderTest extends AndroidTestCase { + + private static final int mConditionCode = WeatherContract.WeatherColumns.WeatherCode.HURRICANE; + private static final double mLow = 35; + private static final double mHigh = 58; + + @SmallTest + public void testUnravelFromParcel() { + DayForecast forecast = new DayForecast.Builder(mConditionCode).setHigh(mHigh).setLow(mLow) + .build(); + + Parcel parcel = Parcel.obtain(); + forecast.writeToParcel(parcel, 0); + + parcel.setDataPosition(0); + + DayForecast forecastFromParcel = DayForecast.CREATOR.createFromParcel(parcel); + + assertEquals(forecast, forecastFromParcel); + assertEquals(forecast.getConditionCode(), forecastFromParcel.getConditionCode()); + assertEquals(forecast.getHigh(), forecastFromParcel.getHigh()); + assertEquals(forecast.getLow(), forecastFromParcel.getLow()); + } + + @SmallTest + public void testUnravelFromParcelWithDefaultValues() { + //Condition code is required + DayForecast forecast = new DayForecast.Builder(mConditionCode).build(); + + Parcel parcel = Parcel.obtain(); + forecast.writeToParcel(parcel, 0); + + parcel.setDataPosition(0); + + DayForecast forecastFromParcel = DayForecast.CREATOR.createFromParcel(parcel); + + assertEquals(forecast, forecastFromParcel); + assertEquals(forecast.getConditionCode(), forecastFromParcel.getConditionCode()); + assertEquals(forecast.getHigh(), forecastFromParcel.getHigh()); + assertEquals(forecast.getLow(), forecastFromParcel.getLow()); + } + + @SmallTest + public void testDayForecastBuilder() { + DayForecast forecast = new DayForecast.Builder(mConditionCode).setHigh(mHigh).setLow(mLow) + .build(); + + assertEquals(forecast.getConditionCode(), mConditionCode); + assertEquals(forecast.getHigh(), mHigh); + assertEquals(forecast.getLow(), mLow); + } + + @SmallTest + public void testInvalidWeatherConditionCode() { + try { + DayForecast forecast = new DayForecast.Builder(Integer.MIN_VALUE).build(); + throw new AssertionError("DayForecast object was built with invalid condition code!"); + } catch (IllegalArgumentException e) { + /* EXPECTED */ + } + } + + @SmallTest + public void testInvalidHighTemperature() { + try { + DayForecast forecast = new DayForecast.Builder(mConditionCode).setHigh(Double.NaN) + .setLow(mLow).build(); + throw new AssertionError("DayForecast object was built with invalid high temperature!"); + } catch (IllegalArgumentException e) { + /* EXPECTED */ + } + } + + @SmallTest + public void testInvalidLowTemperature() { + try { + DayForecast forecast = new DayForecast.Builder(mConditionCode).setHigh(mHigh) + .setLow(Double.NaN).build(); + throw new AssertionError("DayForecast object was built with invalid low temperature!"); + } catch (IllegalArgumentException e) { + /* EXPECTED */ + } + } +} diff --git a/tests/src/org/lineageos/tests/weather/unit/LineageWeatherManagerTest.java b/tests/src/org/lineageos/tests/weather/unit/LineageWeatherManagerTest.java new file mode 100644 index 00000000..f6b23484 --- /dev/null +++ b/tests/src/org/lineageos/tests/weather/unit/LineageWeatherManagerTest.java @@ -0,0 +1,242 @@ +/** + * Copyright (C) 2016 The CyanogenMod Project + * + * Licensed 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.lineageos.tests.weather.unit; + +import android.location.Location; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.SmallTest; +import lineageos.weather.LineageWeatherManager; +import lineageos.weather.LineageWeatherManager.LookupCityRequestListener; +import lineageos.weather.LineageWeatherManager.WeatherServiceProviderChangeListener; +import lineageos.weather.LineageWeatherManager.WeatherUpdateRequestListener; +import lineageos.weather.ILineageWeatherManager; +import lineageos.weather.RequestInfo; +import lineageos.weather.WeatherInfo; +import lineageos.weather.WeatherLocation; +import org.lineageos.tests.common.MockIBinderStubForInterface; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; + +public class LineageWeatherManagerTest extends AndroidTestCase { + + private LineageWeatherManager mWeatherManager; + private static final String CITY_NAME = "Seattle, WA"; + private static final int COUNTDOWN = 1; + private static final int REQUEST_ID = 42; + private static final String MOCKED_WEATHER_PROVIDER_LABEL = "Mock'd Weather Service"; + private ILineageWeatherManager.Stub mILineageWeatherManagerSpy; + + @Override + protected void setUp() throws Exception { + super.setUp(); + setUpMockILineageWeatherManager(); + } + + private void setUpMockILineageWeatherManager() { + mWeatherManager = LineageWeatherManager.getInstance(getContext()); + Field f; + try { + f = mWeatherManager.getClass().getDeclaredField("sWeatherManagerService"); + f.setAccessible(true); + + mILineageWeatherManagerSpy + = MockIBinderStubForInterface.getMockInterface(ILineageWeatherManager.Stub.class); + f.set(mWeatherManager, mILineageWeatherManagerSpy); + + Mockito.doAnswer(new WeatherUpdateRequestAnswer()) + .when(mILineageWeatherManagerSpy).updateWeather(Mockito.any(RequestInfo.class)); + + Mockito.doAnswer(new LookUpCityAnswer()) + .when(mILineageWeatherManagerSpy).lookupCity(Mockito.any(RequestInfo.class)); + + Mockito.doAnswer(new GetActiveWeatherServiceProviderLabelAnser()) + .when(mILineageWeatherManagerSpy).getActiveWeatherServiceProviderLabel(); + + Mockito.doAnswer(new CancelRequestAnswer()) + .when(mILineageWeatherManagerSpy).cancelRequest(Mockito.eq(REQUEST_ID)); + } catch (Exception e) { + throw new AssertionError(e); + } + } + + private static class WeatherUpdateRequestAnswer implements Answer<Integer> { + + @Override + public Integer answer(InvocationOnMock invocation) throws Throwable { + final RequestInfo requestInfo = (RequestInfo) invocation.getArguments()[0]; + if (requestInfo.getRequestType() == RequestInfo.TYPE_WEATHER_BY_GEO_LOCATION_REQ) { + assertNotNull(requestInfo.getLocation()); + } else { + assertNotNull(requestInfo.getWeatherLocation()); + } + final WeatherInfo weatherInfo = new WeatherInfo.Builder(CITY_NAME, + 30d, requestInfo.getTemperatureUnit()).build(); + requestInfo.getRequestListener().onWeatherRequestCompleted(requestInfo, + LineageWeatherManager.RequestStatus.COMPLETED, weatherInfo); + return REQUEST_ID; + } + } + + private static class LookUpCityAnswer implements Answer<Integer> { + + @Override + public Integer answer(InvocationOnMock invocation) throws Throwable { + final RequestInfo requestInfo = (RequestInfo) invocation.getArguments()[0]; + final List<WeatherLocation> locations = new ArrayList<>(); + final String cityName = requestInfo.getCityName(); + assertNotNull(cityName); + locations.add(new WeatherLocation.Builder(cityName).build()); + requestInfo.getRequestListener().onLookupCityRequestCompleted(requestInfo, + LineageWeatherManager.RequestStatus.COMPLETED, locations); + return REQUEST_ID; + } + } + + private static class GetActiveWeatherServiceProviderLabelAnser implements Answer<String> { + + @Override + public String answer(InvocationOnMock invocation) throws Throwable { + return MOCKED_WEATHER_PROVIDER_LABEL; + } + } + + private static class CancelRequestAnswer implements Answer<Void> { + + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + final int requestId = (Integer) invocation.getArguments()[0]; + assertEquals(requestId, REQUEST_ID); + return null; + } + } + + @SmallTest + public void testGetActiveWeatherServiceProviderLabel() { + String providerLabel = mWeatherManager.getActiveWeatherServiceProviderLabel(); + assertEquals(MOCKED_WEATHER_PROVIDER_LABEL, providerLabel); + } + + @MediumTest + public void testLookupCity() { + final CountDownLatch signal = new CountDownLatch(COUNTDOWN); + final boolean[] error = {false}; + mWeatherManager.lookupCity(CITY_NAME, + new LookupCityRequestListener() { + @Override + public void onLookupCityRequestCompleted(int status, + List<WeatherLocation> locations) { + final int totalLocations = locations != null ? locations.size() : 0; + if (status != LineageWeatherManager.RequestStatus.COMPLETED + || totalLocations < 1) { + error[0] = true; + } + signal.countDown(); + } + }); + try { + signal.await(); + assertFalse(error[0]); + } catch (InterruptedException e) { + throw new AssertionError(e); + } + } + + @SmallTest + public void testRegisterListener() { + mWeatherManager.registerWeatherServiceProviderChangeListener(mListener); + + try { + mWeatherManager.registerWeatherServiceProviderChangeListener(mListener); + throw new AssertionError("Listener was registered twice!"); + } catch (IllegalArgumentException e) { + //EXPECTED + } + + mWeatherManager.unregisterWeatherServiceProviderChangeListener(mListener); + + try { + mWeatherManager.unregisterWeatherServiceProviderChangeListener(mListener); + throw new AssertionError("Listener was de-registered twice!"); + } catch (IllegalArgumentException e) { + //EXPECTED + } + } + + private WeatherServiceProviderChangeListener mListener + = new WeatherServiceProviderChangeListener() { + @Override + public void onWeatherServiceProviderChanged(String providerLabel) {} + }; + + @MediumTest + public void testRequestWeatherUpdateByWeatherLocation() { + final CountDownLatch signal = new CountDownLatch(COUNTDOWN); + final WeatherLocation weatherLocation = new WeatherLocation.Builder(CITY_NAME).build(); + final boolean[] error = {false}; + mWeatherManager.requestWeatherUpdate(weatherLocation, new WeatherUpdateRequestListener() { + @Override + public void onWeatherRequestCompleted(int status, WeatherInfo weatherInfo) { + if (status != LineageWeatherManager.RequestStatus.COMPLETED + || !weatherInfo.getCity().equals(CITY_NAME)) { + error[0] = true; + } + signal.countDown(); + } + }); + try { + signal.await(); + assertFalse(error[0]); + } catch (InterruptedException e) { + throw new AssertionError(e); + } + } + + @MediumTest + public void testRequestWeatherUpdateByLocation() { + final CountDownLatch signal = new CountDownLatch(COUNTDOWN); + final Location location = new Location("test_location_provider"); + final boolean[] error = {false}; + mWeatherManager.requestWeatherUpdate(location, new WeatherUpdateRequestListener() { + @Override + public void onWeatherRequestCompleted(int status, WeatherInfo weatherInfo) { + if (status != LineageWeatherManager.RequestStatus.COMPLETED + || !weatherInfo.getCity().equals(CITY_NAME)) { + error[0] = true; + } + signal.countDown(); + } + }); + try { + signal.await(); + assertFalse(error[0]); + } catch (InterruptedException e) { + throw new AssertionError(e); + } + } + + @SmallTest + public void testCancelRequest() { + mWeatherManager.cancelRequest(REQUEST_ID); + } +} diff --git a/tests/src/org/lineageos/tests/weather/unit/MockWeatherProviderService.java b/tests/src/org/lineageos/tests/weather/unit/MockWeatherProviderService.java new file mode 100644 index 00000000..83f6d6ea --- /dev/null +++ b/tests/src/org/lineageos/tests/weather/unit/MockWeatherProviderService.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2016 The CyanogenMod Project + * + * Licensed 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.lineageos.tests.weather.unit; + +import lineageos.weatherservice.ServiceRequest; +import lineageos.weatherservice.WeatherProviderService; +import org.mockito.Mockito; + +public class MockWeatherProviderService extends WeatherProviderService { + + private MockWeatherProviderService mCallTracker; + + public MockWeatherProviderService() { + mCallTracker = Mockito.mock(MockWeatherProviderService.class); + } + + public MockWeatherProviderService getCallTracker() { + return mCallTracker; + } + + @Override + protected void onConnected() { + mCallTracker.onConnected(); + } + + @Override + protected void onDisconnected() { + mCallTracker.onDisconnected(); + } + + @Override + protected void onRequestSubmitted(ServiceRequest request) { + mCallTracker.onRequestSubmitted(request); + } + + @Override + protected void onRequestCancelled(ServiceRequest request) { + mCallTracker.onRequestCancelled(request); + } +} diff --git a/tests/src/org/lineageos/tests/weather/unit/ServiceRequestResultBuilderTest.java b/tests/src/org/lineageos/tests/weather/unit/ServiceRequestResultBuilderTest.java new file mode 100644 index 00000000..1befff61 --- /dev/null +++ b/tests/src/org/lineageos/tests/weather/unit/ServiceRequestResultBuilderTest.java @@ -0,0 +1,96 @@ +/** + * Copyright (C) 2016 The CyanogenMod Project + * + * Licensed 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.lineageos.tests.weather.unit; + +import android.os.Parcel; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import lineageos.providers.WeatherContract; +import lineageos.weather.WeatherInfo; +import lineageos.weather.WeatherLocation; +import lineageos.weatherservice.ServiceRequestResult; + +import java.util.ArrayList; +import java.util.List; + +public class ServiceRequestResultBuilderTest extends AndroidTestCase { + + @SmallTest + public void testUnravelFromParcelWithWeatherInfo() { + final String cityName = "Cancun"; + final double temperature = 70; + final int temperatureUnit = WeatherContract.WeatherColumns.TempUnit.CELSIUS; + + WeatherInfo info = new WeatherInfo.Builder(cityName, temperature, temperatureUnit) + .build(); + + ServiceRequestResult result = new ServiceRequestResult.Builder(info).build(); + + Parcel parcel = Parcel.obtain(); + result.writeToParcel(parcel, 0); + + parcel.setDataPosition(0); + + ServiceRequestResult resultFromParcel + = ServiceRequestResult.CREATOR.createFromParcel(parcel); + + assertEquals(result, resultFromParcel); + assertEquals(result.getWeatherInfo(), resultFromParcel.getWeatherInfo()); + } + + @SmallTest + public void testsUnravelFromParcelWithWeatherLocationList() { + + List<WeatherLocation> weatherLocationList = new ArrayList<>(); + weatherLocationList.add(new WeatherLocation.Builder("Cancun").build()); + ServiceRequestResult result = new ServiceRequestResult.Builder(weatherLocationList).build(); + + Parcel parcel = Parcel.obtain(); + result.writeToParcel(parcel, 0); + + parcel.setDataPosition(0); + + ServiceRequestResult resultFromParcel + = ServiceRequestResult.CREATOR.createFromParcel(parcel); + + assertEquals(result, resultFromParcel); + assertEquals(result.getLocationLookupList(), resultFromParcel.getLocationLookupList()); + } + + @SmallTest + public void testNullWeatherInfo() { + try { + WeatherInfo info = null; + ServiceRequestResult result = new ServiceRequestResult.Builder(info).build(); + throw new AssertionError("ServiceRequestResult object was built with null WeatherInfo"); + } catch (IllegalArgumentException e) { + /* EXPECTED */ + } + } + + @SmallTest + public void testNullWeatherLocationList() { + try { + List<WeatherLocation> list = null; + ServiceRequestResult result = new ServiceRequestResult.Builder(list).build(); + throw new AssertionError("ServiceRequestResult object was built with null " + + "WeatherLocation list"); + } catch (IllegalArgumentException e) { + /* EXPECTED */ + } + } +} diff --git a/tests/src/org/lineageos/tests/weather/unit/WeatherInfoBuilderTest.java b/tests/src/org/lineageos/tests/weather/unit/WeatherInfoBuilderTest.java new file mode 100644 index 00000000..bc1dd100 --- /dev/null +++ b/tests/src/org/lineageos/tests/weather/unit/WeatherInfoBuilderTest.java @@ -0,0 +1,252 @@ +/** + * Copyright (C) 2016 The CyanogenMod Project + * + * Licensed 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.lineageos.tests.weather.unit; + +import android.os.Parcel; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import lineageos.providers.WeatherContract; +import lineageos.weather.WeatherInfo; + +public class WeatherInfoBuilderTest extends AndroidTestCase { + + private static final String mCityName = "Cancun"; + private static final double mTemperature = 70; + private static final int mTemperatureUnit = WeatherContract.WeatherColumns.TempUnit.CELSIUS; + private static final double mHumidity = 45; + private static final double mWindSpeed = 15; + private static final double mWindDirection = 150; + private static final int mWindSpeedUnit = WeatherContract.WeatherColumns.WindSpeedUnit.KPH; + private static final long mTimestamp = System.currentTimeMillis(); + private static final double mTodaysHigh = 80; + private static final double mTodaysLow = 65; + private static final int mWeatherConditionCode + = WeatherContract.WeatherColumns.WeatherCode.SUNNY; + + @SmallTest + public void testUnravelFromParcelWithDefaultValues() { + //City name, temp and unit are required + WeatherInfo info = new WeatherInfo.Builder(mCityName, mTemperature, mTemperatureUnit) + .build(); + Parcel parcel = Parcel.obtain(); + info.writeToParcel(parcel, 0); + + parcel.setDataPosition(0); + + WeatherInfo weatherInfoFromParcel = WeatherInfo.CREATOR.createFromParcel(parcel); + assertNotNull(weatherInfoFromParcel); + + assertEquals(info, weatherInfoFromParcel); + //City name + assertEquals(info.getCity(), weatherInfoFromParcel.getCity()); + //Forecast list + assertEquals(info.getForecasts(), weatherInfoFromParcel.getForecasts()); + //Humidity + assertEquals(info.getHumidity(), weatherInfoFromParcel.getHumidity()); + //Temp + assertEquals(info.getConditionCode(), weatherInfoFromParcel.getConditionCode()); + assertEquals(info.getTemperature(), weatherInfoFromParcel.getTemperature()); + assertEquals(info.getTemperatureUnit(), weatherInfoFromParcel.getTemperatureUnit()); + //Timestamp + assertEquals(info.getTimestamp(), weatherInfoFromParcel.getTimestamp()); + //Today's low/high + assertEquals(info.getTodaysHigh(), weatherInfoFromParcel.getTodaysHigh()); + assertEquals(info.getTodaysLow(), weatherInfoFromParcel.getTodaysLow()); + //Wind + assertEquals(info.getWindDirection(), weatherInfoFromParcel.getWindDirection()); + assertEquals(info.getWindSpeed(), weatherInfoFromParcel.getWindDirection()); + assertEquals(info.getWindSpeedUnit(), weatherInfoFromParcel.getWindSpeedUnit()); + //Verify default values + assertEquals(info.getTodaysHigh(), Double.NaN); + } + + @SmallTest + public void testWeatherInfoBuilder() { + WeatherInfo info = new WeatherInfo.Builder(mCityName, mTemperature, mTemperatureUnit) + .setHumidity(mHumidity) + .setWind(mWindSpeed, mWindDirection, mWindSpeedUnit) + .setTimestamp(mTimestamp) + .setTodaysHigh(mTodaysHigh) + .setTodaysLow(mTodaysLow) + .setWeatherCondition(mWeatherConditionCode).build(); + + assertEquals(info.getCity(), mCityName); + assertEquals(info.getTemperature(), mTemperature); + assertEquals(info.getTemperatureUnit(), mTemperatureUnit); + assertEquals(info.getHumidity(), mHumidity); + assertEquals(info.getWindSpeed(), mWindSpeed); + assertEquals(info.getWindDirection(), mWindDirection); + assertEquals(info.getWindSpeedUnit(), mWindSpeedUnit); + assertEquals(info.getTimestamp(), mTimestamp); + assertEquals(info.getTodaysHigh(), mTodaysHigh); + assertEquals(info.getTodaysLow(), mTodaysLow); + assertEquals(info.getConditionCode(), mWeatherConditionCode); + } + + @SmallTest + public void testUnravelFromParcel() { + WeatherInfo info = new WeatherInfo.Builder(mCityName, mTemperature, mTemperatureUnit) + .setHumidity(mHumidity) + .setWind(mWindSpeed, mWindDirection, mWindSpeedUnit) + .setTimestamp(mTimestamp) + .setTodaysHigh(mTodaysHigh) + .setTodaysLow(mTodaysLow) + .setWeatherCondition(mWeatherConditionCode).build(); + + Parcel parcel = Parcel.obtain(); + info.writeToParcel(parcel, 0); + + parcel.setDataPosition(0); + + WeatherInfo infoFromParcel = WeatherInfo.CREATOR.createFromParcel(parcel); + assertEquals(info.getCity(), infoFromParcel.getCity()); + assertEquals(info.getTemperature(), infoFromParcel.getTemperature()); + assertEquals(info.getTemperatureUnit(), infoFromParcel.getTemperatureUnit()); + assertEquals(info.getHumidity(), infoFromParcel.getHumidity()); + assertEquals(info.getWindSpeed(), infoFromParcel.getWindSpeed()); + assertEquals(info.getWindDirection(), infoFromParcel.getWindDirection()); + assertEquals(info.getWindSpeedUnit(), infoFromParcel.getWindSpeedUnit()); + assertEquals(info.getTimestamp(), infoFromParcel.getTimestamp()); + assertEquals(info.getTodaysHigh(), infoFromParcel.getTodaysHigh()); + assertEquals(info.getTodaysLow(), infoFromParcel.getTodaysLow()); + assertEquals(info.getConditionCode(), infoFromParcel.getConditionCode()); + } + + @SmallTest + public void testNullCityName() { + try { + WeatherInfo info = new WeatherInfo.Builder(null, mTemperature, mTemperatureUnit) + .build(); + throw new AssertionError("WeatherInfo object built with null city name!"); + } catch (IllegalArgumentException e) { + /* EXPECTED */ + } + } + + @SmallTest + public void testInvalidTemperature() { + try { + WeatherInfo info = new WeatherInfo.Builder(mCityName, Double.NaN, mTemperatureUnit) + .build(); + throw new AssertionError("WeatherInfo object built with invalid temperature value!"); + } catch (IllegalArgumentException e) { + /* EXPECTED */ + } + } + + @SmallTest + public void testInvalidTemperatureUnit() { + try { + WeatherInfo info = new WeatherInfo.Builder(mCityName, mTemperature,Integer.MIN_VALUE) + .build(); + throw new AssertionError("WeatherInfo object built with invalid temperature unit!"); + } catch (IllegalArgumentException e) { + /* EXPECTED */ + } + } + + @SmallTest + public void testNullForecastList() { + try { + WeatherInfo info = new WeatherInfo.Builder(mCityName, mTemperature,mTemperatureUnit) + .setForecast(null).build(); + throw new AssertionError("WeatherInfo object built with null forecast list!"); + } catch (IllegalArgumentException e) { + /* EXPECTED */ + } + } + + @SmallTest + public void testInvalidWeatherConditionCode() { + try { + WeatherInfo info = new WeatherInfo.Builder(mCityName, mTemperature,mTemperatureUnit) + .setWeatherCondition(Integer.MIN_VALUE).build(); + throw new AssertionError("WeatherInfo object built with invalid weather " + + "condition code!"); + } catch (IllegalArgumentException e) { + /* EXPECTED */ + } + } + + @SmallTest + public void testInvalidHumidity() { + try { + WeatherInfo info = new WeatherInfo.Builder(mCityName, mTemperature,mTemperatureUnit) + .setHumidity(Double.NaN).build(); + throw new AssertionError("WeatherInfo object built with invalid humidity value!"); + } catch (IllegalArgumentException e) { + /* EXPECTED */ + } + } + + @SmallTest + public void testInvalidWindSpeed() { + try { + WeatherInfo info = new WeatherInfo.Builder(mCityName, mTemperature,mTemperatureUnit) + .setWind(Double.NaN, mWindDirection, mWindSpeedUnit) + .build(); + throw new AssertionError("WeatherInfo object built with invalid wind speed!"); + } catch (IllegalArgumentException e) { + /* EXPECTED */ + } + } + + @SmallTest + public void testInvalidWindDirection() { + try { + WeatherInfo info = new WeatherInfo.Builder(mCityName, mTemperature,mTemperatureUnit) + .setWind(mWindSpeed, Double.NaN, mWindSpeedUnit) + .build(); + throw new AssertionError("WeatherInfo object built with invalid wind direction!"); + } catch (IllegalArgumentException e) { + /* EXPECTED */ + } + } + + @SmallTest + public void testInvalidWindSpeedUnit(){ + try { + WeatherInfo info = new WeatherInfo.Builder(mCityName, mTemperature,mTemperatureUnit) + .setWind(mWindSpeed, mWindDirection, Integer.MIN_VALUE).build(); + throw new AssertionError("WeatherInfo object built with invalid wind speed unit!"); + } catch (IllegalArgumentException e) { + /* EXPECTED */ + } + } + + @SmallTest + public void testInvalidTodaysLow() { + try { + WeatherInfo info = new WeatherInfo.Builder(mCityName, mTemperature,mTemperatureUnit) + .setTodaysLow(Double.NaN).build(); + throw new AssertionError("WeatherInfo object built with invalid low temp!"); + } catch (IllegalArgumentException e) { + /* EXPECTED */ + } + } + + @SmallTest + public void testInvalidTodaysHigh() { + try { + WeatherInfo info = new WeatherInfo.Builder(mCityName, mTemperature,mTemperatureUnit) + .setTodaysHigh(Double.NaN).build(); + throw new AssertionError("WeatherInfo object built with invalid high temp!"); + } catch (IllegalArgumentException e) { + /* EXPECTED */ + } + } +} diff --git a/tests/src/org/lineageos/tests/weather/unit/WeatherLocationBuilderTest.java b/tests/src/org/lineageos/tests/weather/unit/WeatherLocationBuilderTest.java new file mode 100644 index 00000000..b6d9c207 --- /dev/null +++ b/tests/src/org/lineageos/tests/weather/unit/WeatherLocationBuilderTest.java @@ -0,0 +1,129 @@ +/** + * Copyright (C) 2016 The CyanogenMod Project + * + * Licensed 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.lineageos.tests.weather.unit; + +import android.os.Parcel; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import lineageos.weather.WeatherLocation; + +public class WeatherLocationBuilderTest extends AndroidTestCase { + + private static final String mCityId = "can1"; + private static final String mCityName = "Cancun"; + private static final String mState = "Quintana Roo"; + private static final String mCountryId = "MX"; + private static final String mCountry = "Mexico"; + private static final String mZipCode = "77510"; + + @SmallTest + public void testUnravelFromParcelTwoArgsConstructor() { + WeatherLocation location = new WeatherLocation.Builder(mCityId, mCityName) + .setState(mState).setPostalCode(mZipCode).setCountryId(mCountryId) + .setCountry(mCountry).build(); + + Parcel parcel = Parcel.obtain(); + location.writeToParcel(parcel, 0); + + parcel.setDataPosition(0); + + WeatherLocation locationFromParcel = WeatherLocation.CREATOR.createFromParcel(parcel); + + assertEquals(location, locationFromParcel); + assertEquals(location.getCityId(), locationFromParcel.getCityId()); + assertEquals(location.getCity(), locationFromParcel.getCity()); + assertEquals(location.getState(), locationFromParcel.getState()); + assertEquals(location.getPostalCode(), locationFromParcel.getPostalCode()); + assertEquals(location.getCountry(), locationFromParcel.getCountry()); + assertEquals(location.getCountryId(), locationFromParcel.getCountryId()); + } + + @SmallTest + public void testUnravelFromParcelOneArgConstructor() { + WeatherLocation location = new WeatherLocation.Builder(mCityName) + .setState(mState).setPostalCode(mZipCode).setCountryId(mCountryId) + .setCountry(mCountry).build(); + + Parcel parcel = Parcel.obtain(); + location.writeToParcel(parcel, 0); + + parcel.setDataPosition(0); + + WeatherLocation locationFromParcel = WeatherLocation.CREATOR.createFromParcel(parcel); + + assertEquals(location, locationFromParcel); + assertEquals(location.getCityId(), locationFromParcel.getCityId()); + assertEquals(location.getCity(), locationFromParcel.getCity()); + assertEquals(location.getState(), locationFromParcel.getState()); + assertEquals(location.getPostalCode(), locationFromParcel.getPostalCode()); + assertEquals(location.getCountry(), locationFromParcel.getCountry()); + assertEquals(location.getCountryId(), locationFromParcel.getCountryId()); + } + + @SmallTest + public void testUnravelFromParcelWithDefaultsOneArgConstructor() { + WeatherLocation location = new WeatherLocation.Builder(mCityName).build(); + Parcel parcel = Parcel.obtain(); + location.writeToParcel(parcel, 0); + + parcel.setDataPosition(0); + + WeatherLocation locationFromParcel = WeatherLocation.CREATOR.createFromParcel(parcel); + + assertEquals(location, locationFromParcel); + assertEquals(location.getCityId(), locationFromParcel.getCityId()); + assertEquals(location.getCity(), locationFromParcel.getCity()); + assertEquals(location.getState(), locationFromParcel.getState()); + assertEquals(location.getPostalCode(), locationFromParcel.getPostalCode()); + assertEquals(location.getCountry(), locationFromParcel.getCountry()); + assertEquals(location.getCountryId(), locationFromParcel.getCountryId()); + } + + @SmallTest + public void testUnravelFromParcelWithDefaultsTwoArgsConstructor() { + WeatherLocation location = new WeatherLocation.Builder(mCityId, mCityName).build(); + Parcel parcel = Parcel.obtain(); + location.writeToParcel(parcel, 0); + + parcel.setDataPosition(0); + + WeatherLocation locationFromParcel = WeatherLocation.CREATOR.createFromParcel(parcel); + + assertEquals(location, locationFromParcel); + assertEquals(location.getCityId(), locationFromParcel.getCityId()); + assertEquals(location.getCity(), locationFromParcel.getCity()); + assertEquals(location.getState(), locationFromParcel.getState()); + assertEquals(location.getPostalCode(), locationFromParcel.getPostalCode()); + assertEquals(location.getCountry(), locationFromParcel.getCountry()); + assertEquals(location.getCountryId(), locationFromParcel.getCountryId()); + } + + + @SmallTest + public void testWeatherLocationBuilder() { + WeatherLocation location = new WeatherLocation.Builder(mCityId, mCityName) + .setState(mState).setPostalCode(mZipCode).setCountryId(mCountryId) + .setCountry(mCountry).build(); + + assertEquals(location.getCityId(), mCityId); + assertEquals(location.getCity(), mCityName); + assertEquals(location.getState(), mState); + assertEquals(location.getPostalCode(), mZipCode); + assertEquals(location.getCountryId(), mCountryId); + assertEquals(location.getCountry(), mCountry); + } +} diff --git a/tests/src/org/lineageos/tests/weather/unit/WeatherProviderServiceTest.java b/tests/src/org/lineageos/tests/weather/unit/WeatherProviderServiceTest.java new file mode 100644 index 00000000..bce369d4 --- /dev/null +++ b/tests/src/org/lineageos/tests/weather/unit/WeatherProviderServiceTest.java @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2016 The CyanogenMod Project + * + * Licensed 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.lineageos.tests.weather.unit; + +import android.location.Location; +import android.os.IBinder; +import lineageos.weather.LineageWeatherManager; +import lineageos.weather.RequestInfo; +import lineageos.weather.WeatherLocation; +import lineageos.weatherservice.IWeatherProviderService; +import lineageos.weatherservice.IWeatherProviderServiceClient; +import lineageos.weatherservice.ServiceRequest; +import lineageos.weatherservice.ServiceRequestResult; +import org.lineageos.tests.common.MockIBinderStubForInterface; +import org.lineageos.tests.common.ThreadServiceTestCase; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; + +public class WeatherProviderServiceTest extends ThreadServiceTestCase<MockWeatherProviderService> { + + public WeatherProviderServiceTest() { + super(MockWeatherProviderService.class); + } + + private static final String CITY_NAME = "Seattle"; + private static final int TIMEOUT = 5000; + + public void testCityNameLookupRequest() throws Exception { + IBinder binder = bindService((ServiceRunnable) null); + assertNotNull(binder); + + final IWeatherProviderService provider = IWeatherProviderService.Stub.asInterface(binder); + assertNotNull(provider); + + provider.processCityNameLookupRequest( + buildMockdRequestInfo(RequestInfo.TYPE_LOOKUP_CITY_NAME_REQ)); + runOnServiceThread(new Runnable() { + @Override + public void run() { + ArgumentCaptor<ServiceRequest> params + = ArgumentCaptor.forClass(ServiceRequest.class); + + Mockito.verify(getService().getCallTracker(), Mockito.timeout(TIMEOUT).times(1)) + .onRequestSubmitted(params.capture()); + + ServiceRequest request = params.getValue(); + assertEquals(request.getRequestInfo().getRequestType(), + RequestInfo.TYPE_LOOKUP_CITY_NAME_REQ); + + assertEquals(request.getRequestInfo().getCityName(), CITY_NAME); + } + }); + } + + public void testWeatherUpdateRequestByWeatherLocation() throws Exception { + IBinder binder = bindService((ServiceRunnable) null); + assertNotNull(binder); + + final IWeatherProviderService provider = IWeatherProviderService.Stub.asInterface(binder); + assertNotNull(provider); + + provider.processWeatherUpdateRequest( + buildMockdRequestInfo(RequestInfo.TYPE_WEATHER_BY_WEATHER_LOCATION_REQ)); + runOnServiceThread(new Runnable() { + @Override + public void run() { + ArgumentCaptor<ServiceRequest> params + = ArgumentCaptor.forClass(ServiceRequest.class); + + Mockito.verify(getService().getCallTracker(), Mockito.timeout(TIMEOUT).times(1)) + .onRequestSubmitted(params.capture()); + + ServiceRequest request = params.getValue(); + assertEquals(request.getRequestInfo().getRequestType(), + RequestInfo.TYPE_WEATHER_BY_WEATHER_LOCATION_REQ); + + WeatherLocation weatherLocation = request.getRequestInfo().getWeatherLocation(); + assertNotNull(weatherLocation); + assertEquals(weatherLocation.getCity(), CITY_NAME); + } + }); + } + + public void testWeatherUpdateRequestByGeoLocation() throws Exception { + IBinder binder = bindService((ServiceRunnable) null); + assertNotNull(binder); + + final IWeatherProviderService provider = IWeatherProviderService.Stub.asInterface(binder); + assertNotNull(provider); + + provider.processWeatherUpdateRequest( + buildMockdRequestInfo(RequestInfo.TYPE_WEATHER_BY_GEO_LOCATION_REQ)); + runOnServiceThread(new Runnable() { + @Override + public void run() { + ArgumentCaptor<ServiceRequest> params + = ArgumentCaptor.forClass(ServiceRequest.class); + + Mockito.verify(getService().getCallTracker(), Mockito.timeout(TIMEOUT).times(1)) + .onRequestSubmitted(params.capture()); + + ServiceRequest request = params.getValue(); + assertEquals(request.getRequestInfo().getRequestType(), + RequestInfo.TYPE_WEATHER_BY_GEO_LOCATION_REQ); + + Location location = request.getRequestInfo().getLocation(); + assertNotNull(location); + } + }); + } + + public void testServiceRequestResult() throws Exception { + final CountDownLatch latch = new CountDownLatch(3); + IBinder binder = bindService((ServiceRunnable) null); + assertNotNull(binder); + + final IWeatherProviderService provider = IWeatherProviderService.Stub.asInterface(binder); + assertNotNull(provider); + + IWeatherProviderServiceClient client = + MockIBinderStubForInterface.getMockInterface( + IWeatherProviderServiceClient.Stub.class); + + Mockito.doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + RequestInfo requestInfo = (RequestInfo) invocation.getArguments()[0]; + int result = (int) invocation.getArguments()[2]; + + assertNotNull(requestInfo); + assertEquals(result, LineageWeatherManager.RequestStatus.FAILED); + + latch.countDown(); + return null; + } + }).when(client) + .setServiceRequestState(Mockito.any(RequestInfo.class), + Mockito.any(ServiceRequestResult.class), + Mockito.eq(LineageWeatherManager.RequestStatus.FAILED)); + + Mockito.doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + + RequestInfo requestInfo = (RequestInfo) invocation.getArguments()[0]; + int result = (int) invocation.getArguments()[2]; + + assertNotNull(requestInfo); + assertEquals(result, LineageWeatherManager.RequestStatus.SUBMITTED_TOO_SOON); + + latch.countDown(); + return null; + } + }).when(client) + .setServiceRequestState(Mockito.any(RequestInfo.class), + Mockito.any(ServiceRequestResult.class), + Mockito.eq(LineageWeatherManager.RequestStatus.SUBMITTED_TOO_SOON)); + + Mockito.doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + RequestInfo requestInfo = (RequestInfo) invocation.getArguments()[0]; + ServiceRequestResult requestResult + = (ServiceRequestResult) invocation.getArguments()[1]; + int result = (int) invocation.getArguments()[2]; + + assertNotNull(requestInfo); + assertNotNull(requestResult); + assertNotNull(requestResult.getLocationLookupList()); + assertEquals(result, LineageWeatherManager.RequestStatus.COMPLETED); + + latch.countDown(); + return null; + } + }).when(client) + .setServiceRequestState(Mockito.any(RequestInfo.class), + Mockito.any(ServiceRequestResult.class), + Mockito.eq(LineageWeatherManager.RequestStatus.COMPLETED)); + + provider.setServiceClient(client); + + final RequestInfo requestInfo + = buildMockdRequestInfo(RequestInfo.TYPE_LOOKUP_CITY_NAME_REQ); + + Mockito.reset(getService().getCallTracker()); + provider.processCityNameLookupRequest(requestInfo); + runOnServiceThread(new Runnable() { + @Override + public void run() { + ArgumentCaptor<ServiceRequest> params + = ArgumentCaptor.forClass(ServiceRequest.class); + + Mockito.verify(getService().getCallTracker(), Mockito.timeout(TIMEOUT).times(1)) + .onRequestSubmitted(params.capture()); + + ServiceRequest request = params.getValue(); + request.fail(); + } + }); + + Mockito.reset(getService().getCallTracker()); + provider.processCityNameLookupRequest(requestInfo); + runOnServiceThread(new Runnable() { + @Override + public void run() { + ArgumentCaptor<ServiceRequest> params + = ArgumentCaptor.forClass(ServiceRequest.class); + + Mockito.verify(getService().getCallTracker(), Mockito.timeout(TIMEOUT).times(1)) + .onRequestSubmitted(params.capture()); + + ServiceRequest request = params.getValue(); + request.reject(LineageWeatherManager.RequestStatus.SUBMITTED_TOO_SOON); + } + }); + + Mockito.reset(getService().getCallTracker()); + provider.processCityNameLookupRequest(requestInfo); + runOnServiceThread(new Runnable() { + @Override + public void run() { + ArgumentCaptor<ServiceRequest> params + = ArgumentCaptor.forClass(ServiceRequest.class); + + Mockito.verify(getService().getCallTracker(), Mockito.timeout(TIMEOUT).times(1)) + .onRequestSubmitted(params.capture()); + + ServiceRequest request = params.getValue(); + + List<WeatherLocation> locations = new ArrayList<>(); + locations.add(new WeatherLocation.Builder(CITY_NAME).build()); + ServiceRequestResult result = new ServiceRequestResult.Builder(locations).build(); + request.complete(result); + } + }); + + try { + latch.await(); + } catch (InterruptedException e) { + throw new AssertionError(e); + } + + } + + private RequestInfo buildMockdRequestInfo(int requestType) { + try { + Constructor<RequestInfo> c = RequestInfo.class.getDeclaredConstructor(); + c.setAccessible(true); + RequestInfo info = c.newInstance(); + Field type; + type = info.getClass().getDeclaredField("mRequestType"); + type.setAccessible(true); + type.set(info, requestType); + switch (requestType) { + case RequestInfo.TYPE_LOOKUP_CITY_NAME_REQ: + Field cityName; + cityName = info.getClass().getDeclaredField("mCityName"); + cityName.setAccessible(true); + cityName.set(info, CITY_NAME); + break; + case RequestInfo.TYPE_WEATHER_BY_WEATHER_LOCATION_REQ: + Field weatherLocation; + weatherLocation = info.getClass().getDeclaredField("mWeatherLocation"); + weatherLocation.setAccessible(true); + weatherLocation.set(info, new WeatherLocation.Builder(CITY_NAME).build()); + break; + case RequestInfo.TYPE_WEATHER_BY_GEO_LOCATION_REQ: + Field location; + location = info.getClass().getDeclaredField("mLocation"); + location.setAccessible(true); + location.set(info, new Location("dummy_location_provider")); + break; + default: + throw new AssertionError("Unknown request type"); + } + return info; + } catch (Exception e) { + throw new AssertionError(e); + } + } +} |