Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 27808673 authored by Neil Fuller's avatar Neil Fuller
Browse files

Extract support code for NitzStateMachine tests

Extract utility methods / classes for NitzStateMachine tests;
with two implementations likely to exist for R it makes sense to extract
common code to avoid unnecessary duplication.

Bug: 140712361
Test: atest com.android.internal.telephony.NitzStateMachineImplTest
Change-Id: Id77c2dc57004d4869e234c0432efae7e5d2f5f6a
parent 7662ffbb
Loading
Loading
Loading
Loading
+35 −204
Original line number Diff line number Diff line
@@ -16,18 +16,21 @@

package com.android.internal.telephony;

import static com.android.internal.telephony.NitzStateMachineTestSupport.createTimeSignalFromNitzSignal;
import static com.android.internal.telephony.NitzStateMachineTestSupport.createUtcTime;
import static com.android.internal.telephony.NitzStateMachineTestSupport.zone;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import android.icu.util.Calendar;
import android.icu.util.GregorianCalendar;
import android.icu.util.TimeZone;
import android.util.TimestampedValue;

import com.android.internal.telephony.NitzStateMachine.DeviceState;
import com.android.internal.telephony.NitzStateMachineTestSupport.FakeDeviceState;
import com.android.internal.telephony.NitzStateMachineTestSupport.Scenario;
import com.android.internal.telephony.TimeZoneLookupHelper.CountryResult;
import com.android.internal.telephony.TimeZoneLookupHelper.OffsetResult;

