diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..41e3f3a --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +# Maven build output +target/ + +# IDE files +.idea/ +*.iml +.project +.classpath +.settings/ +.vscode/ + +# OS files +.DS_Store +Thumbs.db + +# Python testing artifacts +.venv/ +venv/ +__pycache__/ +.pytest_cache/ +*.pyc +*.pyo diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000..cb28b0e Binary files /dev/null and b/.mvn/wrapper/maven-wrapper.jar differ diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..e70e7bc --- /dev/null +++ b/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.6/apache-maven-3.9.6-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/mvnw b/mvnw new file mode 100755 index 0000000..94bf9c4 --- /dev/null +++ b/mvnw @@ -0,0 +1,148 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.2.0 +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "$(uname)" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back + # to /Library/Java/Home + if [ -z "$JAVA_HOME" ] ; then + if [ -x "/usr/libexec/java_home" ] ; then + JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME + else + JAVA_HOME="/Library/Java/Home"; export JAVA_HOME + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME="$(java-config --jre-home)" + fi +fi + +# For Cygwin and MinGW, ensure paths are in UNIX format before anything is touched +if $cygwin || $mingw ; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" +fi + +if [ -z "$JAVA_HOME" ] ; then + JAVACMD="$(which java)" +else + JAVACMD="$JAVA_HOME/bin/java" +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + echo " Please set JAVA_HOME to the location of your JDK." >&2 + exit 1 +fi + +wdir="$(cd -- "$(dirname -- "$0")" 2>/dev/null && pwd -P)" +MAVEN_PROJECTBASEDIR="${MAVEN_BASEDIR:-"$wdir"}" + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +WRAPPER_JAR="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" + +if [ -r "$WRAPPER_JAR" ]; then + if $cygwin ; then + WRAPPER_JAR="$(cygpath --path --windows "$WRAPPER_JAR")" + MAVEN_PROJECTBASEDIR="$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR")" + fi + exec "$JAVACMD" \ + $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ + -classpath "$WRAPPER_JAR" \ + "-Dmaven.multiModuleProjectDirectory=$MAVEN_PROJECTBASEDIR" \ + $WRAPPER_LAUNCHER $MAVEN_CMD_LINE_ARGS +else + # Fallback: download wrapper jar if not present + echo "Downloading Maven wrapper..." + WRAPPER_URL="$(sed -n 's/^wrapperUrl=//p' "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" 2>/dev/null)" + if [ -z "$WRAPPER_URL" ]; then + WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + fi + + if command -v wget > /dev/null; then + wget -q -O "$WRAPPER_JAR" "$WRAPPER_URL" + elif command -v curl > /dev/null; then + curl -s -L -o "$WRAPPER_JAR" "$WRAPPER_URL" + else + echo "Error: Cannot download maven-wrapper.jar. Install wget or curl." >&2 + exit 1 + fi + + if [ -r "$WRAPPER_JAR" ]; then + exec "$JAVACMD" \ + $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ + -classpath "$WRAPPER_JAR" \ + "-Dmaven.multiModuleProjectDirectory=$MAVEN_PROJECTBASEDIR" \ + $WRAPPER_LAUNCHER $MAVEN_CMD_LINE_ARGS + else + echo "Error: Could not download maven-wrapper.jar" >&2 + exit 1 + fi +fi diff --git a/mvnw.cmd b/mvnw.cmd new file mode 100644 index 0000000..ab07954 --- /dev/null +++ b/mvnw.cmd @@ -0,0 +1,137 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.2.0 +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM:// +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +set MAVEN_CMD_LINE_ARGS=%* + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% + +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +IF EXIST %WRAPPER_JAR% ( + "%JAVA_HOME%\bin\java.exe" ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS% + if ERRORLEVEL 1 goto error + goto end +) + +echo Error: Could not find maven-wrapper.jar >&2 +goto error + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="" goto end2 +pause +:end2 +exit /b %ERROR_CODE% diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..48ab2cf --- /dev/null +++ b/pom.xml @@ -0,0 +1,81 @@ + + + 4.0.0 + + com.emailslicer + emailslicer + 1.0-SNAPSHOT + jar + + Email Slicer + Java 17 implementation of the Email Slicer CLI tool + + + 17 + 17 + UTF-8 + 5.10.2 + + + + + + org.junit + junit-bom + ${junit.version} + pom + import + + + + + + + org.junit.jupiter + junit-jupiter + test + + + + + emailslicer + + + org.apache.maven.plugins + maven-compiler-plugin + 3.11.0 + + 17 + 17 + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.2.5 + + + org.apache.maven.plugins + maven-jar-plugin + 3.3.0 + + + + com.emailslicer.Main + + + + + + org.codehaus.mojo + exec-maven-plugin + 3.1.0 + + com.emailslicer.Main + + + + + diff --git a/src/main/java/com/emailslicer/EmailResult.java b/src/main/java/com/emailslicer/EmailResult.java new file mode 100644 index 0000000..a9966be --- /dev/null +++ b/src/main/java/com/emailslicer/EmailResult.java @@ -0,0 +1,10 @@ +package com.emailslicer; + +/** + * Immutable value type holding the parsed components of an email address. + * + * @param username the local part before the {@code @} symbol + * @param domain the domain part after the {@code @} symbol + */ +public record EmailResult(String username, String domain) { +} diff --git a/src/main/java/com/emailslicer/EmailSlicer.java b/src/main/java/com/emailslicer/EmailSlicer.java new file mode 100644 index 0000000..a71489c --- /dev/null +++ b/src/main/java/com/emailslicer/EmailSlicer.java @@ -0,0 +1,41 @@ +package com.emailslicer; + +import java.util.Optional; + +/** + * Utility class that parses an email address into its username and domain components. + *

