From 1010d1f09a47be9b2763f52748e305579c80c98c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Axel=20Gl=C3=B6ckner?= <axel.glockner00@gmail.com>
Date: Tue, 5 Dec 2023 15:12:58 +0100
Subject: [PATCH] ui-testing

---
 .../androidTestResultsUserPreferences.xml     | 35 ++++++++
 .../app/build.gradle.kts                      |  4 +-
 .../ExampleInstrumentedTest.java              | 84 +++++++++++++++++--
 .../passwordstrenghtmeter/Password.java       | 18 ++++
 .../PasswordStrengthMeter.java                | 35 ++++++--
 .../passwordstrenghtmeter/StrengthBar.java    | 47 +++++++++++
 6 files changed, 208 insertions(+), 15 deletions(-)
 create mode 100644 projects/PasswordStrenghtMeter/.idea/androidTestResultsUserPreferences.xml

diff --git a/projects/PasswordStrenghtMeter/.idea/androidTestResultsUserPreferences.xml b/projects/PasswordStrenghtMeter/.idea/androidTestResultsUserPreferences.xml
new file mode 100644
index 0000000..73dfedf
--- /dev/null
+++ b/projects/PasswordStrenghtMeter/.idea/androidTestResultsUserPreferences.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="AndroidTestResultsUserPreferences">
+    <option name="androidTestResultsTableState">
+      <map>
+        <entry key="-1360427803">
+          <value>
+            <AndroidTestResultsTableState>
+              <option name="preferredColumnWidths">
+                <map>
+                  <entry key="Duration" value="90" />
+                  <entry key="Pixel_6_API_34" value="120" />
+                  <entry key="Tests" value="360" />
+                </map>
+              </option>
+            </AndroidTestResultsTableState>
+          </value>
+        </entry>
+        <entry key="-664877063">
+          <value>
+            <AndroidTestResultsTableState>
+              <option name="preferredColumnWidths">
+                <map>
+                  <entry key="Duration" value="90" />
+                  <entry key="Pixel_6_API_34" value="120" />
+                  <entry key="Tests" value="360" />
+                </map>
+              </option>
+            </AndroidTestResultsTableState>
+          </value>
+        </entry>
+      </map>
+    </option>
+  </component>
+</project>
\ No newline at end of file
diff --git a/projects/PasswordStrenghtMeter/app/build.gradle.kts b/projects/PasswordStrenghtMeter/app/build.gradle.kts
index d8ce6c3..e1270e0 100644
--- a/projects/PasswordStrenghtMeter/app/build.gradle.kts
+++ b/projects/PasswordStrenghtMeter/app/build.gradle.kts
@@ -12,7 +12,6 @@ android {
         targetSdk = 34
         versionCode = 1
         versionName = "1.0"
-
         testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
     }
 
@@ -29,11 +28,12 @@ android {
 }
 
 dependencies {
-
     implementation("androidx.appcompat:appcompat:1.6.1")
     implementation("com.google.android.material:material:1.10.0")
     implementation("androidx.constraintlayout:constraintlayout:2.1.4")
     testImplementation("junit:junit:4.13.2")
     androidTestImplementation("androidx.test.ext:junit:1.1.5")
     androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
+    androidTestImplementation("androidx.test:rules:1.5.0")
+    androidTestImplementation("androidx.test:runner:1.5.2")
 }
\ No newline at end of file
diff --git a/projects/PasswordStrenghtMeter/app/src/androidTest/java/com/example/passwordstrenghtmeter/ExampleInstrumentedTest.java b/projects/PasswordStrenghtMeter/app/src/androidTest/java/com/example/passwordstrenghtmeter/ExampleInstrumentedTest.java
index 8158124..e8fa614 100644
--- a/projects/PasswordStrenghtMeter/app/src/androidTest/java/com/example/passwordstrenghtmeter/ExampleInstrumentedTest.java
+++ b/projects/PasswordStrenghtMeter/app/src/androidTest/java/com/example/passwordstrenghtmeter/ExampleInstrumentedTest.java
@@ -1,26 +1,96 @@
 package com.example.passwordstrenghtmeter;
-
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.action.ViewActions.typeText;
+import static androidx.test.espresso.assertion.ViewAssertions.matches;
+import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.withId;
 import android.content.Context;
-
+import androidx.test.ext.junit.rules.ActivityScenarioRule;
 import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
