Browse Source

feat: Replace uploads resource with Firebase remote config JSON

develop
Ezerous 3 years ago
parent
commit
8f34fa4bdc
  1. 3
      app/build.gradle
  2. 32
      app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadActivity.java
  3. 85
      app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadsCourse.java
  4. 2
      app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java
  5. 38
      app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java
  6. 46
      app/src/main/java/gr/thmmy/mthmmy/utils/io/ResourceUtils.java
  7. 1702
      app/src/main/res/raw/uploads_courses.json
  8. 157
      app/src/main/res/values/uploads_courses.xml
  9. 43
      app/src/test/java/gr/thmmy/mthmmy/utils/UploadsCoursesJSONReadingTest.java
  10. 1702
      app/src/test/resources/raw/uploads_courses.json

3
app/build.gradle

@ -84,8 +84,10 @@ dependencies {
implementation 'com.google.android.material:material:1.4.0' implementation 'com.google.android.material:material:1.4.0'
implementation platform('com.google.firebase:firebase-bom:28.4.0') implementation platform('com.google.firebase:firebase-bom:28.4.0')
implementation 'com.google.firebase:firebase-analytics' implementation 'com.google.firebase:firebase-analytics'
implementation 'com.google.firebase:firebase-config'
implementation 'com.google.firebase:firebase-crashlytics' implementation 'com.google.firebase:firebase-crashlytics'
implementation 'com.google.firebase:firebase-messaging' implementation 'com.google.firebase:firebase-messaging'
implementation 'com.google.code.gson:gson:2.8.8'
implementation 'com.snatik:storage:2.1.0' implementation 'com.snatik:storage:2.1.0'
implementation 'com.squareup.okhttp3:okhttp:3.14.9' implementation 'com.squareup.okhttp3:okhttp:3.14.9'
implementation 'org.jsoup:jsoup:1.14.2' implementation 'org.jsoup:jsoup:1.14.2'
@ -111,4 +113,5 @@ dependencies {
testImplementation 'org.powermock:powermock-module-junit4:2.0.2' testImplementation 'org.powermock:powermock-module-junit4:2.0.2'
testImplementation 'org.powermock:powermock-api-mockito2:2.0.2' testImplementation 'org.powermock:powermock-api-mockito2:2.0.2'
testImplementation 'net.lachlanmckee:timber-junit-rule:1.0.1' testImplementation 'net.lachlanmckee:timber-junit-rule:1.0.1'
testImplementation 'org.json:json:20210307'
} }

32
app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadActivity.java

