Skip to content

Creates new Credential provider; Deprecated Internet provider methods#1628

Merged
bodiam merged 2 commits intodatafaker-net:mainfrom
rcriosbr:main
Aug 30, 2025
Merged

Creates new Credential provider; Deprecated Internet provider methods#1628
bodiam merged 2 commits intodatafaker-net:mainfrom
rcriosbr:main

Conversation

@rcriosbr
Copy link
Copy Markdown
Contributor

Creates a new provider, Credential, whose purpose is to centralize the creation of credential-related data, such as user names, IDs, passwords, keys, etc.

In addition to the methods that already existed in the Internet provider (which were marked as deprecated), two new methods were created to assist in the creation of weak passwords (black list) and user IDs.

Improved test coverage for Internet provider.

@what-the-diff
Copy link
Copy Markdown

what-the-diff bot commented Aug 24, 2025

PR Summary

  • Introduction of Credential provider
    The team has created a new class called Credential. This class has several new features that help in generating items such as usernames, passwords, and unique user IDs.

  • Features of Credential class

    • username(): This function helps in creating usernames from a person's first and last names.
    • password(): The functionality of this method is flexible. It generates passwords based on specific criteria such as length, the inclusion of uppercase letters, digits, and special characters.
    • weakPassword(): This function returns a weak password from a predefined list.
    • userId(): This function generates user IDs based on specific patterns.
  • Enhancements to BaseProviders
    There's been a new addition to the BaseProviders class. A method called credential() has been added which returns an instance of the Credential class.

  • Deprecation in Internet provider
    Some of the password-related methods that were originally part of the Internet provider are now considered outdated. These methods have been replaced with the newer and improved methods present in the Credential class.

  • Introduction of credential.yml file
    A new file named credential.yml has been added. This file defines weak passwords and user ID patterns.

  • New Test Suite for Credential
    To ensure that the Credential functions as intended, a comprehensive suite of tests has been implemented, which covers features such as username, password, and user ID generation.

  • Updates to EnFile
    The EnFile has been updated to include credential.yml in the list of existing files.

  • Enhancements in InternetTest
    A test for checking the type safety of email addresses has been added. This enhancement ensures the proper handling of name suffixes and prefixes.

@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Aug 24, 2025

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.36%. Comparing base (7b7237a) to head (c8eafd7).
⚠️ Report is 1 commits behind head on main.
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@             Coverage Diff              @@
##               main    #1628      +/-   ##
============================================
+ Coverage     92.22%   92.36%   +0.13%     
- Complexity     3355     3377      +22     
============================================
  Files           331      332       +1     
  Lines          6636     6664      +28     
  Branches        662      664       +2     
============================================
+ Hits           6120     6155      +35     
+ Misses          350      349       -1     
+ Partials        166      160       -6     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@asolntsev
Copy link
Copy Markdown
Collaborator

@rcriosbr Isn't Credentials better name than Credential? Afaik "credentials" is a common term.

From AI:

Both "credential" and "credentials" are grammatically correct, but "credentials" is far more common because the word is often used to refer to a collection of qualifications or proofs of identity, even if it's a single document. Use "credentials" when referring to a person's achievements, qualities, or qualifications in general, or specific proofs of identity such as a username and password. Use "credential" when referring to a single specific achievement, quality, or qualification, such as "My experience as a manager is my strongest credential".

@asolntsev asolntsev added this to the 2.4.5 milestone Aug 24, 2025
@asolntsev asolntsev added the enhancement New feature or request label Aug 24, 2025
@rcriosbr
Copy link
Copy Markdown
Contributor Author