@@ -748,63 +751,6 @@ public class NitzStateMachineImplTest extends TelephonyTest {
                TimeZone.getTimeZone(zoneId2).getOffset(timeMillis));
    }

    private static long createUtcTime(int year, int monthInYear, int day, int hourOfDay, int minute,
            int second) {
        Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("Etc/UTC"));
        cal.clear();
        cal.set(year, monthInYear - 1, day, hourOfDay, minute, second);
        return cal.getTimeInMillis();
    }

    /** Some piece of state that tests want to track. */
    private static class TestState<T> {
        private T mInitialValue;
        private LinkedList<T> mValues = new LinkedList<>();

        void init(T value) {
            mValues.clear();
            mInitialValue = value;
        }

        void set(T value) {
            mValues.addFirst(value);
        }

        boolean hasBeenSet() {
            return mValues.size() > 0;
        }

        void assertHasNotBeenSet() {
            assertFalse(hasBeenSet());
        }

        void assertHasBeenSet() {
            assertTrue(hasBeenSet());
        }

        void commitLatest() {
            if (hasBeenSet()) {
                mInitialValue = mValues.getLast();
                mValues.clear();
            }
        }

        void assertLatestEquals(T expected) {
            assertEquals(expected, getLatest());
        }

        void assertChangeCount(int expectedCount) {
            assertEquals(expectedCount, mValues.size());
        }

        public T getLatest() {
            if (hasBeenSet()) {
                return mValues.getFirst();
            }
            return mInitialValue;
        }
    }

    /**
     * A "fluent" helper class allowing reuse of logic for test state initialization, simulation of
     * events, and verification of device state changes with self-describing method names.
@@ -924,129 +870,56 @@ public class NitzStateMachineImplTest extends TelephonyTest {
        }
    }

    private static TimestampedValue<Long> createTimeSignalFromNitzSignal(
            TimestampedValue<NitzData> nitzSignal) {
        return new TimestampedValue<>(
                nitzSignal.getReferenceTimeMillis(),
                nitzSignal.getValue().getCurrentTimeInMillis());
    }

    /**
     * A scenario used during tests. Describes a fictional reality.
     */
    static class Scenario {

        private final boolean mFrozen;
        private TimeZone mZone;
        private String mNetworkCountryIsoCode;
        private long mElapsedRealtimeMillis;
        private long mActualTimeMillis;

        Scenario(boolean frozen, long elapsedRealtimeMillis, long timeMillis, String zoneId,
                String countryIsoCode) {
            mFrozen = frozen;
            mActualTimeMillis = timeMillis;
            mElapsedRealtimeMillis = elapsedRealtimeMillis;
            mZone = zone(zoneId);
            mNetworkCountryIsoCode = countryIsoCode;
        }

        /** Creates an NITZ signal to match the scenario. */
        TimestampedValue<NitzData> createNitzSignal() {
            int[] offsets = new int[2];
            mZone.getOffset(mActualTimeMillis, false /* local */, offsets);
            int zoneOffsetMillis = offsets[0] + offsets[1];
            NitzData nitzData = NitzData.createForTests(
                    zoneOffsetMillis, offsets[1], mActualTimeMillis,
                    null /* emulatorHostTimeZone */);
            return new TimestampedValue<>(mElapsedRealtimeMillis, nitzData);
        }

        /** Creates a time signal to match the scenario. */
        TimestampedValue<Long> createTimeSignal() {
            return new TimestampedValue<>(mElapsedRealtimeMillis, mActualTimeMillis);
        }

        long getDeviceRealTimeMillis() {
            return mElapsedRealtimeMillis;
        }

        String getNetworkCountryIsoCode() {
            return mNetworkCountryIsoCode;
        }

        String getTimeZoneId() {
            return mZone.getID();
        }
    /** Some piece of state that tests want to track. */
    private static class TestState<T> {
        private T mInitialValue;
        private LinkedList<T> mValues = new LinkedList<>();

        long getActualTimeMillis() {
            return mActualTimeMillis;
        void init(T value) {
            mValues.clear();
            mInitialValue = value;
        }

        Scenario incrementTime(long timeIncrementMillis) {
            checkFrozen();
            mElapsedRealtimeMillis += timeIncrementMillis;
            mActualTimeMillis += timeIncrementMillis;
            return this;
        void set(T value) {
            mValues.addFirst(value);
        }

        Scenario changeCountry(String timeZoneId, String networkCountryIsoCode) {
            checkFrozen();
            mZone = zone(timeZoneId);
            mNetworkCountryIsoCode = networkCountryIsoCode;
            return this;
        boolean hasBeenSet() {
            return mValues.size() > 0;
        }

        Scenario mutableCopy() {
            return new Scenario(
                    false /* frozen */, mElapsedRealtimeMillis, mActualTimeMillis, mZone.getID(),
                    mNetworkCountryIsoCode);
        void assertHasNotBeenSet() {
            assertFalse(hasBeenSet());
        }

        private void checkFrozen() {
            if (mFrozen) {
                throw new IllegalStateException("Scenario is frozen. Copy first");
            }
        void assertHasBeenSet() {
            assertTrue(hasBeenSet());
        }

        static class Builder {

            private long mInitialDeviceRealtimeMillis;
            private long mActualTimeMillis;
            private String mZoneId;
            private String mCountryIsoCode;

            Builder setDeviceRealtimeMillis(long realtimeMillis) {
                mInitialDeviceRealtimeMillis = realtimeMillis;
                return this;
        void commitLatest() {
            if (hasBeenSet()) {
                mInitialValue = mValues.getLast();
                mValues.clear();
            }

            Builder setActualTimeUtc(int year, int monthInYear, int day, int hourOfDay,
                    int minute, int second) {
                mActualTimeMillis = createUtcTime(year, monthInYear, day, hourOfDay, minute,
                        second);
                return this;
        }

            Builder setTimeZone(String zoneId) {
                mZoneId = zoneId;
                return this;
        void assertLatestEquals(T expected) {
            assertEquals(expected, getLatest());
        }

            Builder setCountryIso(String isoCode) {
                mCountryIsoCode = isoCode;
                return this;
        void assertChangeCount(int expectedCount) {
            assertEquals(expectedCount, mValues.size());
        }

            Scenario buildFrozen() {
                return new Scenario(
                        true /* frozen */, mInitialDeviceRealtimeMillis, mActualTimeMillis, mZoneId,
                        mCountryIsoCode);
        public T getLatest() {
            if (hasBeenSet()) {
                return mValues.getFirst();
            }
            return mInitialValue;
        }
    }

    private class FakeTimeServiceHelper implements TimeServiceHelper {
    private static class FakeTimeServiceHelper implements TimeServiceHelper {

        public TimeServiceHelper.Listener listener;
        public boolean timeZoneDetectionEnabled;
@@ -1093,46 +966,4 @@ public class NitzStateMachineImplTest extends TelephonyTest {
            suggestedTime.commitLatest();
        }
    }

    private static class FakeDeviceState implements DeviceState {

        public boolean ignoreNitz;
        public int nitzUpdateDiffMillis;
        public int nitzUpdateSpacingMillis;
        public String networkCountryIsoForPhone;
        public long elapsedRealtime;

        @Override
        public int getNitzUpdateSpacingMillis() {
            return nitzUpdateSpacingMillis;
        }

        @Override
        public int getNitzUpdateDiffMillis() {
            return nitzUpdateDiffMillis;
        }

        @Override
        public boolean getIgnoreNitz() {
            return ignoreNitz;
        }

        @Override
        public String getNetworkCountryIsoForPhone() {
            return networkCountryIsoForPhone;
        }

        @Override
        public long elapsedRealtime() {
            return elapsedRealtime;
        }
    }

    private static TimeZone zone(String zoneId) {
        TimeZone timeZone = TimeZone.getFrozenTimeZone(zoneId);
        if (timeZone.getID().equals(TimeZone.UNKNOWN_ZONE_ID)) {
            fail(zoneId + " is not a valid zone");
        }
        return timeZone;
    }
}
+207 −0
Original line number Diff line number Diff line
/*
 * Copyright 2019 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 com.android.internal.telephony;

import static org.junit.Assert.fail;

import android.icu.util.Calendar;
import android.icu.util.GregorianCalendar;
import android.icu.util.TimeZone;
import android.util.TimestampedValue;

import com.android.internal.telephony.NitzStateMachine.DeviceState;

/**
 * An assortment of methods and classes for testing {@link NitzStateMachine} implementations.
 */
final class NitzStateMachineTestSupport {

    /**
     * A scenario used during tests. Describes a fictional reality.
     */
    static class Scenario {

        private final boolean mFrozen;
        private TimeZone mZone;
        private String mNetworkCountryIsoCode;
        private long mElapsedRealtimeMillis;
        private long mActualTimeMillis;

        Scenario(boolean frozen, long elapsedRealtimeMillis, long timeMillis, String zoneId,
                String countryIsoCode) {
            mFrozen = frozen;
            mActualTimeMillis = timeMillis;
            mElapsedRealtimeMillis = elapsedRealtimeMillis;
            mZone = zone(zoneId);
            mNetworkCountryIsoCode = countryIsoCode;
        }

        /** Creates an NITZ signal to match the scenario. */
        TimestampedValue<NitzData> createNitzSignal() {
            int[] offsets = new int[2];
            mZone.getOffset(mActualTimeMillis, false /* local */, offsets);
            int zoneOffsetMillis = offsets[0] + offsets[1];
            NitzData nitzData = NitzData.createForTests(
                    zoneOffsetMillis, offsets[1], mActualTimeMillis,
                    null /* emulatorHostTimeZone */);
            return new TimestampedValue<>(mElapsedRealtimeMillis, nitzData);
        }

        /** Creates a time signal to match the scenario. */
        TimestampedValue<Long> createTimeSignal() {
            return new TimestampedValue<>(mElapsedRealtimeMillis, mActualTimeMillis);
        }

        long getDeviceRealTimeMillis() {
            return mElapsedRealtimeMillis;
        }

        String getNetworkCountryIsoCode() {
            return mNetworkCountryIsoCode;
        }

        String getTimeZoneId() {
            return mZone.getID();
        }

        long getActualTimeMillis() {
            return mActualTimeMillis;
        }

        Scenario incrementTime(long timeIncrementMillis) {
            checkFrozen();
            mElapsedRealtimeMillis += timeIncrementMillis;
            mActualTimeMillis += timeIncrementMillis;
            return this;
        }

        Scenario changeCountry(String timeZoneId, String networkCountryIsoCode) {
            checkFrozen();
            mZone = zone(timeZoneId);
            mNetworkCountryIsoCode = networkCountryIsoCode;
            return this;
        }

        Scenario mutableCopy() {
            return new Scenario(
                    false /* frozen */, mElapsedRealtimeMillis, mActualTimeMillis, mZone.getID(),
                    mNetworkCountryIsoCode);
        }

        private void checkFrozen() {
            if (mFrozen) {
                throw new IllegalStateException("Scenario is frozen. Copy first");
            }
        }

        static class Builder {

            private long mInitialDeviceRealtimeMillis;
            private long mActualTimeMillis;
            private String mZoneId;
            private String mCountryIsoCode;

            Builder setDeviceRealtimeMillis(long realtimeMillis) {
                mInitialDeviceRealtimeMillis = realtimeMillis;
                return this;
            }

            Builder setActualTimeUtc(int year, int monthInYear, int day, int hourOfDay,
                    int minute, int second) {
                mActualTimeMillis = createUtcTime(year, monthInYear, day, hourOfDay, minute,
                        second);
                return this;
            }

            Builder setTimeZone(String zoneId) {
                mZoneId = zoneId;
                return this;
            }

            Builder setCountryIso(String isoCode) {
                mCountryIsoCode = isoCode;
                return this;
            }

            Scenario buildFrozen() {
                return new Scenario(
                        true /* frozen */, mInitialDeviceRealtimeMillis, mActualTimeMillis, mZoneId,
                        mCountryIsoCode);
            }
        }
    }

    /** A fake implementation of {@link DeviceState}. */
    static class FakeDeviceState implements DeviceState {

        public boolean ignoreNitz;
        public int nitzUpdateDiffMillis;
        public int nitzUpdateSpacingMillis;
        public String networkCountryIsoForPhone;
        public long elapsedRealtime;

        @Override
        public int getNitzUpdateSpacingMillis() {
            return nitzUpdateSpacingMillis;
        }

        @Override
        public int getNitzUpdateDiffMillis() {
            return nitzUpdateDiffMillis;
        }

        @Override
        public boolean getIgnoreNitz() {
            return ignoreNitz;
        }

        @Override
        public String getNetworkCountryIsoForPhone() {
            return networkCountryIsoForPhone;
        }

        @Override
        public long elapsedRealtime() {
            return elapsedRealtime;
        }
    }

    private NitzStateMachineTestSupport() {}

    static long createUtcTime(int year, int monthInYear, int day, int hourOfDay, int minute,
            int second) {
        Calendar cal = new GregorianCalendar(zone("Etc/UTC"));
        cal.clear();
        cal.set(year, monthInYear - 1, day, hourOfDay, minute, second);
        return cal.getTimeInMillis();
    }

    static TimestampedValue<Long> createTimeSignalFromNitzSignal(
            TimestampedValue<NitzData> nitzSignal) {
        return new TimestampedValue<>(
                nitzSignal.getReferenceTimeMillis(),
                nitzSignal.getValue().getCurrentTimeInMillis());
    }

    static TimeZone zone(String zoneId) {
        TimeZone timeZone = TimeZone.getFrozenTimeZone(zoneId);
        if (timeZone.getID().equals(TimeZone.UNKNOWN_ZONE_ID)) {
            fail(zoneId + " is not a valid zone");
        }
        return timeZone;
    }
}