@ -6,7 +6,6 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.Typeface; import android.graphics.Typeface;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.net.Uri; import android.net.Uri;
@ -38,10 +37,13 @@ import androidx.core.content.FileProvider;
import androidx.preference.PreferenceManager; import androidx.preference.PreferenceManager;
import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.firebase.remoteconfig.FirebaseRemoteConfig;
import net.gotev.uploadservice.UploadNotificationAction; import net.gotev.uploadservice.UploadNotificationAction;
import net.gotev.uploadservice.UploadNotificationConfig; import net.gotev.uploadservice.UploadNotificationConfig;
import org.json.JSONException;
import org.json.JSONObject;
import org.jsoup.nodes.Document; import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element; import org.jsoup.nodes.Element;
import org.jsoup.select.Elements; import org.jsoup.select.Elements;
@ -86,6 +88,8 @@ public class UploadActivity extends BaseActivity {
* The key to use when putting upload's category String to {@link UploadActivity}'s Bundle. * The key to use when putting upload's category String to {@link UploadActivity}'s Bundle.
*/ */
public static final String BUNDLE_UPLOAD_CATEGORY = "UPLOAD_CATEGORY"; public static final String BUNDLE_UPLOAD_CATEGORY = "UPLOAD_CATEGORY";
public static final String firebaseConfigUploadsCoursesKey = "uploads_courses";
private static final String uploadIndexUrl = "https://www.thmmy.gr/smf/index.php?action=tpmod;dl=upload"; private static final String uploadIndexUrl = "https://www.thmmy.gr/smf/index.php?action=tpmod;dl=upload";
private static final String uploadedFromTHMMYPromptHtml = "<br /><div style=\"text-align: right;\"><span style=\"font-style: italic;\">uploaded from <a href=\"https://play.google.com/store/apps/details?id=gr.thmmy.mthmmy\">mTHMMY</a></span>"; private static final String uploadedFromTHMMYPromptHtml = "<br /><div style=\"text-align: right;\"><span style=\"font-style: italic;\">uploaded from <a href=\"https://play.google.com/store/apps/details?id=gr.thmmy.mthmmy\">mTHMMY</a></span>";
/** /**
@ -103,7 +107,7 @@ public class UploadActivity extends BaseActivity {
private static final int MAX_FILE_SIZE_SUPPORTED = 45000000; private static final int MAX_FILE_SIZE_SUPPORTED = 45000000;
private HashMap<String, UploadsCourse> uploadsCourses; private HashMap<Integer, UploadsCourse> uploadsCourses;
private ArrayList<UploadCategory> uploadRootCategories = new ArrayList<>(); private ArrayList<UploadCategory> uploadRootCategories = new ArrayList<>();
private ParseUploadPageTask parseUploadPageTask; private ParseUploadPageTask parseUploadPageTask;
@ -416,10 +420,16 @@ public class UploadActivity extends BaseActivity {
updateUIElements(); updateUIElements();
generateFieldsButton.setEnabled(true); generateFieldsButton.setEnabled(true);
} }
FirebaseRemoteConfig firebaseRemoteConfig = FirebaseRemoteConfig.getInstance();
Resources res = getResources(); String uploadsCoursesString = firebaseRemoteConfig.getString(firebaseConfigUploadsCoursesKey);
uploadsCourses = new HashMap<>(UploadsCourse JSONObject uploadsCoursesJSON;
.generateUploadsCourses(res.getStringArray(R.array.string_array_uploads_courses))); try {
uploadsCoursesJSON = new JSONObject(uploadsCoursesString);
uploadsCourses = UploadsCourse.generateCoursesFromJSON(uploadsCoursesJSON);
} catch (JSONException e) {
uploadsCourses = new HashMap<>();
Timber.e(e, "JSONException in uploads courses.");
}
} }
@Override @Override
@ -939,8 +949,10 @@ public class UploadActivity extends BaseActivity {
.trim(); .trim();
if (!retrievedCourse.isEmpty()) { if (!retrievedCourse.isEmpty()) {
UploadsCourse foundUploadsCourse = UploadsCourse.findCourse(retrievedCourse, uploadsCourses); try {
int categoryValue = Integer.parseInt(categorySelected);
if(uploadsCourses.containsKey(categoryValue)){
UploadsCourse foundUploadsCourse = uploadsCourses.get(categoryValue);
if (foundUploadsCourse != null) { if (foundUploadsCourse != null) {
uploadsCourse = foundUploadsCourse; uploadsCourse = foundUploadsCourse;
semester = maybeSemester.replaceAll("-", "").trim().substring(0, 1); semester = maybeSemester.replaceAll("-", "").trim().substring(0, 1);
@ -948,6 +960,10 @@ public class UploadActivity extends BaseActivity {
generateFieldsButton.setEnabled(true); generateFieldsButton.setEnabled(true);
} }
} }
} catch (final NumberFormatException e) {
Timber.e(e, "Invalid category value!");
}
}
} }
} }

85
app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadsCourse.java

@ -1,79 +1,60 @@
package gr.thmmy.mthmmy.activities.upload; package gr.thmmy.mthmmy.activities.upload;
import android.os.Bundle; import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import gr.thmmy.mthmmy.base.BaseApplication; public class UploadsCourse {
import timber.log.Timber; private final int id;
private final String name, minifiedName, greeklishName;
class UploadsCourse { private UploadsCourse(int id, String name, String minifiedName, String greeklishName) {
private final String name; this.id = id;
private final String minifiedName; this.name = name;
private final String greeklishName;
private UploadsCourse(String fullName, String minifiedName, String greeklishName) {
this.name = fullName;
this.minifiedName = minifiedName; this.minifiedName = minifiedName;
this.greeklishName = greeklishName; this.greeklishName = greeklishName;
} }
String getName() { public int getId() {
return id;
}
public String getName() {
return name; return name;
} }
String getMinifiedName() { public String getMinifiedName() {
return minifiedName; return minifiedName;
} }
String getGreeklishName() { public String getGreeklishName() {
return greeklishName; return greeklishName;
} }
static Map<String, UploadsCourse> generateUploadsCourses(String[] uploadsCoursesRes) { public static HashMap<Integer, UploadsCourse> generateCoursesFromJSON(JSONObject json) throws JSONException {
Map<String, UploadsCourse> uploadsCourses = new HashMap<>(); HashMap<Integer, UploadsCourse> coursesHashMap = new HashMap<>();
for (String uploadsCourseStr : uploadsCoursesRes) { if(json.has("courses")){
String[] split = uploadsCourseStr.split("\\|"); JSONArray coursesArray = json.getJSONArray("courses");
UploadsCourse uploadsCourse = new UploadsCourse(split[0], split[1], split[2]); for(int i=0, size = coursesArray.length(); i<size; i++) {
uploadsCourses.put(uploadsCourse.getName(), uploadsCourse); JSONObject course = coursesArray.getJSONObject(i);
int id = course.getInt("id");
String name = course.getString("name");
String minifiedName = course.getString("minified");
String greeklisName = course.getString("greeklish");
coursesHashMap.put(course.getInt("id"), new UploadsCourse(id, name, minifiedName, greeklisName));
} }
return uploadsCourses;
} }
static UploadsCourse findCourse(String retrievedCourse, if(json.has("categories")){
Map<String, UploadsCourse> uploadsCourses) { JSONArray categoriesArray = json.getJSONArray("categories");
retrievedCourse = normalizeGreekNumbers(retrievedCourse); for(int i=0, size = categoriesArray.length(); i<size; i++) {
UploadsCourse uploadsCourse = uploadsCourses.get(retrievedCourse); JSONObject category = categoriesArray.getJSONObject(i);
if (uploadsCourse != null) return uploadsCourse; coursesHashMap.putAll(generateCoursesFromJSON(category));
String foundKey = null;
for (Map.Entry<String, UploadsCourse> entry : uploadsCourses.entrySet()) {
String key = entry.getKey();
if ((key.contains(retrievedCourse) || retrievedCourse.contains(key))
&& (foundKey == null || key.length() > foundKey.length()))
foundKey = key;
} }
if (foundKey == null) {
Timber.w("Couldn't find course that matches %s", retrievedCourse);
Bundle bundle = new Bundle();
bundle.putString("course_name", retrievedCourse);
BaseApplication.getInstance().logFirebaseAnalyticsEvent("unsupported_uploads_course", bundle);
return null;
}
return uploadsCourses.get(foundKey);
} }
private static String normalizeGreekNumbers(String stringWithGreekNumbers) { return coursesHashMap;
StringBuilder normalizedStrBuilder = new StringBuilder(stringWithGreekNumbers);
Pattern pattern = Pattern.compile("(Ι+)(?:\\s|\\(|\\)|$)");
Matcher matcher = pattern.matcher(stringWithGreekNumbers);
while (matcher.find())
normalizedStrBuilder.replace(matcher.start(1), matcher.end(1), matcher.group(1).replaceAll("Ι", "I"));
return normalizedStrBuilder.toString();
} }
} }

2
app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java

@ -102,8 +102,6 @@ public abstract class BaseActivity extends AppCompatActivity {
protected Toolbar toolbar; protected Toolbar toolbar;
protected Drawer drawer; protected Drawer drawer;
AlertDialog uploadsProgressDialog;
private MainActivity mainActivity; private MainActivity mainActivity;
private boolean isMainActivity; private boolean isMainActivity;
private boolean isUserConsentDialogShown; //Needed because sometimes onResume is being called twice private boolean isUserConsentDialogShown; //Needed because sometimes onResume is being called twice

38
app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java

@ -19,6 +19,8 @@ import com.franmontiel.persistentcookiejar.persistence.SharedPrefsCookiePersisto
import com.google.firebase.FirebaseApp; import com.google.firebase.FirebaseApp;
import com.google.firebase.analytics.FirebaseAnalytics; import com.google.firebase.analytics.FirebaseAnalytics;
import com.google.firebase.crashlytics.FirebaseCrashlytics; import com.google.firebase.crashlytics.FirebaseCrashlytics;
import com.google.firebase.remoteconfig.FirebaseRemoteConfig;
import com.google.firebase.remoteconfig.FirebaseRemoteConfigSettings;
import com.localebro.okhttpprofiler.OkHttpProfilerInterceptor; import com.localebro.okhttpprofiler.OkHttpProfilerInterceptor;
import com.mikepenz.materialdrawer.util.AbstractDrawerImageLoader; import com.mikepenz.materialdrawer.util.AbstractDrawerImageLoader;
import com.mikepenz.materialdrawer.util.DrawerImageLoader; import com.mikepenz.materialdrawer.util.DrawerImageLoader;
@ -26,7 +28,11 @@ import com.mikepenz.materialdrawer.util.DrawerImageLoader;
import net.gotev.uploadservice.UploadService; import net.gotev.uploadservice.UploadService;
import net.gotev.uploadservice.okhttp.OkHttpStack; import net.gotev.uploadservice.okhttp.OkHttpStack;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import gr.thmmy.mthmmy.BuildConfig; import gr.thmmy.mthmmy.BuildConfig;
@ -40,8 +46,10 @@ import timber.log.Timber;
import static gr.thmmy.mthmmy.activities.settings.SettingsActivity.DISPLAY_COMPACT_TABS; import static gr.thmmy.mthmmy.activities.settings.SettingsActivity.DISPLAY_COMPACT_TABS;
import static gr.thmmy.mthmmy.activities.settings.SettingsActivity.DISPLAY_RELATIVE_TIME; import static gr.thmmy.mthmmy.activities.settings.SettingsActivity.DISPLAY_RELATIVE_TIME;
import static gr.thmmy.mthmmy.activities.upload.UploadActivity.firebaseConfigUploadsCoursesKey;
import static gr.thmmy.mthmmy.utils.io.ResourceUtils.readJSONResourceToString;
public class BaseApplication extends Application { public class BaseApplication extends Application implements Executor{
private static BaseApplication baseApplication; //BaseApplication singleton private static BaseApplication baseApplication; //BaseApplication singleton
private CrashReportingTree crashReportingTree; private CrashReportingTree crashReportingTree;
@ -49,6 +57,7 @@ public class BaseApplication extends Application {
//Firebase //Firebase
private static String firebaseProjectId; private static String firebaseProjectId;
private FirebaseAnalytics firebaseAnalytics; private FirebaseAnalytics firebaseAnalytics;
private FirebaseRemoteConfig firebaseRemoteConfig;
//Client & SessionManager //Client & SessionManager
private OkHttpClient client; private OkHttpClient client;
@ -119,6 +128,27 @@ public class BaseApplication extends Application {
Timber.i("Starting app with Firebase Analytics enabled."); Timber.i("Starting app with Firebase Analytics enabled.");
else else
Timber.i("Starting app with Firebase Analytics disabled."); Timber.i("Starting app with Firebase Analytics disabled.");
// Firebase Remote Config (uploads courses)
InputStream inputStream = getApplicationContext().getResources().openRawResource(R.raw.uploads_courses);
String uploadsCourses = readJSONResourceToString(inputStream);
Map<String, Object> uploadsCoursesMap = new HashMap<>();
uploadsCoursesMap.put(firebaseConfigUploadsCoursesKey, uploadsCourses);
firebaseRemoteConfig = FirebaseRemoteConfig.getInstance();
FirebaseRemoteConfigSettings configSettings = new FirebaseRemoteConfigSettings.Builder()
.setMinimumFetchIntervalInSeconds(3600)
.build();
firebaseRemoteConfig.setConfigSettingsAsync(configSettings);
firebaseRemoteConfig.setDefaultsAsync(uploadsCoursesMap);
firebaseRemoteConfig.fetchAndActivate()
.addOnCompleteListener(this, task -> {
if (task.isSuccessful()) {
boolean updated = task.getResult();
Timber.i("Firebase remote config params updated: %s", updated);
} else
Timber.e("Fetching Firebase remote config params failed!");
});
} }
private void initOkHttp(PersistentCookieJar cookieJar) { private void initOkHttp(PersistentCookieJar cookieJar) {
@ -247,4 +277,10 @@ public class BaseApplication extends Application {
public static String getFirebaseProjectId() { public static String getFirebaseProjectId() {
return firebaseProjectId; return firebaseProjectId;
} }
// Implement Executor (for Firebase remote config)
@Override
public void execute(Runnable runnable) {
runnable.run();
}
} }

46
app/src/main/java/gr/thmmy/mthmmy/utils/io/ResourceUtils.java

@ -0,0 +1,46 @@
package gr.thmmy.mthmmy.utils.io;
import android.content.res.Resources;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import timber.log.Timber;
public class ResourceUtils {
public static String readJSONResourceToString(Resources resources, int id) {
InputStream inputStream = resources.openRawResource(id);
return readStream(inputStream);
}
public static String readJSONResourceToString(InputStream inputStream) {
return readStream(inputStream);
}
private static String readStream(InputStream inputStream) {
Writer writer = new StringWriter();
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
String line = reader.readLine();
while (line != null) {
writer.write(line);
line = reader.readLine();
}
} catch (Exception e) {
Timber.e(e, "Unhandled exception while using readJSONFromResource");
} finally {
try {
inputStream.close();
} catch (Exception e) {
Timber.e(e, "Unhandled exception while using readJSONFromResource");
}
}
return writer.toString();
}
}

1702
app/src/main/res/raw/uploads_courses.json

File diff suppressed because it is too large

157
app/src/main/res/values/uploads_courses.xml

@ -1,157 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--Format| Original|Minified|Greeklish-->
<string-array name="string_array_uploads_courses">
<item>Ακουστική I|Ακουστική 1|Akoustiki_I</item>
<item>Ακουστική II|Ακουστική 2|Akoustiki_II</item>
<item>Ανάλυση Ηλεκτρικών Κυκλωμάτων με Υπολογιστή|Ανάλυση Ηλεκτρικ. Κυκλ. με Υπολογιστή|Analysi_Ilektr_Kykl</item>
<item>Ανάλυση Συστημάτων Ηλεκτρικής Ενέργειας|ΑΣΗΕ|ASHE</item>
<item>Ανάλυση Χρονοσειρών|Χρονοσειρές|Xronoseires</item>
<item>Ανάλυση και Σχεδίαση Αλγορίθμων|Αλγόριθμοι|Algorithms</item>
<item>Αναγνώριση Προτύπων|Αναγνώριση Προτύπων|Protypa</item>
<item>Αναλογικές Τηλεπικοινωνίες (πρώην Τηλεπικοινωνιακά Συστήματα I)|Αναλογικές Τηλεπ.|Anal_Tilep</item>
<item>Αντικειμενοστραφής Προγραμματισμός|Αντικειμενοστραφής|OOP</item>
<item>Αξιοπιστία Συστημάτων|Αξιοπιστία Συστημάτων|Aksiopistia_Systimaton</item>
<item>Αριθμητική Ανάλυση|Αριθμ. Ανάλυση|Arith_Anal</item>
<item>Αρχές Οικονομίας|Αρχές Οικονομίας|Arx_Oikonomias</item>
<item>Αρχές Παράλληλης Επεξεργασίας|Αρχές Παράλληλης Επεξεργασίας|Arxes_Parall_Epeksergasias</item>
<item>Αρχιτεκτονική Υπολογιστών|Αρχ. Υπολογιστών|Arx_Ypologiston</item>
<item>Ασαφή Συστήματα|Ασαφή|Asafi</item>
<item>Ασφάλεια Πληροφοριακών Συστημάτων|Ασφάλεια|Asfaleia</item>
<item>Ασύρματος Τηλεπικοινωνία I|Ασύρματος 1|Asyrmatos_I</item>
<item>Ασύρματος Τηλεπικοινωνία II|Ασύρματος 2|Asyrmatos_II</item>
<item>Βάσεις Δεδομένων|Βάσεις|Vaseis</item>
<item>Βιομηχανικά Ηλεκτρονικά|Βιομηχανικά Ηλεκτρονικά|Viomix_Ilektronika</item>
<item>Βιομηχανική Πληροφορική|Βιομηχανική Πληρ|Viomix_Plir</item>
<item>Βιοϊατρική Τεχνολογία|Βιοϊατρική|Vioiatriki</item>
<item>Γεωηλεκτρομαγνητισμός|Γεωηλεκτρομαγνητισμός|Geoilektromagnitismos</item>
<item>Γραμμική Άλγεβρα|Γραμμ. Άλγεβρ.|Grammiki_Algevra</item>
<item>Γραφική με Υπολογιστές|Γραφική|Grafiki</item>
<item>Δίκτυα Τηλεπικοινωνιών|Δίκτυα Τηλέπ.|Diktya_Tilep</item>
<item>Δίκτυα Υπολογιστών I|Δίκτυα 1|Diktya_I</item>
<item>Δίκτυα Υπολογιστών II|Δίκτυα 2|Diktya_II</item>
<item>Διάδοση Η/Μ Κύματος II|Διάδοση 2|Diadosi_II</item>
<item>Διάδοση Ηλεκτρομαγνητικού Κύματος I (πρώην Πεδίο III)|Διάδοση 1|Diadosi_I</item>
<item>Διακριτά Μαθηματικά|Διακριτά Μαθηματικά|Diakrita</item>
<item>Διανεμημένη Παραγωγή|Διανεμημένη Παραγωγή|Dian_Paragogi</item>
<item>Διατάξεις Υψηλών Συχνοτήτων|ΔΥΣ|DYS</item>
<item>Διαφορικές Εξισώσεις|Διαφορικές|Diaforikes</item>
<item>Διαχείριση Συστημάτων Ηλεκτρικής Ενέργειας|ΔΣΗΕ|DSHE</item>
<item>Δομές Δεδομένων|Δομ. Δεδομ.|Domes_Dedomenon</item>
<item>Δομημένος Προγραμματισμός|Δομ. Προγραμμ.|C</item>
<item>Ειδικά Κεφάλαια Διαφορικών Εξισώσεων|Ειδικά Κεφάλαια Διαφορικών Εξισώσεων|Eidika_Kef_Diaf_Eksis</item>
<item>Ειδικά Κεφάλαια Ηλεκτρομαγνητικού Πεδίου I|Ειδικά Κεφάλαια Ηλεκτρομαγνητικού Πεδίου I|Eidika_Kef_HM_Pediou_I</item>
<item>Ειδικά Κεφάλαια Συστημάτων Ηλεκτρικής Ενέργειας|ΕΚΣΗΕ|EKSHE</item>
<item>Ειδικές Αρχιτεκτονικές Υπολογιστών|Ειδικές Αρχιτεκτονικές Υπολογιστών|Eidikes_Arx_Ypolog</item>
<item>Ειδικές Κεραίες, Σύνθεση Κεραιών|Ειδικές Κεραίες, Σύνθεση Κεραιών|Eidikes_Keraies</item>
<item>Εισαγωγή στην Ενεργειακή Τεχνολογία I|ΕΕΤ 1|EET_I</item>
<item>Εισαγωγή στην Ενεργειακή Τεχνολογία II|ΕΕΤ 2|EET_II</item>
<item>Εισαγωγή στην Πολιτική Οικονομία|Πολιτική Οικονομία|Polit_Oik</item>
<item>Εισαγωγή στις εφαρμογές Πυρηνικής Τεχνολογίας|Εισ. Πυρηνικη Τεχν.|Intro_Pyriniki_Texn</item>
<item>Ενσωματωμένα Συστήματα Πραγματικού Χρόνου|Ενσωματωμένα|Ensomatomena</item>
<item>Επιχειρησιακή Έρευνα|Επιχειρησιακή Έρευνα|Epixeirisiaki</item>
<item>Ευρυζωνικά Δίκτυα|Ευρυζωνικά|Evryzonika</item>
<item>Ευφυή Συστήματα Ρομπότ|Ευφυή|Eufyi</item>
<item>Εφαρμογές Τηλεπικοινωνιακών Διατάξεων|Εφαρμογές Τηλεπ. Διατάξεων|Efarm_Tilep_Diatakseon</item>
<item>Εφαρμοσμένα Μαθηματικά I|Εφαρμοσμένα 1|Efarmosmena_Math_I</item>
<item>Εφαρμοσμένα Μαθηματικά II|Εφαρμοσμένα 2|Efarmosmena_Math_II</item>
<item>Εφαρμοσμένη Θερμοδυναμική|Θερμοδυναμική|Thermodynamiki</item>
<item>Ηλεκτρακουστική I|Ηλεκτρακουστική 1|Ilektrakoustiki_I</item>
<item>Ηλεκτρακουστική II|Ηλεκτρακουστική 2|Ilektrakoustiki_II</item>
<item>Ηλεκτρικά Κυκλώματα I|Κυκλώματα 1|Kyklomata_I</item>
<item>Ηλεκτρικά Κυκλώματα II|Κυκλώματα 2|Kyklomata_II</item>
<item>Ηλεκτρικά Κυκλώματα III|Κυκλώματα 3|Kyklomata_I</item>
<item>Ηλεκτρικές Μετρήσεις I|Μετρήσεις 1|Metriseis_I</item>
<item>Ηλεκτρικές Μετρήσεις II|Μετρήσεις 2|Metriseis_II</item>
<item>Ηλεκτρικές Μηχανές I|Μηχανές I|Mixanes_I</item>
<item>Ηλεκτρικές Μηχανές Α\'|Μηχανές Α|Mixanes_A</item>
<item>Ηλεκτρικές Μηχανές Β\'|Μηχανές Β|Mixanes_B</item>
<item>Ηλεκτρικές Μηχανές Γ\'|Μηχανές Γ|Mixanes_C</item>
<item>Ηλεκτρική Οικονομία|Ηλεκτρική Οικονομία|Ilektr_Oikonomia</item>
<item>Ηλεκτρολογικά Υλικά|Ηλεκτρ. Υλικά|Ylika</item>
<item>Ηλεκτρομαγνητική Συμβατότητα|H/M Συμβατότητα|HM_Symvatotita</item>
<item>Ηλεκτρομαγνητικό Πεδίο I|Πεδίο 1|Pedio_I</item>
<item>Ηλεκτρομαγνητικό Πεδίο II|Πεδίο 2|Pedio_II</item>
<item>Ηλεκτρονικά Ισχύος I|Ισχύος 1|Isxyos_I</item>
<item>Ηλεκτρονικά Ισχύος II|Ισχύος 2|Isxyos_II</item>
<item>Ηλεκτρονικές Διατάξεις και Μετρήσεις|Ηλεκτρονικές Διατάξεις και Μετρήσεις|Ilektron_Diatakseis_Metriseis</item>
<item>Ηλεκτρονική I|Ηλεκτρονική 1|Ilektroniki_I</item>
<item>Ηλεκτρονική II|Ηλεκτρονική 2|Ilektroniki_II</item>
<item>Ηλεκτρονική III|Ηλεκτρονική 3|Ilektroniki_III</item>
<item>Ημιαγωγά Υλικά: Θεωρία-Διατάξεις|Ημιαγωγά Υλικά|Imiagoga_Ylika</item>
<item>Θεωρία Πιθανοτήτων και Στατιστική|Πιθανότητες|Pithanotites</item>
<item>Θεωρία Πληροφοριών|Θεωρία Πληρ.|Theoria_Plir</item>
<item>Θεωρία Σημάτων και Γραμμικών Συστημάτων|Σήματα &amp; Συστήματα|Analog_Sima</item>
<item>Θεωρία Σκέδασης|Σκέδαση|Skedasi</item>
<item>Θεωρία Υπολογισμών και Αλγορίθμων|ΘΥΑ|THYA</item>
<item>Θεωρία και Τεχνολογία Πυρηνικών Αντιδραστήρων|Τεχνολογία Αντιδραστήρων|Texn_Antidrasthron</item>
<item>Κβαντική Φυσική|Κβαντική|Kvantiki</item>
<item>Κινητές και Δορυφορικές Επικοινωνίες|Κινητές &amp; Δορυφορικές Επικοινωνίες|Kinites_Doryforikes_Epik</item>
<item>Λειτουργικά Συστήματα|Λειτουργικά|OS</item>
<item>Λογική Σχεδίαση|Λογική Σχεδίαση|Logiki_Sxediasi</item>
<item>Λογισμός I|Λογισμός 1|Logismos_I</item>
<item>Λογισμός II|Λογισμός 2|Logismos_II</item>
<item>Μετάδοση Θερμότητας|Μετάδοση Θερμ.|Metadosi_Therm</item>
<item>Μικροεπεξεργαστές και Περιφερειακά|Μίκρο 2|Mikro_II</item>
<item>Μικροκυματική Τηλεπισκόπηση|Τηλεπισκόπηση|Tilepiskopisi</item>
<item>Μικροκύματα I|Μικροκύματα 1|Mikrokymata_I</item>
<item>Μικροκύματα II|Μικροκύματα 2|Mikrokymata_II</item>
<item>Οπτικές Επικοινωνίες|Οπτικές Τηλεπ.|Optikes_Tilep</item>
<item>Οπτική I|Οπτική 1|Optiki_I</item>
<item>Οπτική II|Οπτική 2|Optiki_II</item>
<item>Οργάνωση Υπολογιστών|Οργάνωση Υπολ.|Org_Ypol</item>
<item>Οργάνωση και Διοίκηση Εργοστασίων|Οργάνωση και Διοίκηση Εργοστασίων|Organ_Dioik_Ergostasion</item>
<item>Παράλληλα και Κατανεμημένα Συστήματα|Παράλληλα|Parallila</item>
<item>Προγραμματιζόμενα Κυκλώματα ASIC|ASIC|ASIC</item>
<item>Προγραμματιστικές Τεχνικές|Προγραμματ. Τεχν.|CPP</item>
<item>Προηγμένες Τεχνικές Επεξεργασίας Σήματος|ΠΤΕΣ|PTES</item>
<item>Προσομοίωση και Μοντελοποίηση Συστημάτων|Μοντελοποίηση|Montelopoiisi</item>
<item>Ρομποτική|Ρομποτική|Robotiki</item>
<item>Σήματα και Συστήματα|Σήματα &amp; Συστήματα|Analog_Sima</item>
<item>Σερβοκινητήρια Συστήματα|Σέρβο|Servo</item>
<item>Σταθμοί Παραγωγής Ηλεκτρικής Ενέργειας|ΣΠΗΕ|SPHE</item>
<item>Στοχαστικά Σήματα και Διαδικασίες|Στοχαστικό|Stochastic</item>
<item>Στοχαστικό Σήμα|Στοχαστικό|Stochastic</item>
<item>Συστήματα Αυτομάτου Ελέγχου I|ΣΑΕ 1|SAE_I</item>
<item>Συστήματα Αυτομάτου Ελέγχου II|ΣΑΕ 2|SAE_II</item>
<item>Συστήματα Αυτομάτου Ελέγχου III|ΣΑΕ 3|SAE_III</item>
<item>Συστήματα Ηλεκτρικής Ενέργειας I|ΣΗΕ 1|SHE_I</item>
<item>Συστήματα Ηλεκτρικής Ενέργειας II|ΣΗΕ 2|SHE_II</item>
<item>Συστήματα Ηλεκτρικής Ενέργειας III|ΣΗΕ 3|SHE_III</item>
<item>Συστήματα Ηλεκτροκίνησης|Ηλεκτροκίνηση|Ilektrokinisi</item>
<item>Συστήματα Μικροϋπολογιστών|Μίκρο 1|Mikro_I</item>
<item>Συστήματα Πολυμέσων και Εικονική Πραγματικότητα|Πολυμέσα|Polymesa</item>
<item>Συστήματα Υπολογιστών (Υπολογιστικά Συστήματα)|Συσ. Υπολογιστών|Sys_Ypologiston</item>
<item>Σχεδίαση Συστημάτων VLSI|VLSI|VLSI</item>
<item>Σύνθεση Ενεργών και Παθητικών Κυκλωμάτων|Σύνθεση|Synthesi</item>
<item>Σύνθεση Τηλεπικοινωνιακών Διατάξεων|Σύνθεση Τηλεπ. Διατάξεων|Synth_Tilep_Diatakseon</item>
<item>Τεχνικές Βελτιστοποίησης|Βελτιστοποίηση|Veltistopoiisi</item>
<item>Τεχνικές Κωδικοποίησης|Τεχνικές Κωδικοποίησης|Texn_Kodikopoiisis</item>
<item>Τεχνικές Σχεδίασης με Η/Υ|Σχέδιο|Sxedio</item>
<item>Τεχνικές μη Καταστρεπτικών Δοκιμών|Μη Καταστρεπτικές Δοκιμές|Non_Destructive_Tests</item>
<item>Τεχνική Μηχανική|Τεχν. Μηχαν.|Texn_Mixan</item>
<item>Τεχνολογία Ήχου και Εικόνας|Τεχνολογία Ήχου και Εικόνας|Texn_Ixou_Eikonas</item>
<item>Τεχνολογία Ηλεκτροτεχνικών Υλικών|Ηλεκτροτεχνικά Υλικά|Ilektrotexnika_Ylika</item>
<item>Τεχνολογία Λογισμικού|Τεχνολογία Λογισμικού|SE</item>
<item>Τηλεοπτικά Συστήματα|Τηλεοπτικά|Tileoptika</item>
<item>Τηλεπικοινωνιακά Συστήματα I|Τηλεπικοινωνιακά I|Tilepikoinoniaka_I</item>
<item>Τηλεπικοινωνιακά Συστήματα II|Τηλεπικοινωνιακά II|Tilepikoinoniaka_II</item>
<item>Τηλεπικοινωνιακή Ηλεκτρονική|Τηλεπ. Ηλεκτρ.|Tilep_Ilektr</item>
<item>Υπολογιστικές Μέθοδοι στα Ενεργειακά Συστήματα|ΥΜΕΣ|YMES</item>
<item>Υπολογιστικός Ηλεκτρομαγνητισμός|Υπολογιστικός Η/Μ|Ypologistikos_HM</item>
<item>Υψηλές Τάσεις I|Υψηλές 1|Ypsiles_I</item>
<item>Υψηλές Τάσεις II|Υψηλές 2|Ypsiles_II</item>
<item>Υψηλές Τάσεις III|Υψηλές 3|Ypsiles_III</item>
<item>Υψηλές Τάσεις 4|Υψηλές 4|Ypsiles_IV</item>
<item>Φυσική I|Φυσική 1|Fysiki_I</item>
<item>Φωτονική Τεχνολογία|Φωτονική|Fotoniki</item>
<item>Ψηφιακά Συστήματα I|Ψηφιακά 1|Psifiaka_I</item>
<item>Ψηφιακά Συστήματα II|Ψηφιακά 2|Psifiaka_II</item>
<item>Ψηφιακά Συστήματα III|Ψηφιακά 3|Psifiaka_III</item>
<item>Ψηφιακά Φίλτρα|Φίλτρα|Filtra</item>
<item>Ψηφιακές Τηλεπικοινωνίες I|Ψηφιακές Τηλεπ. 1|Psif_Tilep_I</item>
<item>Ψηφιακές Τηλεπικοινωνίες II|Ψηφιακές Τηλεπ. 2|Psif_Tilep_II</item>
<item>Ψηφιακή Επεξεργασία Εικόνας|ΨΕΕ|PSEE</item>
<item>Ψηφιακή Επεξεργασία Σήματος|ΨΕΣ|PSES</item>
</string-array>
</resources>

43
app/src/test/java/gr/thmmy/mthmmy/utils/UploadsCoursesJSONReadingTest.java

@ -0,0 +1,43 @@
package gr.thmmy.mthmmy.utils;
import net.lachlanmckee.timberjunit.TimberTestRule;
import org.json.JSONObject;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import java.io.InputStream;
import java.util.HashMap;
import gr.thmmy.mthmmy.activities.upload.UploadsCourse;
import gr.thmmy.mthmmy.utils.io.ResourceUtils;
import static gr.thmmy.mthmmy.activities.upload.UploadsCourse.generateCoursesFromJSON;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@RunWith(PowerMockRunner.class)
@PrepareForTest(JSONObject.class)
public class UploadsCoursesJSONReadingTest {
private final String filePath = "/raw/uploads_courses.json";
@Rule
public TimberTestRule logAllAlwaysRule = TimberTestRule.logAllAlways();
@Test
public void uploadsCoursesRetrievedCorrectly() throws Exception {
InputStream is = this.getClass().getResourceAsStream(filePath);
assertNotNull(is);
String uploadsCoursesJSON = ResourceUtils.readJSONResourceToString(is);
assertNotNull(uploadsCoursesJSON);;
JSONObject jsonObject = new JSONObject(uploadsCoursesJSON);
assertTrue(jsonObject.has("categories"));
HashMap<Integer, UploadsCourse> coursesHashMap = generateCoursesFromJSON(jsonObject);
assertEquals(coursesHashMap.size(), 216);
}
}

1702
app/src/test/resources/raw/uploads_courses.json

File diff suppressed because it is too large
Loading…
Cancel
Save