mirror of
				https://github.com/commons-app/apps-android-commons.git
				synced 2025-10-31 14:53:59 +01:00 
			
		
		
		
	Testing, Documentation and Cleanup.
This commit is contained in:
		
							parent
							
								
									8fe958e3c6
								
							
						
					
					
						commit
						ea94ea782b
					
				
					 5 changed files with 230 additions and 46 deletions
				
			
		|  | @ -400,35 +400,43 @@ public class OkHttpJsonApiClient { | |||
|     /** | ||||
|      * Retrieves a list of places based on the provided list of places and language. | ||||
|      * | ||||
|      * @param placeList A list of Place objects for which to fetch information. | ||||
|      * @param language  The language code to use for the query. | ||||
|      * @param placeList           A list of Place objects for which to fetch information. | ||||
|      * @param language            The language code to use for the query. | ||||
|      * @param secondaryLanguages  The serialized secondary language code(s) to use for fallback queries. | ||||
|      * @return A list of Place objects with additional information retrieved from Wikidata, or null | ||||
|      * if an error occurs. | ||||
|      *         if an error occurs. | ||||
|      * @throws IOException If there is an issue with reading the resource file or executing the HTTP | ||||
|      *                     request. | ||||
|      */ | ||||
|     @Nullable | ||||
|     public List<Place> getPlaces( | ||||
|         final List<Place> placeList, final String language, final String secondaryLanguages) throws IOException { | ||||
|         final String wikidataQuery = FileUtils.readFromResource("/queries/query_for_item.rq"); | ||||
|         final String[] secondaryLanguageArray = secondaryLanguages.split(",\\s*"); // could be used to generate backup SparQL Queries | ||||
| 
 | ||||
|         // Read the SparQL query template from the resource file | ||||
|         final String wikidataQuery = FileUtils.readFromResource("/queries/query_for_item.rq"); | ||||
| 
 | ||||
|         // Split the secondary languages string into an array to use in fallback queries | ||||
|         final String[] secondaryLanguageArray = secondaryLanguages.split(",\\s*"); | ||||
| 
 | ||||
|         // Prepare the Wikidata entity IDs (QIDs) for each place in the list | ||||
|         String qids = ""; | ||||
|         for (final Place place : placeList) { | ||||
|             qids += "\n" + ("wd:" + place.getWikiDataEntityId()); | ||||
|         } | ||||
| 
 | ||||
|         // Build fallback descriptions for secondary languages in case the primary language is unavailable | ||||
|         StringBuilder fallBackDescription = new StringBuilder(); | ||||
|         for (int i = 0; i < secondaryLanguageArray.length; i++) { | ||||
|             fallBackDescription.append("OPTIONAL {?item schema:description ?itemDescriptionPreferredLanguage_") | ||||
|                 .append(i + 1) | ||||
|                 .append(i + 1)  // Unique identifier for each fallback | ||||
|                 .append(". FILTER (lang(?itemDescriptionPreferredLanguage_") | ||||
|                 .append(i + 1) | ||||
|                 .append(") = \"") | ||||
|                 .append(secondaryLanguageArray[i]) | ||||
|                 .append(secondaryLanguageArray[i])  // Use the secondary language code | ||||
|                 .append("\")}\n"); | ||||
|         } | ||||
| 
 | ||||
|         // Build fallback labels for secondary languages | ||||
|         StringBuilder fallbackLabel = new StringBuilder(); | ||||
|         for (int i = 0; i < secondaryLanguageArray.length; i++) { | ||||
|             fallbackLabel.append("OPTIONAL {?item rdfs:label ?itemLabelPreferredLanguage_") | ||||
|  | @ -440,6 +448,7 @@ public class OkHttpJsonApiClient { | |||
|                 .append("\")}\n"); | ||||
|         } | ||||
| 
 | ||||
|         // Build fallback class labels for secondary languages | ||||
|         StringBuilder fallbackClassLabel = new StringBuilder(); | ||||
|         for (int i = 0; i < secondaryLanguageArray.length; i++) { | ||||
|             fallbackClassLabel.append("OPTIONAL {?class rdfs:label ?classLabelPreferredLanguage_") | ||||
|  | @ -451,6 +460,7 @@ public class OkHttpJsonApiClient { | |||
|                 .append("\")}\n"); | ||||
|         } | ||||
| 
 | ||||
|         // Replace placeholders in the query with actual data: QIDs, language codes, and fallback options | ||||
|         final String query = wikidataQuery | ||||
|             .replace("${ENTITY}", qids) | ||||
|             .replace("${LANG}", language) | ||||
|  | @ -458,33 +468,41 @@ public class OkHttpJsonApiClient { | |||
|             .replace("${SECONDARYLABEL}", fallbackLabel.toString()) | ||||
|             .replace("${SECONDARYCLASSLABEL}", fallbackClassLabel.toString()); | ||||
| 
 | ||||
|         // Build the URL for the SparQL query with the formatted query string | ||||
|         final HttpUrl.Builder urlBuilder = HttpUrl | ||||
|             .parse(sparqlQueryUrl) | ||||
|             .newBuilder() | ||||
|             .addQueryParameter("query", query) | ||||
|             .addQueryParameter("format", "json"); | ||||
|             .addQueryParameter("format", "json");  // Ensure JSON response | ||||
| 
 | ||||
|         // Create and send the HTTP request | ||||
|         final Request request = new Request.Builder() | ||||
|             .url(urlBuilder.build()) | ||||
|             .build(); | ||||
| 
 | ||||
|         // Execute the request and handle the response | ||||
|         try (Response response = okHttpClient.newCall(request).execute()) { | ||||
|             if (response.isSuccessful()) { | ||||
|                 // Parse the JSON response and convert it to a list of NearbyResultItems | ||||
|                 final String json = response.body().string(); | ||||
|                 final NearbyResponse nearbyResponse = gson.fromJson(json, NearbyResponse.class); | ||||
|                 final List<NearbyResultItem> bindings = nearbyResponse.getResults().getBindings(); | ||||
| 
 | ||||
|                 // Convert each NearbyResultItem into a Place object and return the list of places | ||||
|                 final List<Place> places = new ArrayList<>(); | ||||
|                 for (final NearbyResultItem item : bindings) { | ||||
|                     final Place placeFromNearbyItem = Place.from(item); | ||||
|                     places.add(placeFromNearbyItem); | ||||
|                 } | ||||
|                 return places; | ||||
|                 return places;  // Return the list of places with additional information | ||||
|             } else { | ||||
|                 // Handle unsuccessful HTTP response codes | ||||
|                 throw new IOException("Unexpected response code: " + response.code()); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     /** | ||||
|      * Make API Call to get Places | ||||
|      * | ||||
|  |  | |||
|  | @ -127,6 +127,7 @@ public class NearbyPlaces { | |||
|      * | ||||
|      * @param placeList A list of Place objects for which to fetch information. | ||||
|      * @param lang      The language code to use for the query. | ||||
|      * @param lang2      The serialised secondary language code to use for the query. | ||||
|      * @return A list of Place objects obtained from the Wikidata query. | ||||
|      * @throws Exception If an error occurs during the retrieval process. | ||||
|      */ | ||||
|  |  | |||
|  | @ -290,6 +290,13 @@ public class SettingsFragment extends PreferenceFragmentCompat { | |||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Updates the ListView to display saved languages using the SavedLanguagesAdapter. | ||||
|      * | ||||
|      * @param savedLanguageListView  The ListView that will display the saved languages. | ||||
|      * @param savedLanguages         A list of saved Language objects to be displayed. | ||||
|      * @param selectedLanguages      A HashMap containing the selected language IDs and their corresponding names. | ||||
|      */ | ||||
|     private void updateSavedLanguages(ListView savedLanguageListView, List<Language> savedLanguages, HashMap<Integer, String> selectedLanguages) { | ||||
|         // Use SavedLanguagesAdapter to display saved languages | ||||
|         SavedLanguagesAdapter savedLanguagesAdapter = new SavedLanguagesAdapter( | ||||
|  | @ -302,6 +309,12 @@ public class SettingsFragment extends PreferenceFragmentCompat { | |||
|         savedLanguageListView.setAdapter(savedLanguagesAdapter); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Deserializes a comma-separated string of language codes into an ArrayList of strings. | ||||
|      * | ||||
|      * @param languageCodes  A string containing language codes separated by commas. | ||||
|      * @return               An ArrayList of language codes, or an empty ArrayList if the input is null or empty. | ||||
|      */ | ||||
|     private ArrayList<String> deSerialise(String languageCodes) { | ||||
|         // Check if the stored string is empty or null | ||||
|         if (languageCodes == null || languageCodes.isEmpty()) { | ||||
|  | @ -313,21 +326,21 @@ public class SettingsFragment extends PreferenceFragmentCompat { | |||
|         return new ArrayList<>(Arrays.asList(languageArray));  // Convert array to ArrayList and return | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     /** | ||||
|      * Prepare and Show language selection dialog box | ||||
|      * Disable default/already selected language from dialog box | ||||
|      * Saves values chosen by user to shared preferences as a serialised string. | ||||
|      */ | ||||
|     private void prepareSecondaryLanguageDialog() { | ||||
|         final String languageCode = getCurrentLanguageCode("descriptionSecondaryLanguagePref"); | ||||
|         HashMap<Integer, String> selectedLanguages = new HashMap<>(); | ||||
|         assert languageCode != null; | ||||
|         selectedLanguages.put(0, Locale.getDefault().getLanguage()); | ||||
|         System.out.println(Locale.getDefault().getLanguage()); | ||||
|         System.out.println(languageCode); | ||||
| 
 | ||||
|         // Deserializing saved language codes to Language objects | ||||
|         ArrayList<Language> savedLanguages = new ArrayList<>(); | ||||
|         for (String code : deSerialise(languageCode)) { | ||||
|             System.out.println(code); | ||||
|             if(code.equals(Locale.getDefault().getLanguage())){ | ||||
|                 System.out.println("match"); | ||||
|                 continue; | ||||
|             } | ||||
|             Locale locale = new Locale(code); | ||||
|  | @ -633,42 +646,10 @@ public class SettingsFragment extends PreferenceFragmentCompat { | |||
|         separator.setVisibility(View.GONE); | ||||
|     } | ||||
| 
 | ||||
|     private String reSerialise(ArrayList<String> languageCodes) { | ||||
|         // Join the elements of the list into a single string, separated by a comma and a space | ||||
|         return String.join(", ", languageCodes); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Changing the default app language with selected one and save it to SharedPreferences | ||||
|      */ | ||||
|     public void setLocale(final Activity activity, String userSelectedValue) { | ||||
| //        if (userSelectedValue.equals("")) { | ||||
| //            userSelectedValue = Locale.getDefault().getLanguage(); | ||||
| //        } | ||||
| // | ||||
| //        String current = Locale.getDefault().getLanguage(); | ||||
| //        ArrayList<String> languageCodes = deSerialise(current); | ||||
| //        if(appUI) { | ||||
| //            languageCodes.set(0, userSelectedValue); | ||||
| //            userSelectedValue = reSerialise(languageCodes); | ||||
| //            } | ||||
| //        else{ | ||||
| //            ArrayList<String> newLanguageCodes = new ArrayList<>(); | ||||
| //            ArrayList<String> userSelctedCode = deSerialise(userSelectedValue); | ||||
| // | ||||
| //            newLanguageCodes.add(languageCodes.get(0)); | ||||
| //            for(String code : userSelctedCode){ | ||||
| //                newLanguageCodes.add(code); | ||||
| //            } | ||||
| //            userSelectedValue = reSerialise(newLanguageCodes); | ||||
| //        } | ||||
| // | ||||
| //        System.out.println("Final locale"); | ||||
| //        System.out.println(userSelectedValue); | ||||
| // | ||||
| //        System.out.println("vs"); | ||||
| //        System.out.println(getCurrentLanguageCode("appUiDefaultLanguagePref")); | ||||
| //        System.out.println(getCurrentLanguageCode("descriptionSecondaryLanguagePref")); | ||||
| 
 | ||||
|         final Locale locale = createLocale(userSelectedValue); | ||||
|         Locale.setDefault(locale); | ||||
|  |  | |||
							
								
								
									
										74
									
								
								app/src/test/java/StringBuilderTest.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								app/src/test/java/StringBuilderTest.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,74 @@ | |||
| import org.junit.jupiter.api.Test; | ||||
| import static org.junit.jupiter.api.Assertions.*; | ||||
| 
 | ||||
| class StringBuilderTest { | ||||
|     @Test | ||||
|     void testFallbackDescriptionBuilder() { | ||||
|         String secondaryLanguages = "en,fr,es";  // Example secondary languages | ||||
|         String[] secondaryLanguageArray = secondaryLanguages.split(",\\s*"); | ||||
| 
 | ||||
|         StringBuilder fallBackDescription = new StringBuilder(); | ||||
|         for (int i = 0; i < secondaryLanguageArray.length; i++) { | ||||
|             fallBackDescription.append("OPTIONAL {?item schema:description ?itemDescriptionPreferredLanguage_") | ||||
|                 .append(i + 1)  // Unique identifier for each fallback | ||||
|                 .append(". FILTER (lang(?itemDescriptionPreferredLanguage_") | ||||
|                 .append(i + 1) | ||||
|                 .append(") = \"") | ||||
|                 .append(secondaryLanguageArray[i])  // Use the secondary language code | ||||
|                 .append("\")}\n"); | ||||
|         } | ||||
| 
 | ||||
|         String expected = "OPTIONAL {?item schema:description ?itemDescriptionPreferredLanguage_1. FILTER (lang(?itemDescriptionPreferredLanguage_1) = \"en\")}\n" + | ||||
|             "OPTIONAL {?item schema:description ?itemDescriptionPreferredLanguage_2. FILTER (lang(?itemDescriptionPreferredLanguage_2) = \"fr\")}\n" + | ||||
|             "OPTIONAL {?item schema:description ?itemDescriptionPreferredLanguage_3. FILTER (lang(?itemDescriptionPreferredLanguage_3) = \"es\")}\n"; | ||||
| 
 | ||||
|         assertEquals(expected, fallBackDescription.toString()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     void testFallbackLabelBuilder() { | ||||
|         String secondaryLanguages = "en,fr,es";  // Example secondary languages | ||||
|         String[] secondaryLanguageArray = secondaryLanguages.split(",\\s*"); | ||||
| 
 | ||||
|         StringBuilder fallbackLabel = new StringBuilder(); | ||||
|         for (int i = 0; i < secondaryLanguageArray.length; i++) { | ||||
|             fallbackLabel.append("OPTIONAL {?item rdfs:label ?itemLabelPreferredLanguage_") | ||||
|                 .append(i + 1) | ||||
|                 .append(". FILTER (lang(?itemLabelPreferredLanguage_") | ||||
|                 .append(i + 1) | ||||
|                 .append(") = \"") | ||||
|                 .append(secondaryLanguageArray[i]) | ||||
|                 .append("\")}\n"); | ||||
|         } | ||||
| 
 | ||||
|         String expected = "OPTIONAL {?item rdfs:label ?itemLabelPreferredLanguage_1. FILTER (lang(?itemLabelPreferredLanguage_1) = \"en\")}\n" + | ||||
|             "OPTIONAL {?item rdfs:label ?itemLabelPreferredLanguage_2. FILTER (lang(?itemLabelPreferredLanguage_2) = \"fr\")}\n" + | ||||
|             "OPTIONAL {?item rdfs:label ?itemLabelPreferredLanguage_3. FILTER (lang(?itemLabelPreferredLanguage_3) = \"es\")}\n"; | ||||
| 
 | ||||
|         assertEquals(expected, fallbackLabel.toString()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     void testFallbackClassLabelBuilder() { | ||||
|         String secondaryLanguages = "en,fr,es";  // Example secondary languages | ||||
|         String[] secondaryLanguageArray = secondaryLanguages.split(",\\s*"); | ||||
| 
 | ||||
|         StringBuilder fallbackClassLabel = new StringBuilder(); | ||||
|         for (int i = 0; i < secondaryLanguageArray.length; i++) { | ||||
|             fallbackClassLabel.append("OPTIONAL {?class rdfs:label ?classLabelPreferredLanguage_") | ||||
|                 .append(i + 1) | ||||
|                 .append(". FILTER (lang(?classLabelPreferredLanguage_") | ||||
|                 .append(i + 1) | ||||
|                 .append(") = \"") | ||||
|                 .append(secondaryLanguageArray[i]) | ||||
|                 .append("\")}\n"); | ||||
|         } | ||||
| 
 | ||||
|         String expected = "OPTIONAL {?class rdfs:label ?classLabelPreferredLanguage_1. FILTER (lang(?classLabelPreferredLanguage_1) = \"en\")}\n" + | ||||
|             "OPTIONAL {?class rdfs:label ?classLabelPreferredLanguage_2. FILTER (lang(?classLabelPreferredLanguage_2) = \"fr\")}\n" + | ||||
|             "OPTIONAL {?class rdfs:label ?classLabelPreferredLanguage_3. FILTER (lang(?classLabelPreferredLanguage_3) = \"es\")}\n"; | ||||
| 
 | ||||
|         assertEquals(expected, fallbackClassLabel.toString()); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -0,0 +1,110 @@ | |||
| package fr.free.nrw.commons.settings | ||||
| 
 | ||||
| import android.app.Dialog | ||||
| import android.os.Looper | ||||
| import fr.free.nrw.commons.TestCommonsApplication | ||||
| import fr.free.nrw.commons.recentlanguages.Language | ||||
| import fr.free.nrw.commons.recentlanguages.RecentLanguagesDao | ||||
| import org.junit.Assert | ||||
| import org.junit.Before | ||||
| import org.junit.Test | ||||
| import org.junit.runner.RunWith | ||||
| import org.mockito.Mockito | ||||
| import org.mockito.MockitoAnnotations | ||||
| import org.robolectric.Robolectric | ||||
| import org.robolectric.RobolectricTestRunner | ||||
| import org.robolectric.Shadows | ||||
| import org.robolectric.annotation.Config | ||||
| import org.robolectric.annotation.LooperMode | ||||
| import java.lang.reflect.Method | ||||
| 
 | ||||
| @RunWith(RobolectricTestRunner::class) | ||||
| @Config(sdk = [21], application = TestCommonsApplication::class) | ||||
| @LooperMode(LooperMode.Mode.PAUSED) | ||||
| class SettingsFragmentSecondaryLanguageTests { | ||||
| 
 | ||||
|     private lateinit var fragment: SettingsFragment | ||||
| 
 | ||||
|     private lateinit var recentLanguagesDao: RecentLanguagesDao | ||||
| 
 | ||||
|     @Before | ||||
|     fun setUp() { | ||||
|         MockitoAnnotations.openMocks(this) | ||||
|         val activity = Robolectric.buildActivity(SettingsActivity::class.java).create().get() | ||||
|         fragment = SettingsFragment() | ||||
|         val fragmentManager = activity.supportFragmentManager | ||||
|         val fragmentTransaction = fragmentManager.beginTransaction() | ||||
|         fragmentTransaction.add(fragment, null) | ||||
|         fragmentTransaction.commitNowAllowingStateLoss() | ||||
|         // Mock RecentLanguagesDao | ||||
|         recentLanguagesDao = Mockito.mock(RecentLanguagesDao::class.java) | ||||
|         fragment.recentLanguagesDao = recentLanguagesDao | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     @Throws(Exception::class) | ||||
|     fun `Test prepareSecondaryLanguageDialog is invoked and dialog is created`() { | ||||
|         // Set up the main looper to idle, as necessary in Robolectric tests | ||||
|         Shadows.shadowOf(Looper.getMainLooper()).idle() | ||||
| 
 | ||||
|         val method: Method = SettingsFragment::class.java.getDeclaredMethod("prepareSecondaryLanguageDialog") | ||||
|         method.isAccessible = true | ||||
| 
 | ||||
|         method.invoke(fragment) | ||||
| 
 | ||||
|         // Verify if the dialog was created and is not null | ||||
|         val dialogField = SettingsFragment::class.java.getDeclaredField("dialog") | ||||
|         dialogField.isAccessible = true | ||||
|         val dialog: Dialog? = dialogField.get(fragment) as Dialog? | ||||
|         Assert.assertNotNull(dialog) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     @Throws(Exception::class) | ||||
|     fun `Test prepareSecondaryLanguageDialog adds a language and updates preferences`() { | ||||
|         Shadows.shadowOf(Looper.getMainLooper()).idle() | ||||
| 
 | ||||
|         // Mock recent languages and saved languages | ||||
|         val savedLanguages = mutableListOf(Language("English", "en")) | ||||
| 
 | ||||
|         val method: Method = SettingsFragment::class.java.getDeclaredMethod("prepareSecondaryLanguageDialog") | ||||
|         method.isAccessible = true | ||||
| 
 | ||||
|         method.invoke(fragment) | ||||
| 
 | ||||
|         val dialogField = SettingsFragment::class.java.getDeclaredField("dialog") | ||||
|         dialogField.isAccessible = true | ||||
|         val dialog: Dialog? = dialogField.get(fragment) as Dialog? | ||||
| 
 | ||||
|         val newLanguage = Language("German", "de") | ||||
|         savedLanguages.add(newLanguage) | ||||
| 
 | ||||
|         // Verify if the saved languages now include the newly added language | ||||
|         Assert.assertTrue(savedLanguages.contains(newLanguage)) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     @Throws(Exception::class) | ||||
|     fun `Test prepareSecondaryLanguageDialog removes a language and updates preferences`() { | ||||
|         Shadows.shadowOf(Looper.getMainLooper()).idle() | ||||
| 
 | ||||
|         // Mock recent languages and saved languages | ||||
|         val savedLanguages = mutableListOf(Language("English", "en"), Language("French", "fr")) | ||||
| 
 | ||||
|         val method: Method = SettingsFragment::class.java.getDeclaredMethod("prepareSecondaryLanguageDialog") | ||||
|         method.isAccessible = true | ||||
| 
 | ||||
|         method.invoke(fragment) | ||||
| 
 | ||||
|         val dialogField = SettingsFragment::class.java.getDeclaredField("dialog") | ||||
|         dialogField.isAccessible = true | ||||
|         val dialog: Dialog? = dialogField.get(fragment) as Dialog? | ||||
| 
 | ||||
|         // Simulate removing a language from the saved list (e.g., removing "French") | ||||
|         val positionToRemove = 1 | ||||
|         savedLanguages.removeAt(positionToRemove) | ||||
| 
 | ||||
|         Assert.assertFalse(savedLanguages.any { it.languageCode == "fr" }) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Adith
						Adith