@asolntsev In general, I follow the NIST definitions (https://csrc.nist.gov/glossary/term/credential), but yes, I have seen several sources using "credentials" to refer to the user name/ID and password pair and others that only use plural when the user has more than one credential (like password, certificate, biometrics, etc)

Whatever you think is most appropriate.

@kingthorin
Copy link
Copy Markdown
Collaborator

My vote is with the s

@bodiam
Copy link
Copy Markdown
Contributor

bodiam commented Aug 29, 2025

Hi all, anything still needs be done here? I'm happy to accept the PR, and people who care a lot about with the S or without the S can make that change. I don't mind either way, and this is a place for meritocracy, so code (and coders) win.

Thank you again @rcriosbr , it's a great contribution!

@kingthorin
Copy link
Copy Markdown
Collaborator

Here's a patch that does the Credential ➡️ Credentials switch:

patch
diff --git a/src/main/java/net/datafaker/providers/base/Credentials.java b/src/main/java/net/datafaker/providers/base/Credentials.java
new file mode 100644
--- /dev/null
+++ b/src/main/java/net/datafaker/providers/base/Credentials.java
@@ -0,0 +1,170 @@
+package net.datafaker.providers.base;
+
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+/**
+ * Generates credentials such as usernames, uids and passwords.
+ * 
+ * @since 2.4.5
+ */
+public class Credentials extends AbstractProvider<BaseProviders> {
+
+    public static final int MIN_PASSWORD_LENGTH = 8;
+    public static final int MAX_PASSWORD_LENGTH = 16;
+
+    protected Credentials(BaseProviders faker) {
+        super(faker);
+    }
+    
+    /**
+     * A lowercase username composed of the first_name and last_name joined with a '.'. Some examples are:
+     * <ul>
+     *     <li>(template) {@link Name#firstName()}.{@link Name#lastName()}</li>
+     *     <li>jim.jones</li>
+     *     <li>jason.leigh</li>
+     *     <li>tracy.jordan</li>
+     * </ul>
+     *
+     * @return a random two part username.
+     * @see Name#firstName()
+     * @see Name#lastName()
+     */
+    public String username() {
+        StringBuilder result = new StringBuilder();
+        final Name name = faker.name();
+        final String firstName = name.firstName().toLowerCase(faker.getContext().getLocale())
+            + "." + name.lastName().toLowerCase(faker.getContext().getLocale());
+        for (int i = 0; i < firstName.length(); i++) {
+            final char c = firstName.charAt(i);
+            if (c == '\'' || Character.isWhitespace(c)) {
+                continue;
+            }
+            result.append(c);
+        }
+        return result.toString();
+    }
+
+    /**
+     * Generates a password, only with lowercase letters, numbers and
+     * with length between 8 and 16 characters.
+     *
+     * @return A randomly generated password
+     */
+    public String password() {
+        return password(MIN_PASSWORD_LENGTH, MAX_PASSWORD_LENGTH);
+    }
+
+    /**
+     * Generates a password, only with lowercase letters and optionally numbers
+     * with length between 8 and 16 characters.
+     *
+     * @param includeDigit if true, the password will contain at least one digit
+     * @return A randomly generated password
+     */
+    public String password(boolean includeDigit) {
+        return password(MIN_PASSWORD_LENGTH, MAX_PASSWORD_LENGTH, false, false, includeDigit);
+    }
+
+    /**
+     * Generates a password, only with lowercase letters, numbers and 
+     * with min and max length defined by the user.
+     *
+     * @param minimumLength the minimum length of the password
+     * @param maximumLength the maximum length of the password
+     * @return A randomly generated password
+     */
+    public String password(int minimumLength, int maximumLength) {
+        return password(minimumLength, maximumLength, false);
+    }
+
+    /**
+     * Generates a password with lowercase and optionally uppercase letters, numbers
+     * and with min and max length defined by the user.
+     *
+     * @param minimumLength    the minimum length of the password
+     * @param maximumLength    the maximum length of the password
+     * @param includeUppercase if true, the password will contain at least one uppercase letter
+     * @return A randomly generated password
+     */
+    public String password(int minimumLength, int maximumLength, boolean includeUppercase) {
+        return password(minimumLength, maximumLength, includeUppercase, false);
+    }
+
+    /**
+     * Generates a password with lowercase letters, numbers and optionally uppercase letters and 
+     * special characters and with min and max length defined by the user.
+     *
+     * @param minimumLength    the minimum length of the password
+     * @param maximumLength    the maximum length of the password
+     * @param includeUppercase if true, the password will contain at least one uppercase letter
+     * @param includeSpecial   if true, the password will contain at least one special character
+     * @return A randomly generated password
+     */
+    public String password(int minimumLength, int maximumLength, boolean includeUppercase, boolean includeSpecial) {
+        return password(minimumLength, maximumLength, includeUppercase, includeSpecial, true);
+    }
+
+    /**
+     * Generates a password with lowercase letters and optionally uppercase letters, numbers and 
+     * special characters and with min and max length defined by the user.
+     *
+     * @param minimumLength    the minimum length of the password
+     * @param maximumLength    the maximum length of the password
+     * @param includeUppercase if true, the password will contain at least one uppercase letter
+     * @param includeSpecial   if true, the password will contain at least one special character
+     * @param includeDigit     if true, the password will contain at least one digit
+     * @return A randomly generated password
+     */
+    public String password(int minimumLength, int maximumLength, boolean includeUppercase, boolean includeSpecial, boolean includeDigit) {
+        return faker.text().text(minimumLength, maximumLength, includeUppercase, includeSpecial, includeDigit);
+    }
+
+    /**
+     * Returns a weak password from a pre-defined list of common weak passwords.
+     * 
+     * Some examples are:
+     * <ul>
+     *     <li>123456</li>
+     *     <li>password</li>
+     *     <li>qwerty</li>
+     * </ul>
+     * 
+     * @return a random weak password.
+     */
+    public String weakPassword() {
+        return resolve("credentials.weak_password");
+    }
+
+    /**
+     * Generates a user ID based on the regex pattern defined in the resource file.
+     * If the regex is null or invalid, it returns null.
+     *
+     * @return A randomly generated user ID based on the regex or null if the regex is null or invalid
+     */
+    public String userId() {
+        return userId(resolve("credentials.uid_pattern"));
+    }
+
+    /**
+     * Generates a user ID based on the provided regex pattern.
+     * If the regex is null or invalid, it returns null.
+     *
+     * @param regex The regex pattern to generate the user ID
+     * @return A randomly generated user ID based on the regex or null if the regex is null or invalid
+     */
+    public String userId(String regex) {
+        if(regex == null) {
+            return null;
+        }
+
+        try {
+            Pattern.compile(regex);
+        } catch (PatternSyntaxException e) {
+            return null;
+        }
+
+        return faker.regexify(regex);
+    }
+}
diff --git a/src/main/java/net/datafaker/providers/base/Credential.java b/src/main/java/net/datafaker/providers/base/Credential.java
deleted file mode 100644
--- a/src/main/java/net/datafaker/providers/base/Credential.java
+++ /dev/null
@@ -1,169 +0,0 @@
-package net.datafaker.providers.base;
-
-import java.util.regex.Pattern;
-import java.util.regex.PatternSyntaxException;
-
-/**
- * Generates credentials such as usernames, uids and passwords.
- * 
- * @since 2.4.5
- */
-public class Credential extends AbstractProvider<BaseProviders> {
-
-    public static final int MIN_PASSWORD_LENGTH = 8;
-    public static final int MAX_PASSWORD_LENGTH = 16;
-
-    protected Credential(BaseProviders faker) {
-        super(faker);
-    }
-    
-    /**
-     * A lowercase username composed of the first_name and last_name joined with a '.'. Some examples are:
-     * <ul>
-     *     <li>(template) {@link Name#firstName()}.{@link Name#lastName()}</li>
-     *     <li>jim.jones</li>
-     *     <li>jason.leigh</li>
-     *     <li>tracy.jordan</li>
-     * </ul>
-     *
-     * @return a random two part username.
-     * @see Name#firstName()
-     * @see Name#lastName()
-     */
-    public String username() {
-        StringBuilder result = new StringBuilder();
-        final Name name = faker.name();
-        final String firstName = name.firstName().toLowerCase(faker.getContext().getLocale())
-            + "." + name.lastName().toLowerCase(faker.getContext().getLocale());
-        for (int i = 0; i < firstName.length(); i++) {
-            final char c = firstName.charAt(i);
-            if (c == '\'' || Character.isWhitespace(c)) {
-                continue;
-            }
-            result.append(c);
-        }
-        return result.toString();
-    }
-
-    /**
-     * Generates a password, only with lowercase letters, numbers and
-     * with length between 8 and 16 characters.
-     *
-     * @return A randomly generated password
-     */
-    public String password() {
-        return password(MIN_PASSWORD_LENGTH, MAX_PASSWORD_LENGTH);
-    }
-
-    /**
-     * Generates a password, only with lowercase letters and optionally numbers
-     * with length between 8 and 16 characters.
-     *
-     * @param includeDigit if true, the password will contain at least one digit
-     * @return A randomly generated password
-     */
-    public String password(boolean includeDigit) {
-        return password(MIN_PASSWORD_LENGTH, MAX_PASSWORD_LENGTH, false, false, includeDigit);
-    }
-
-    /**
-     * Generates a password, only with lowercase letters, numbers and 
-     * with min and max length defined by the user.
-     *
-     * @param minimumLength the minimum length of the password
-     * @param maximumLength the maximum length of the password
-     * @return A randomly generated password
-     */
-    public String password(int minimumLength, int maximumLength) {
-        return password(minimumLength, maximumLength, false);
-    }
-
-    /**
-     * Generates a password with lowercase and optionally uppercase letters, numbers
-     * and with min and max length defined by the user.
-     *
-     * @param minimumLength    the minimum length of the password
-     * @param maximumLength    the maximum length of the password
-     * @param includeUppercase if true, the password will contain at least one uppercase letter
-     * @return A randomly generated password
-     */
-    public String password(int minimumLength, int maximumLength, boolean includeUppercase) {
-        return password(minimumLength, maximumLength, includeUppercase, false);
-    }
-
-    /**
-     * Generates a password with lowercase letters, numbers and optionally uppercase letters and 
-     * special characters and with min and max length defined by the user.
-     *
-     * @param minimumLength    the minimum length of the password
-     * @param maximumLength    the maximum length of the password
-     * @param includeUppercase if true, the password will contain at least one uppercase letter
-     * @param includeSpecial   if true, the password will contain at least one special character
-     * @return A randomly generated password
-     */
-    public String password(int minimumLength, int maximumLength, boolean includeUppercase, boolean includeSpecial) {
-        return password(minimumLength, maximumLength, includeUppercase, includeSpecial, true);
-    }
-
-    /**
-     * Generates a password with lowercase letters and optionally uppercase letters, numbers and 
-     * special characters and with min and max length defined by the user.
-     *
-     * @param minimumLength    the minimum length of the password
-     * @param maximumLength    the maximum length of the password
-     * @param includeUppercase if true, the password will contain at least one uppercase letter
-     * @param includeSpecial   if true, the password will contain at least one special character
-     * @param includeDigit     if true, the password will contain at least one digit
-     * @return A randomly generated password
-     */
-    public String password(int minimumLength, int maximumLength, boolean includeUppercase, boolean includeSpecial, boolean includeDigit) {
-        return faker.text().text(minimumLength, maximumLength, includeUppercase, includeSpecial, includeDigit);
-    }
-
-    /**
-     * Returns a weak password from a pre-defined list of common weak passwords.
-     * 
-     * Some examples are:
-     * <ul>
-     *     <li>123456</li>
-     *     <li>password</li>
-     *     <li>qwerty</li>
-     * </ul>
-     * 
-     * @return a random weak password.
-     */
-    public String weakPassword() {
-        return resolve("credential.weak_password");
-    }
-
-    /**
-     * Generates a user ID based on the regex pattern defined in the resource file.
-     * If the regex is null or invalid, it returns null.
-     *
-     * @return A randomly generated user ID based on the regex or null if the regex is null or invalid
-     */
-    public String userId() {
-        return userId(resolve("credential.uid_pattern"));
-    }
-
-    /**
-     * Generates a user ID based on the provided regex pattern.
-     * If the regex is null or invalid, it returns null.
-     *
-     * @param regex The regex pattern to generate the user ID
-     * @return A randomly generated user ID based on the regex or null if the regex is null or invalid
-     */
-    public String userId(String regex) {
-        if(regex == null) {
-            return null;
-        }
-
-        try {
-            Pattern.compile(regex);
-        } catch (PatternSyntaxException e) {
-            return null;
-        }
-
-        return faker.regexify(regex);
-    }
-}
-diff --git a/src/main/java/net/datafaker/providers/base/BaseProviders.java b/src/main/java/net/datafaker/providers/base/BaseProviders.java
--- src/main/java/net/datafaker/providers/base/BaseProviders.java
+++ src/main/java/net/datafaker/providers/base/BaseProviders.java
@@ -136,10 +136,10 @@
     default CPF cpf() {
         return getProvider(CPF.class, CPF::new);
     }
 
-    default Credential credential() {
-        return getProvider(Credential.class, Credential::new);
+    default Credentials credentials() {
+        return getProvider(Credentials.class, Credentials::new);
     }
 
     default CryptoCoin cryptoCoin() {
         return getProvider(CryptoCoin.class, CryptoCoin::new);
diff --git a/src/main/java/net/datafaker/providers/base/Internet.java b/src/main/java/net/datafaker/providers/base/Internet.java
--- src/main/java/net/datafaker/providers/base/Internet.java
+++ src/main/java/net/datafaker/providers/base/Internet.java
@@ -260,49 +260,49 @@
         return resolve("internet.http_method");
     }
 
     /**
-     * @deprecated since 2.4.5. Use {@link net.datafaker.providers.base.Credential#password()} instead.
+     * @deprecated since 2.4.5. Use {@link net.datafaker.providers.base.Credentials#password()} instead.
      */
     @Deprecated(since = "2.4.5", forRemoval = true)
     public String password() {
         return password(8, 16);
     }
 
     /**
-     * @deprecated since 2.4.5. Use {@link net.datafaker.providers.base.Credential#password(boolean)} instead.
+     * @deprecated since 2.4.5. Use {@link net.datafaker.providers.base.Credentials#password(boolean)} instead.
      */
     @Deprecated(since = "2.4.5", forRemoval = true)
     public String password(boolean includeDigit) {
         return password(8, 16, false, false, includeDigit);
     }
 
     /**
-     * @deprecated since 2.4.5. Use {@link net.datafaker.providers.base.Credential#password(int, int)} instead.
+     * @deprecated since 2.4.5. Use {@link net.datafaker.providers.base.Credentials#password(int, int)} instead.
      */
     @Deprecated(since = "2.4.5", forRemoval = true)
     public String password(int minimumLength, int maximumLength) {
         return password(minimumLength, maximumLength, false);
     }
 
     /**
-     * @deprecated since 2.4.5. Use {@link net.datafaker.providers.base.Credential#password(int, int, boolean)} instead.
+     * @deprecated since 2.4.5. Use {@link net.datafaker.providers.base.Credentials#password(int, int, boolean)} instead.
      */
     @Deprecated(since = "2.4.5", forRemoval = true)
     public String password(int minimumLength, int maximumLength, boolean includeUppercase) {
         return password(minimumLength, maximumLength, includeUppercase, false);
     }
 
     /**
-     * @deprecated since 2.4.5. Use {@link net.datafaker.providers.base.Credential#password(int, int, boolean, boolean)} instead.
+     * @deprecated since 2.4.5. Use {@link net.datafaker.providers.base.Credentials#password(int, int, boolean, boolean)} instead.
      */
     @Deprecated(since = "2.4.5", forRemoval = true)
     public String password(int minimumLength, int maximumLength, boolean includeUppercase, boolean includeSpecial) {
         return password(minimumLength, maximumLength, includeUppercase, includeSpecial, true);
     }
 
     /**
-     * @deprecated since 2.4.5. Use {@link net.datafaker.providers.base.Credential#password(int, int, boolean, boolean, boolean)} instead.
+     * @deprecated since 2.4.5. Use {@link net.datafaker.providers.base.Credentials#password(int, int, boolean, boolean, boolean)} instead.
      */
     @Deprecated(since = "2.4.5", forRemoval = true)
     public String password(int minimumLength, int maximumLength, boolean includeUppercase, boolean includeSpecial, boolean includeDigit) {
         return faker.text().text(minimumLength, maximumLength, includeUppercase, includeSpecial, includeDigit);
diff --git a/src/main/java/net/datafaker/service/files/EnFile.java b/src/main/java/net/datafaker/service/files/EnFile.java
--- src/main/java/net/datafaker/service/files/EnFile.java
+++ src/main/java/net/datafaker/service/files/EnFile.java
@@ -76,9 +76,9 @@
         "construction.yml",
         "cosmere.yml",
         "country.yml",
         "cowboy_bebop.yml",
-        "credential.yml",
+        "credentials.yml",
         "cricket.yml",
         "crypto_coin.yml",
         "culture_series.yml",
         "currency.yml",
diff --git a/src/main/resources/en/credentials.yml b/src/main/resources/en/credentials.yml
new file mode 100644
--- /dev/null
+++ b/src/main/resources/en/credentials.yml
@@ -0,0 +1,33 @@
+en:
+  faker:
+    credential:
+      weak_password:
+      - "123456"
+      - "password"
+      - "123456789"
+      - "12345678"
+      - "12345"
+      - "111111"
+      - "1234567"
+      - "sunshine"
+      - "qwerty"
+      - "iloveyou"
+      - "princess"
+      - "admin"
+      - "welcome"
+      - "666666"
+      - "abc123"
+      - "football"
+      - "123123"
+      - "monkey"
+      - "654321"
+      - "!@#$%^&*"
+      - "charlie"
+      - "aa123456"
+      - "donald"
+      - "password1"
+      - "qwerty123"
+      uid_pattern:
+      - "\\d{6}"
+      - "[A-Z]{1}\\d{5}"
diff --git a/src/main/resources/en/credential.yml b/src/main/resources/en/credential.yml
deleted file mode 100644
--- a/src/main/resources/en/credential.yml
+++ /dev/null
@@ -1,32 +0,0 @@
-en:
-  faker:
-    credential:
-      weak_password:
-      - "123456"
-      - "password"
-      - "123456789"
-      - "12345678"
-      - "12345"
-      - "111111"
-      - "1234567"
-      - "sunshine"
-      - "qwerty"
-      - "iloveyou"
-      - "princess"
-      - "admin"
-      - "welcome"
-      - "666666"
-      - "abc123"
-      - "football"
-      - "123123"
-      - "monkey"
-      - "654321"
-      - "!@#$%^&*"
-      - "charlie"
-      - "aa123456"
-      - "donald"
-      - "password1"
-      - "qwerty123"
-      uid_pattern:
-      - "\\d{6}"
-      - "[A-Z]{1}\\d{5}"
-diff --git a/src/test/java/net/datafaker/providers/base/CredentialsTest.java b/src/test/java/net/datafaker/providers/base/CredentialsTest.java
new file mode 100644
--- /dev/null
+++ b/src/test/java/net/datafaker/providers/base/CredentialsTest.java
@@ -0,0 +1,145 @@
+package net.datafaker.providers.base;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.junit.jupiter.api.RepeatedTest;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+class CredentiasTest {
+    private final BaseFaker faker = new BaseFaker();
+
+    @RepeatedTest(100)
+    void testUsername() {
+        assertThat(faker.credentials().username()).matches("^(\\w+)\\.(\\w+)$");
+    }
+
+    @Test
+    void testUsernameWithSpaces() {
+        Name name = mock();
+        doReturn("Jin Quan").when(name).firstName();
+        doReturn("D'Artagnan").when(name).lastName();
+
+        BaseFaker mockedFaker = new BaseFaker() {
+            @Override
+            public Name name() {
+                return name;
+            }
+        };
+        assertThat(mockedFaker.credentials().username())
+            .doesNotContain(" ", "'")
+            .matches("^(\\w+)\\.(\\w+)$")
+            .matches("^\\p{javaLowerCase}+\\.\\p{javaLowerCase}+$");
+    }
+
+    @RepeatedTest(100)
+    void testPassword() {
+        assertThat(faker.credentials().password()).hasSizeBetween(8, 16).matches("^[a-z0-9]+$");
+    }
+
+    @RepeatedTest(100)
+    void testPasswordWithoutDigits() {
+        assertThat(faker.credentials().password(false)).hasSizeBetween(8, 16).matches("^[a-z]+$");
+    }
+
+    @RepeatedTest(100)
+    void testPasswordWithSpecificSize() {
+        assertThat(faker.credentials().password(3, 7)).hasSizeBetween(3, 7).matches("^[a-z0-9]+$");
+    }
+
+    @RepeatedTest(100)
+    void testPasswordWithSpecificSizeAndUppercase() {
+        assertThat(faker.credentials().password(8, 16, true)).hasSizeBetween(8, 16).matches("^[a-zA-Z0-9]+$");
+    }
+
+    @Test
+    void testPassword1000() {
+        final Pattern specialCharacterPattern = Pattern.compile("[^a-zA-Z0-9]");
+        final Pattern digitPattern = Pattern.compile("[0-9]");
+        for (int i = 0; i < 1000; i++) {
+            String password = faker.credentials().password(8, 16, true, true, true);
+            Matcher specialCharacterMatcher = specialCharacterPattern.matcher(password);
+            Matcher digitMatcher = digitPattern.matcher(password);
+
+            boolean isPasswordContainsSpecialCharacter = specialCharacterMatcher.find();
+            boolean isPasswordContainsDigit = digitMatcher.find();
+
+            assertThat(isPasswordContainsDigit).isTrue();
+            assertThat(isPasswordContainsSpecialCharacter).isTrue();
+        }
+    }
+
+    @Test
+    void passwordSpecial() {
+        boolean check = true;
+        for (int i = 0; i < 10; i++) {
+            String password = faker.credentials().password(8, 16, true, true, true);
+            Pattern specialCharacterPattern = Pattern.compile("[^a-zA-Z0-9]");
+            Matcher specialCharacterMatcher = specialCharacterPattern.matcher(password);
+            if (!specialCharacterMatcher.find()) {
+                check = false;
+                break;
+            }
+
+        }
+        assertThat(check).isTrue();
+    }
+
+    @Test
+    void passwordMix() {
+        boolean check = true;
+        for (int i = 0; i < 10; i++) {
+            String password = faker.credentials().password(8, 16, true, true, true);
+            Pattern specialCharacterPattern = Pattern.compile("[^a-zA-Z0-9]");
+            Matcher specialCharacterMatcher = specialCharacterPattern.matcher(password);
+            Pattern digitPattern = Pattern.compile("[0-9]");
+            Matcher digitMatcher = digitPattern.matcher(password);
+            if (!specialCharacterMatcher.find()) {
+                check = false;
+                break;
+            }
+            if (!digitMatcher.find()) {
+                check = false;
+                break;
+            }
+        }
+        assertThat(check).isTrue();
+    }
+
+    @Test
+    void weakPassword() {
+        Object obj = faker.fakeValuesService().fetchObject("credentials.weak_password", faker.getContext());
+        final List<String> list = (obj instanceof List<?> l
+                && l.stream().allMatch(String.class::isInstance))
+                        ? l.stream().map(String.class::cast).toList()
+                        : Collections.emptyList();
+
+        assertThat(faker.credentials().weakPassword()).isIn(list);
+    }
+
+    @RepeatedTest(100)
+    void testUserId() {
+        String uid = faker.credentials().userId();
+        assertThat(uid).matches("^([A-Z]{1})?[0-9]{5,6}$");
+    }
+
+    @Test
+    void userIdWithParameter() {
+        String uid = faker.credentials().userId(null);
+        assertThat(uid).isNull();
+
+        uid = faker.credentials().userId("*");
+        assertThat(uid).isNull();
+
+        uid = faker.credentials().userId("");
+        assertThat(uid).isEmpty();
+        System.out.println(uid);
+    }
+}
diff --git a/src/test/java/net/datafaker/providers/base/CredentialTest.java b/src/test/java/net/datafaker/providers/base/CredentialTest.java
deleted file mode 100644
--- a/src/test/java/net/datafaker/providers/base/CredentialTest.java
+++ /dev/null
@@ -1,144 +0,0 @@
-package net.datafaker.providers.base;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.junit.jupiter.api.RepeatedTest;
-import org.junit.jupiter.api.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-
-class CredentialTest {
-    private final BaseFaker faker = new BaseFaker();
-
-    @RepeatedTest(100)
-    void testUsername() {
-        assertThat(faker.credential().username()).matches("^(\\w+)\\.(\\w+)$");
-    }
-
-    @Test
-    void testUsernameWithSpaces() {
-        Name name = mock();
-        doReturn("Jin Quan").when(name).firstName();
-        doReturn("D'Artagnan").when(name).lastName();
-
-        BaseFaker mockedFaker = new BaseFaker() {
-            @Override
-            public Name name() {
-                return name;
-            }
-        };
-        assertThat(mockedFaker.credential().username())
-            .doesNotContain(" ", "'")
-            .matches("^(\\w+)\\.(\\w+)$")
-            .matches("^\\p{javaLowerCase}+\\.\\p{javaLowerCase}+$");
-    }
-
-    @RepeatedTest(100)
-    void testPassword() {
-        assertThat(faker.credential().password()).hasSizeBetween(8, 16).matches("^[a-z0-9]+$");
-    }
-
-    @RepeatedTest(100)
-    void testPasswordWithoutDigits() {
-        assertThat(faker.credential().password(false)).hasSizeBetween(8, 16).matches("^[a-z]+$");
-    }
-
-    @RepeatedTest(100)
-    void testPasswordWithSpecificSize() {
-        assertThat(faker.credential().password(3, 7)).hasSizeBetween(3, 7).matches("^[a-z0-9]+$");
-    }
-
-    @RepeatedTest(100)
-    void testPasswordWithSpecificSizeAndUppercase() {
-        assertThat(faker.credential().password(8, 16, true)).hasSizeBetween(8, 16).matches("^[a-zA-Z0-9]+$");
-    }
-
-    @Test
-    void testPassword1000() {
-        final Pattern specialCharacterPattern = Pattern.compile("[^a-zA-Z0-9]");
-        final Pattern digitPattern = Pattern.compile("[0-9]");
-        for (int i = 0; i < 1000; i++) {
-            String password = faker.credential().password(8, 16, true, true, true);
-            Matcher specialCharacterMatcher = specialCharacterPattern.matcher(password);
-            Matcher digitMatcher = digitPattern.matcher(password);
-
-            boolean isPasswordContainsSpecialCharacter = specialCharacterMatcher.find();
-            boolean isPasswordContainsDigit = digitMatcher.find();
-
-            assertThat(isPasswordContainsDigit).isTrue();
-            assertThat(isPasswordContainsSpecialCharacter).isTrue();
-        }
-    }
-
-    @Test
-    void passwordSpecial() {
-        boolean check = true;
-        for (int i = 0; i < 10; i++) {
-            String password = faker.credential().password(8, 16, true, true, true);
-            Pattern specialCharacterPattern = Pattern.compile("[^a-zA-Z0-9]");
-            Matcher specialCharacterMatcher = specialCharacterPattern.matcher(password);
-            if (!specialCharacterMatcher.find()) {
-                check = false;
-                break;
-            }
-
-        }
-        assertThat(check).isTrue();
-    }
-
-    @Test
-    void passwordMix() {
-        boolean check = true;
-        for (int i = 0; i < 10; i++) {
-            String password = faker.credential().password(8, 16, true, true, true);
-            Pattern specialCharacterPattern = Pattern.compile("[^a-zA-Z0-9]");
-            Matcher specialCharacterMatcher = specialCharacterPattern.matcher(password);
-            Pattern digitPattern = Pattern.compile("[0-9]");
-            Matcher digitMatcher = digitPattern.matcher(password);
-            if (!specialCharacterMatcher.find()) {
-                check = false;
-                break;
-            }
-            if (!digitMatcher.find()) {
-                check = false;
-                break;
-            }
-        }
-        assertThat(check).isTrue();
-    }
-
-    @Test
-    void weakPassword() {
-        Object obj = faker.fakeValuesService().fetchObject("credential.weak_password", faker.getContext());
-        final List<String> list = (obj instanceof List<?> l
-                && l.stream().allMatch(String.class::isInstance))
-                        ? l.stream().map(String.class::cast).toList()
-                        : Collections.emptyList();
-
-        assertThat(faker.credential().weakPassword()).isIn(list);
-    }
-
-    @RepeatedTest(100)
-    void testUserId() {
-        String uid = faker.credential().userId();
-        assertThat(uid).matches("^([A-Z]{1})?[0-9]{5,6}$");
-    }
-
-    @Test
-    void userIdWithParameter() {
-        String uid = faker.credential().userId(null);
-        assertThat(uid).isNull();
-
-        uid = faker.credential().userId("*");
-        assertThat(uid).isNull();
-
-        uid = faker.credential().userId("");
-        assertThat(uid).isEmpty();
-        System.out.println(uid);
-    }
-}
-

@bodiam
Copy link
Copy Markdown
Contributor

bodiam commented Aug 29, 2025

@kingthorin Thanks, love it, but I'm not sure how to apply the patch. Are you okay if I merge this PR and then we rename it?

@kingthorin
Copy link
Copy Markdown
Collaborator

Sure, no problem.
I'll tackle it Monday.

@bodiam bodiam merged commit a8cd4a2 into datafaker-net:main Aug 30, 2025
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants