mirror of
				https://github.com/TeamNewPipe/NewPipe
				synced 2025-10-31 07:13:00 +00:00 
			
		
		
		
	Merge pull request #5358 from XiangRongLin/testable_prettytime
Make Localization.relativeTime testable
This commit is contained in:
		| @@ -6,16 +6,26 @@ import android.content.Context; | |||||||
| import android.content.SharedPreferences; | import android.content.SharedPreferences; | ||||||
| import android.os.Build; | import android.os.Build; | ||||||
| import android.util.Log; | import android.util.Log; | ||||||
|  |  | ||||||
| import androidx.annotation.NonNull; | import androidx.annotation.NonNull; | ||||||
| import androidx.annotation.Nullable; | import androidx.annotation.Nullable; | ||||||
| import androidx.multidex.MultiDexApplication; | import androidx.multidex.MultiDexApplication; | ||||||
| import androidx.preference.PreferenceManager; | import androidx.preference.PreferenceManager; | ||||||
|  |  | ||||||
| import com.nostra13.universalimageloader.cache.memory.impl.LRULimitedMemoryCache; | import com.nostra13.universalimageloader.cache.memory.impl.LRULimitedMemoryCache; | ||||||
| import com.nostra13.universalimageloader.core.ImageLoader; | import com.nostra13.universalimageloader.core.ImageLoader; | ||||||
| import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; | import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; | ||||||
|  | import io.reactivex.rxjava3.disposables.Disposable; | ||||||
|  | import io.reactivex.rxjava3.exceptions.CompositeException; | ||||||
|  | import io.reactivex.rxjava3.exceptions.MissingBackpressureException; | ||||||
|  | import io.reactivex.rxjava3.exceptions.OnErrorNotImplementedException; | ||||||
|  | import io.reactivex.rxjava3.exceptions.UndeliverableException; | ||||||
|  | import io.reactivex.rxjava3.functions.Consumer; | ||||||
|  | import io.reactivex.rxjava3.plugins.RxJavaPlugins; | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.io.InterruptedIOException; | ||||||
|  | import java.net.SocketException; | ||||||
|  | import java.util.Arrays; | ||||||
|  | import java.util.Collections; | ||||||
|  | import java.util.List; | ||||||
| import org.acra.ACRA; | import org.acra.ACRA; | ||||||
| import org.acra.config.ACRAConfigurationException; | import org.acra.config.ACRAConfigurationException; | ||||||
| import org.acra.config.CoreConfiguration; | import org.acra.config.CoreConfiguration; | ||||||
| @@ -31,21 +41,6 @@ import org.schabi.newpipe.util.Localization; | |||||||
| import org.schabi.newpipe.util.ServiceHelper; | import org.schabi.newpipe.util.ServiceHelper; | ||||||
| import org.schabi.newpipe.util.StateSaver; | import org.schabi.newpipe.util.StateSaver; | ||||||
|  |  | ||||||
| import java.io.IOException; |  | ||||||
| import java.io.InterruptedIOException; |  | ||||||
| import java.net.SocketException; |  | ||||||
| import java.util.Arrays; |  | ||||||
| import java.util.Collections; |  | ||||||
| import java.util.List; |  | ||||||
|  |  | ||||||
| import io.reactivex.rxjava3.disposables.Disposable; |  | ||||||
| import io.reactivex.rxjava3.exceptions.CompositeException; |  | ||||||
| import io.reactivex.rxjava3.exceptions.MissingBackpressureException; |  | ||||||
| import io.reactivex.rxjava3.exceptions.OnErrorNotImplementedException; |  | ||||||
| import io.reactivex.rxjava3.exceptions.UndeliverableException; |  | ||||||
| import io.reactivex.rxjava3.functions.Consumer; |  | ||||||
| import io.reactivex.rxjava3.plugins.RxJavaPlugins; |  | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * Copyright (C) Hans-Christoph Steiner 2016 <hans@eds.org> |  * Copyright (C) Hans-Christoph Steiner 2016 <hans@eds.org> | ||||||
|  * App.java is part of NewPipe. |  * App.java is part of NewPipe. | ||||||
| @@ -93,9 +88,9 @@ public class App extends MultiDexApplication { | |||||||
|         SettingsActivity.initSettings(this); |         SettingsActivity.initSettings(this); | ||||||
|  |  | ||||||
|         NewPipe.init(getDownloader(), |         NewPipe.init(getDownloader(), | ||||||
|                 Localization.getPreferredLocalization(this), |             Localization.getPreferredLocalization(this), | ||||||
|                 Localization.getPreferredContentCountry(this)); |             Localization.getPreferredContentCountry(this)); | ||||||
|         Localization.init(getApplicationContext()); |         Localization.initPrettyTime(Localization.resolvePrettyTime(getApplicationContext())); | ||||||
|  |  | ||||||
|         StateSaver.init(this); |         StateSaver.init(this); | ||||||
|         initNotificationChannels(); |         initNotificationChannels(); | ||||||
|   | |||||||
| @@ -20,6 +20,8 @@ | |||||||
|  |  | ||||||
| package org.schabi.newpipe; | package org.schabi.newpipe; | ||||||
|  |  | ||||||
|  | import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage; | ||||||
|  |  | ||||||
| import android.content.BroadcastReceiver; | import android.content.BroadcastReceiver; | ||||||
| import android.content.Context; | import android.content.Context; | ||||||
| import android.content.Intent; | import android.content.Intent; | ||||||
| @@ -41,7 +43,6 @@ import android.widget.AdapterView; | |||||||
| import android.widget.ArrayAdapter; | import android.widget.ArrayAdapter; | ||||||
| import android.widget.FrameLayout; | import android.widget.FrameLayout; | ||||||
| import android.widget.Spinner; | import android.widget.Spinner; | ||||||
|  |  | ||||||
| import androidx.annotation.NonNull; | import androidx.annotation.NonNull; | ||||||
| import androidx.appcompat.app.ActionBar; | import androidx.appcompat.app.ActionBar; | ||||||
| import androidx.appcompat.app.ActionBarDrawerToggle; | import androidx.appcompat.app.ActionBarDrawerToggle; | ||||||
| @@ -52,9 +53,10 @@ import androidx.drawerlayout.widget.DrawerLayout; | |||||||
| import androidx.fragment.app.Fragment; | import androidx.fragment.app.Fragment; | ||||||
| import androidx.fragment.app.FragmentManager; | import androidx.fragment.app.FragmentManager; | ||||||
| import androidx.preference.PreferenceManager; | import androidx.preference.PreferenceManager; | ||||||
|  |  | ||||||
| import com.google.android.material.bottomsheet.BottomSheetBehavior; | import com.google.android.material.bottomsheet.BottomSheetBehavior; | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Objects; | ||||||
| import org.schabi.newpipe.databinding.ActivityMainBinding; | import org.schabi.newpipe.databinding.ActivityMainBinding; | ||||||
| import org.schabi.newpipe.databinding.DrawerHeaderBinding; | import org.schabi.newpipe.databinding.DrawerHeaderBinding; | ||||||
| import org.schabi.newpipe.databinding.DrawerLayoutBinding; | import org.schabi.newpipe.databinding.DrawerLayoutBinding; | ||||||
| @@ -87,12 +89,6 @@ import org.schabi.newpipe.util.TLSSocketFactoryCompat; | |||||||
| import org.schabi.newpipe.util.ThemeHelper; | import org.schabi.newpipe.util.ThemeHelper; | ||||||
| import org.schabi.newpipe.views.FocusOverlayView; | import org.schabi.newpipe.views.FocusOverlayView; | ||||||
|  |  | ||||||
| import java.util.ArrayList; |  | ||||||
| import java.util.List; |  | ||||||
| import java.util.Objects; |  | ||||||
|  |  | ||||||
| import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage; |  | ||||||
|  |  | ||||||
| public class MainActivity extends AppCompatActivity { | public class MainActivity extends AppCompatActivity { | ||||||
|     private static final String TAG = "MainActivity"; |     private static final String TAG = "MainActivity"; | ||||||
|     public static final boolean DEBUG = !BuildConfig.BUILD_TYPE.equals("release"); |     public static final boolean DEBUG = !BuildConfig.BUILD_TYPE.equals("release"); | ||||||
| @@ -468,7 +464,7 @@ public class MainActivity extends AppCompatActivity { | |||||||
|     protected void onResume() { |     protected void onResume() { | ||||||
|         assureCorrectAppLanguage(this); |         assureCorrectAppLanguage(this); | ||||||
|         // Change the date format to match the selected language on resume |         // Change the date format to match the selected language on resume | ||||||
|         Localization.init(getApplicationContext()); |         Localization.initPrettyTime(Localization.resolvePrettyTime(getApplicationContext())); | ||||||
|         super.onResume(); |         super.onResume(); | ||||||
|  |  | ||||||
|         // Close drawer on return, and don't show animation, |         // Close drawer on return, and don't show animation, | ||||||
|   | |||||||
| @@ -9,19 +9,10 @@ import android.icu.text.CompactDecimalFormat; | |||||||
| import android.os.Build; | import android.os.Build; | ||||||
| import android.text.TextUtils; | import android.text.TextUtils; | ||||||
| import android.util.DisplayMetrics; | import android.util.DisplayMetrics; | ||||||
|  |  | ||||||
| import androidx.annotation.NonNull; | import androidx.annotation.NonNull; | ||||||
| import androidx.annotation.PluralsRes; | import androidx.annotation.PluralsRes; | ||||||
| import androidx.annotation.StringRes; | import androidx.annotation.StringRes; | ||||||
| import androidx.preference.PreferenceManager; | import androidx.preference.PreferenceManager; | ||||||
|  |  | ||||||
| import org.ocpsoft.prettytime.PrettyTime; |  | ||||||
| import org.ocpsoft.prettytime.units.Decade; |  | ||||||
| import org.schabi.newpipe.R; |  | ||||||
| import org.schabi.newpipe.extractor.ListExtractor; |  | ||||||
| import org.schabi.newpipe.extractor.localization.ContentCountry; |  | ||||||
| import org.schabi.newpipe.ktx.OffsetDateTimeKt; |  | ||||||
|  |  | ||||||
| import java.math.BigDecimal; | import java.math.BigDecimal; | ||||||
| import java.math.RoundingMode; | import java.math.RoundingMode; | ||||||
| import java.text.NumberFormat; | import java.text.NumberFormat; | ||||||
| @@ -33,6 +24,12 @@ import java.util.Arrays; | |||||||
| import java.util.Calendar; | import java.util.Calendar; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.Locale; | import java.util.Locale; | ||||||
|  | import org.ocpsoft.prettytime.PrettyTime; | ||||||
|  | import org.ocpsoft.prettytime.units.Decade; | ||||||
|  | import org.schabi.newpipe.R; | ||||||
|  | import org.schabi.newpipe.extractor.ListExtractor; | ||||||
|  | import org.schabi.newpipe.extractor.localization.ContentCountry; | ||||||
|  | import org.schabi.newpipe.ktx.OffsetDateTimeKt; | ||||||
|  |  | ||||||
|  |  | ||||||
| /* | /* | ||||||
| @@ -62,10 +59,6 @@ public final class Localization { | |||||||
|  |  | ||||||
|     private Localization() { } |     private Localization() { } | ||||||
|  |  | ||||||
|     public static void init(final Context context) { |  | ||||||
|         initPrettyTime(context); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @NonNull |     @NonNull | ||||||
|     public static String concatenateStrings(final String... strings) { |     public static String concatenateStrings(final String... strings) { | ||||||
|         return concatenateStrings(Arrays.asList(strings)); |         return concatenateStrings(Arrays.asList(strings)); | ||||||
| @@ -307,12 +300,16 @@ public final class Localization { | |||||||
|     // Pretty Time |     // Pretty Time | ||||||
|     //////////////////////////////////////////////////////////////////////////*/ |     //////////////////////////////////////////////////////////////////////////*/ | ||||||
|  |  | ||||||
|     private static void initPrettyTime(final Context context) { |     public static void initPrettyTime(final PrettyTime time) { | ||||||
|         prettyTime = new PrettyTime(getAppLocale(context)); |         prettyTime = time; | ||||||
|         // Do not use decades as YouTube doesn't either. |         // Do not use decades as YouTube doesn't either. | ||||||
|         prettyTime.removeUnit(Decade.class); |         prettyTime.removeUnit(Decade.class); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public static PrettyTime resolvePrettyTime(final Context context) { | ||||||
|  |         return new PrettyTime(getAppLocale(context)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     public static String relativeTime(final OffsetDateTime offsetDateTime) { |     public static String relativeTime(final OffsetDateTime offsetDateTime) { | ||||||
|         return relativeTime(OffsetDateTimeKt.toCalendar(offsetDateTime)); |         return relativeTime(OffsetDateTimeKt.toCalendar(offsetDateTime)); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -0,0 +1,40 @@ | |||||||
|  | package org.schabi.newpipe.util | ||||||
|  |  | ||||||
|  | import org.junit.Assert.assertEquals | ||||||
|  | import org.junit.Test | ||||||
|  | import org.ocpsoft.prettytime.PrettyTime | ||||||
|  | import java.text.SimpleDateFormat | ||||||
|  | import java.time.OffsetDateTime | ||||||
|  | import java.time.ZoneOffset | ||||||
|  | import java.util.GregorianCalendar | ||||||
|  | import java.util.Locale | ||||||
|  |  | ||||||
|  | class LocalizationTest { | ||||||
|  |  | ||||||
|  |     @Test | ||||||
|  |     fun `After initializing pretty time relativeTime() with a Calendar must work`() { | ||||||
|  |         val reference = SimpleDateFormat("yyyy/MM/dd").parse("2021/1/1") | ||||||
|  |         Localization.initPrettyTime(PrettyTime(reference, Locale.ENGLISH)) | ||||||
|  |  | ||||||
|  |         val actual = Localization.relativeTime(GregorianCalendar(2021, 1, 6)) | ||||||
|  |  | ||||||
|  |         // yes this assertion is true, even if it should be 5 days, it works as it is. Future research required. | ||||||
|  |         assertEquals("1 month from now", actual) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Test(expected = NullPointerException::class) | ||||||
|  |     fun `relativeTime() must fail without initializing pretty time`() { | ||||||
|  |         Localization.relativeTime(GregorianCalendar(2021, 1, 6)) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Test | ||||||
|  |     fun `relativeTime() with a OffsetDateTime must work`() { | ||||||
|  |         val reference = SimpleDateFormat("yyyy/MM/dd").parse("2021/1/1") | ||||||
|  |         Localization.initPrettyTime(PrettyTime(reference, Locale.ENGLISH)) | ||||||
|  |  | ||||||
|  |         val offset = OffsetDateTime.of(2021, 1, 6, 0, 0, 0, 0, ZoneOffset.UTC) | ||||||
|  |         val actual = Localization.relativeTime(offset) | ||||||
|  |  | ||||||
|  |         assertEquals("5 days from now", actual) | ||||||
|  |     } | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user
	 Robin
					Robin