-
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-
 import static org.junit.Assert.*;
 
 /**
- * Instrumented test, which will execute on an Android device.
+ * Instrumented test class for testing the password strength meter.
  *
- * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ * This class contains a set of tests to ensure the proper functionality of the password strength meter
+ * in the context of an Android device.
  */
 @RunWith(AndroidJUnit4.class)
 public class ExampleInstrumentedTest {
+
+    /**
+     * Ensures that we are running main activity.
+     */
+    @Rule
+    public ActivityScenarioRule<MainActivity> activityRule =
+            new ActivityScenarioRule<>(MainActivity.class);
+
+    /**
+     * Verify that the application's context is correct.
+     */
     @Test
     public void useAppContext() {
         // Context of the app under test.
         Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
         assertEquals("com.example.passwordstrenghtmeter", appContext.getPackageName());
     }
-}
\ No newline at end of file
+
+    /**
+     * Test for a weak password.
+     *
+     * This test enters a weak password and checks if the strength bar is displayed and if the
+     * password strength is correctly identified as "Weak".
+     */
+    @Test
+    public void weakPasswordTest() {
+        onView(withId(Password.passwordId)).perform(typeText("password"));
+        onView(withId(StrengthBar.strengthBarId)).check(matches(isDisplayed()));
+        assertEquals("Weak", getPasswordStrength());
+    }
+
+    /**
+     * Test for a medium-strength password.
+     *
+     * This test enters a medium-strength password and checks if the strength bar is displayed and
+     * if the password strength is correctly identified as "Medium".
+     */
+    @Test
+    public void mediumPasswordTest() {
+        onView(withId(Password.passwordId)).perform(typeText("Password"));
+        onView(withId(StrengthBar.strengthBarId)).check(matches(isDisplayed()));
+        assertEquals("Medium", getPasswordStrength());
+    }
+
+    /**
+     * Test for a strong password.
+     *
+     * This test enters a strong password and checks if the strength bar is displayed and if the
+     * password strength is correctly identified as "Strong".
+     */
+    @Test
+    public void strongPasswordTest() {
+        onView(withId(Password.passwordId)).perform(typeText("Password@"));
+        onView(withId(StrengthBar.strengthBarId)).check(matches(isDisplayed()));
+        assertEquals("Strong", getPasswordStrength());
+    }
+
+    /**
+     * Helper method to get the password strength.
+     *
+     * This method retrieves the password strength from the StrengthBar and returns it as a string.
+     *
+     * @return The password strength ("Weak", "Medium", or "Strong").
+     */
+    private String getPasswordStrength() {
+        final String[] passwordStrength = new String[1];
+        activityRule.getScenario().onActivity(activity -> {
+            StrengthBar strengthBar = activity.findViewById(StrengthBar.strengthBarId);
+            passwordStrength[0] = strengthBar.getPasswordStrenght();
+        });
+        return passwordStrength[0];
+    }
+}
diff --git a/projects/PasswordStrenghtMeter/app/src/main/java/com/example/passwordstrenghtmeter/Password.java b/projects/PasswordStrenghtMeter/app/src/main/java/com/example/passwordstrenghtmeter/Password.java
index a89673a..cca8592 100644
--- a/projects/PasswordStrenghtMeter/app/src/main/java/com/example/passwordstrenghtmeter/Password.java
+++ b/projects/PasswordStrenghtMeter/app/src/main/java/com/example/passwordstrenghtmeter/Password.java
@@ -1,13 +1,17 @@
 package com.example.passwordstrenghtmeter;
 import android.content.Context;