+ * This mirrors the Python original's behavior: the input is trimmed, checked for the + * presence of {@code @}, and split into username (before {@code @}) and domain (after {@code @}). + */ +public final class EmailSlicer { + + private EmailSlicer() { + // Utility class — prevent instantiation + } + + /** + * Slices an email address into its username and domain parts. + * + * @param email the raw email string (may include leading/trailing whitespace) + * @return an {@link Optional} containing the parsed {@link EmailResult}, + * or {@link Optional#empty()} if the input is null or does not contain {@code @} + */ + public static Optional slice(String email) { + if (email == null) { + return Optional.empty(); + } + + String trimmed = email.strip(); + + int atIndex = trimmed.indexOf('@'); + if (atIndex == -1) { + return Optional.empty(); + } + + String username = trimmed.substring(0, atIndex); + String domain = trimmed.substring(atIndex + 1); + + return Optional.of(new EmailResult(username, domain)); + } +} diff --git a/src/main/java/com/emailslicer/Main.java b/src/main/java/com/emailslicer/Main.java new file mode 100644 index 0000000..3bd7413 --- /dev/null +++ b/src/main/java/com/emailslicer/Main.java @@ -0,0 +1,28 @@ +package com.emailslicer; + +import java.util.Scanner; + +/** + * Console entry point for the Email Slicer CLI tool. + *