+import android.os.Build;
 import android.text.InputType;
 import android.util.AttributeSet;
 import android.view.View;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.core.view.ViewCompat;
 
 public class Password extends androidx.appcompat.widget.AppCompatEditText {
     private View passwordView;
+    public static int passwordId; // EditText id.
+
     public Password(@NonNull Context context) {
         super(context);
         init();
@@ -28,6 +32,20 @@ public class Password extends androidx.appcompat.widget.AppCompatEditText {
         setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD );
         setGravity(android.view.Gravity.CENTER_VERTICAL | android.view.Gravity.CENTER_HORIZONTAL);
         this.passwordView = this;
+        passwordId = generateID();
+        setId(passwordId);
+    }
+
+    /**
+     * Generate a unique id
+     * @return id
+     */
+    private int generateID(){
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            return ViewCompat.generateViewId();
+        } else {
+            return View.generateViewId();
+        }
     }
 
     public void setView(View view){
diff --git a/projects/PasswordStrenghtMeter/app/src/main/java/com/example/passwordstrenghtmeter/PasswordStrengthMeter.java b/projects/PasswordStrenghtMeter/app/src/main/java/com/example/passwordstrenghtmeter/PasswordStrengthMeter.java
index 5c2995b..493788d 100644
--- a/projects/PasswordStrenghtMeter/app/src/main/java/com/example/passwordstrenghtmeter/PasswordStrengthMeter.java
+++ b/projects/PasswordStrenghtMeter/app/src/main/java/com/example/passwordstrenghtmeter/PasswordStrengthMeter.java
@@ -4,6 +4,7 @@ import android.text.Editable;
 import android.text.TextWatcher;
 import android.util.AttributeSet;
 import android.view.View;
+import android.widget.Button;
 import android.widget.LinearLayout;
 import androidx.annotation.Nullable;
 
@@ -12,6 +13,12 @@ public class PasswordStrengthMeter extends LinearLayout {
     private Password password;
     private StrengthBar strengthBar;
     private String passwordData;
+
+    private String text;
+
+    private Button button;
+
+    private int passwordId;
     public PasswordStrengthMeter(Context context) {
         super(context);
     }
@@ -39,13 +46,30 @@ public class PasswordStrengthMeter extends LinearLayout {
         password = new Password(getContext());
         strengthBar = new StrengthBar(getContext());
         strengthValidator = new DefaultValidator();
+        button = new Button(getContext());
         password.addTextChangedListener(getTextWatcher());
+        button.setText("Register");
         strengthBar.setErrorMessage(strengthValidator.ErrorMessage());
+        button.setOnClickListener(v -> onButtonClicked());
         addView(password);
         addView(strengthBar);
+        addView(button);
         addView(strengthBar.getErrorMessageView());
     }
 
+    /**
+     * If the password is strong, and the button is clicked we save the password.
+     */
+    private void onButtonClicked(){
+        if(text!=null) {
+            if (strengthValidator.ValidateLength(text)
+                    && strengthValidator.ValidateSpecialCharacters(text)
+                    && strengthValidator.ValidateCapLetters(text)) {
+                setPasswordData(text);
+            }
+        }
+
+    }
     /**
      * A text watcher to dynamically validate the password.
      * @return TextWatcher
@@ -60,18 +84,13 @@ public class PasswordStrengthMeter extends LinearLayout {
 
             @Override
             public void afterTextChanged(Editable s) {
-                final String text = s.toString();
+                text = s.toString();
                 if(text.isEmpty()){
                     strengthBar.hideErrorMessage();
                 }
                 strengthBar.updateStrengthNew(strengthValidator.ValidateLength(text),
                                               strengthValidator.ValidateSpecialCharacters(text),
                                               strengthValidator.ValidateCapLetters(text));
-                if(strengthValidator.ValidateLength(text)
-                        && strengthValidator.ValidateSpecialCharacters(text)
-                        && strengthValidator.ValidateCapLetters(text)){
-                    setPasswordData(text);
-                }
             }
         };
     }
@@ -120,4 +139,8 @@ public class PasswordStrengthMeter extends LinearLayout {
     public String getPasswordData(){
         return this.passwordData;
     }
+
+    public int getPasswordId(){
+        return password.getId();
+    }
 }
diff --git a/projects/PasswordStrenghtMeter/app/src/main/java/com/example/passwordstrenghtmeter/StrengthBar.java b/projects/PasswordStrenghtMeter/app/src/main/java/com/example/passwordstrenghtmeter/StrengthBar.java
index 993184e..1ec30d0 100644
--- a/projects/PasswordStrenghtMeter/app/src/main/java/com/example/passwordstrenghtmeter/StrengthBar.java
+++ b/projects/PasswordStrenghtMeter/app/src/main/java/com/example/passwordstrenghtmeter/StrengthBar.java
@@ -2,10 +2,15 @@ package com.example.passwordstrenghtmeter;
 import android.content.Context;
 import android.graphics.Color;
 import android.graphics.PorterDuff;
+import android.os.Build;
 import android.util.AttributeSet;
 import android.view.View;
 import android.widget.ProgressBar;
 import android.widget.TextView;
+import android.widget.Toast;
+
+import androidx.core.view.ViewCompat;
+
 public class StrengthBar extends ProgressBar {
     private static final int defaultColor = Color.TRANSPARENT; // constant for transparent color.
     private static final int alpha = 255; // constant for 100% opacity.
@@ -14,6 +19,9 @@ public class StrengthBar extends ProgressBar {
     private int mediumColor;
     private int strongColor;
     private View progressBarView;
+    public static int strengthBarId;
+
+    private int strength;
 
     public StrengthBar(Context context) {
         super(context, null, android.R.attr.progressBarStyleHorizontal);
@@ -32,6 +40,18 @@ public class StrengthBar extends ProgressBar {
         init();
     }
 
+    /**
+     * Generate a unique id
+     * @return id
+     */
+    private int generateID(){
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            return ViewCompat.generateViewId();
+        } else {
+            return View.generateViewId();
+        }
+    }
+
     /**
      * Initialize colors and error messages.
      */
@@ -44,6 +64,9 @@ public class StrengthBar extends ProgressBar {
         errorMessage.setVisibility(View.GONE);
         errorMessage.setGravity(android.view.Gravity.CENTER_VERTICAL | android.view.Gravity.CENTER_HORIZONTAL);
         this.progressBarView = this;
+        strengthBarId = generateID();
+        setId(strengthBarId);
+
     }
 
     protected void hideErrorMessage() {
@@ -70,6 +93,7 @@ public class StrengthBar extends ProgressBar {
         }if(capLet){
             trueCount++;
         }
+        setStrength(trueCount);
         if(trueCount==0){
             setProgressbarColor(defaultColor);
             showErrorMessage();
@@ -130,4 +154,27 @@ public class StrengthBar extends ProgressBar {
     protected void setErrorMessage(String message){
         errorMessage.setText(message);
     }
+
+    public int getStrength() {
+        return strength;
+    }
+    public void setStrength(int strength) {
+        this.strength = strength;
+    }
+
+    /**
+     * For confirming a test.
+     * @return
+     */
+    public String getPasswordStrenght(){
+        if(this.strength==1){
+            return "Weak";
+        }else if(this.strength==2){
+            return "Medium";
+        }else if (this.strength==3){
+            return "Strong";
+        }else{
+            return null;
+        }
+    }
 }
-- 
GitLab