+ * Mirrors the Python original's user-facing behavior: + * prompts for an email address, parses it, and prints the username and domain. + */ +public class Main { + + public static void main(String[] args) { + System.out.println("Please enter your Email Id:"); + + try (Scanner scanner = new Scanner(System.in)) { + String email = scanner.nextLine(); + + EmailSlicer.slice(email).ifPresentOrElse( + result -> { + System.out.println("Your username is: " + result.username()); + System.out.println("Your domain is: " + result.domain()); + }, + () -> System.out.println("Please enter a valid Email Id.") + ); + } + } +} diff --git a/src/test/java/com/emailslicer/EmailSlicerTest.java b/src/test/java/com/emailslicer/EmailSlicerTest.java new file mode 100644 index 0000000..990892c --- /dev/null +++ b/src/test/java/com/emailslicer/EmailSlicerTest.java @@ -0,0 +1,131 @@ +package com.emailslicer; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.NullSource; +import org.junit.jupiter.params.provider.ValueSource; + +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Unit tests for {@link EmailSlicer#slice(String)}. + */ +class EmailSlicerTest { + + // ---- Valid emails ---- + + @ParameterizedTest(name = "valid email: {0} -> username={1}, domain={2}") + @CsvSource({ + "user@domain.com, user, domain.com", + "first.last@sub.domain.org, first.last, sub.domain.org", + "alice@example.io, alice, example.io", + "a@b, a, b" + }) + void slice_validEmail_returnsExpectedParts(String email, String expectedUser, String expectedDomain) { + Optional result = EmailSlicer.slice(email); + + assertTrue(result.isPresent(), "Expected a result for: " + email); + assertEquals(expectedUser, result.get().username()); + assertEquals(expectedDomain, result.get().domain()); + } + + // ---- Whitespace trimming ---- + + @Test + void slice_leadingAndTrailingWhitespace_isTrimmed() { + Optional result = EmailSlicer.slice(" user@domain.com "); + + assertTrue(result.isPresent()); + assertEquals("user", result.get().username()); + assertEquals("domain.com", result.get().domain()); + } + + @Test + void slice_tabsAndNewlines_areTrimmed() { + Optional result = EmailSlicer.slice("\t user@domain.com \n"); + + assertTrue(result.isPresent()); + assertEquals("user", result.get().username()); + assertEquals("domain.com", result.get().domain()); + } + + // ---- Invalid emails ---- + + @ParameterizedTest(name = "invalid email: \"{0}\" -> empty") + @ValueSource(strings = { + "invalidemail", + "", + " ", + "noatsign" + }) + void slice_noAtSign_returnsEmpty(String email) { + Optional result = EmailSlicer.slice(email); + + assertTrue(result.isEmpty(), "Expected empty for: \"" + email + "\""); + } + + @ParameterizedTest(name = "null input -> empty") + @NullSource + void slice_null_returnsEmpty(String email) { + Optional result = EmailSlicer.slice(email); + + assertTrue(result.isEmpty()); + } + + // ---- Edge cases matching Python behavior ---- + // The Python original only checks for @ presence; these inputs are accepted + // by the Python version and should also be accepted here for behavioral parity. + + @Test + void slice_emptyUsername_returnsResult() { + // Python: "@domain.com" -> username="", domain="domain.com" + Optional result = EmailSlicer.slice("@domain.com"); + + assertTrue(result.isPresent()); + assertEquals("", result.get().username()); + assertEquals("domain.com", result.get().domain()); + } + + @Test + void slice_emptyDomain_returnsResult() { + // Python: "user@" -> username="user", domain="" + Optional result = EmailSlicer.slice("user@"); + + assertTrue(result.isPresent()); + assertEquals("user", result.get().username()); + assertEquals("", result.get().domain()); + } + + @Test + void slice_multipleAtSigns_splitsOnFirst() { + // Python: "a@b@c" -> username="a", domain="b@c" (uses index of first @) + Optional result = EmailSlicer.slice("a@b@c"); + + assertTrue(result.isPresent()); + assertEquals("a", result.get().username()); + assertEquals("b@c", result.get().domain()); + } + + // ---- EmailResult record ---- + + @Test + void emailResult_equalsAndHashCode() { + EmailResult a = new EmailResult("user", "domain.com"); + EmailResult b = new EmailResult("user", "domain.com"); + + assertEquals(a, b); + assertEquals(a.hashCode(), b.hashCode()); + } + + @Test + void emailResult_toString_containsFields() { + EmailResult result = new EmailResult("user", "domain.com"); + String str = result.toString(); + + assertTrue(str.contains("user")); + assertTrue(str.contains("domain.com")); + } +}