Skip to content

Commit 8b60485

Browse files
authored
Enhance docs, add more tests in Vigenere (#5899)
1 parent e6f7063 commit 8b60485

File tree

2 files changed

+118
-19
lines changed

2 files changed

+118
-19
lines changed

src/main/java/com/thealgorithms/ciphers/Vigenere.java

+61-6
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,54 @@
11
package com.thealgorithms.ciphers;
22

33
/**
4-
* A Java implementation of Vigenere Cipher.
4+
* A Java implementation of the Vigenère Cipher.
5+
*
6+
* The Vigenère Cipher is a polyalphabetic substitution cipher that uses a
7+
* keyword to shift letters in the plaintext by different amounts, depending
8+
* on the corresponding character in the keyword. It wraps around the alphabet,
9+
* ensuring the shifts are within 'A'-'Z' or 'a'-'z'.
10+
*
11+
* Non-alphabetic characters (like spaces, punctuation) are kept unchanged.
12+
*
13+
* Encryption Example:
14+
* - Plaintext: "Hello World!"
15+
* - Key: "suchsecret"
16+
* - Encrypted Text: "Zynsg Yfvev!"
17+
*
18+
* Decryption Example:
19+
* - Ciphertext: "Zynsg Yfvev!"
20+
* - Key: "suchsecret"
21+
* - Decrypted Text: "Hello World!"
22+
*
23+
* Wikipedia Reference:
24+
* <a href="https://en.wikipedia.org/wiki/Vigen%C3%A8re_cipher">Vigenère Cipher - Wikipedia</a>
525
*
626
* @author straiffix
727
* @author beingmartinbmc
828
*/
929
public class Vigenere {
1030

31+
/**
32+
* Encrypts a given message using the Vigenère Cipher with the specified key.
33+
* Steps:
34+
* 1. Iterate over each character in the message.
35+
* 2. If the character is a letter, shift it by the corresponding character in the key.
36+
* 3. Preserve the case of the letter.
37+
* 4. Preserve non-alphabetic characters.
38+
* 5. Move to the next character in the key (cyclic).
39+
* 6. Return the encrypted message.
40+
*
41+
* @param message The plaintext message to encrypt.
42+
* @param key The keyword used for encryption.
43+
* @throws IllegalArgumentException if the key is empty.
44+
* @return The encrypted message.
45+
*/
1146
public String encrypt(final String message, final String key) {
12-
StringBuilder result = new StringBuilder();
47+
if (key.isEmpty()) {
48+
throw new IllegalArgumentException("Key cannot be empty.");
49+
}
1350

51+
StringBuilder result = new StringBuilder();
1452
int j = 0;
1553
for (int i = 0; i < message.length(); i++) {
1654
char c = message.charAt(i);
@@ -20,17 +58,35 @@ public String encrypt(final String message, final String key) {
2058
} else {
2159
result.append((char) ((c + key.toLowerCase().charAt(j) - 2 * 'a') % 26 + 'a'));
2260
}
61+
j = ++j % key.length();
2362
} else {
2463
result.append(c);
2564
}
26-
j = ++j % key.length();
2765
}
2866
return result.toString();
2967
}
3068

69+
/**
70+
* Decrypts a given message encrypted with the Vigenère Cipher using the specified key.
71+
* Steps:
72+
* 1. Iterate over each character in the message.
73+
* 2. If the character is a letter, shift it back by the corresponding character in the key.
74+
* 3. Preserve the case of the letter.
75+
* 4. Preserve non-alphabetic characters.
76+
* 5. Move to the next character in the key (cyclic).
77+
* 6. Return the decrypted message.
78+
*
79+
* @param message The encrypted message to decrypt.
80+
* @param key The keyword used for decryption.
81+
* @throws IllegalArgumentException if the key is empty.
82+
* @return The decrypted plaintext message.
83+
*/
3184
public String decrypt(final String message, final String key) {
32-
StringBuilder result = new StringBuilder();
85+
if (key.isEmpty()) {
86+
throw new IllegalArgumentException("Key cannot be empty.");
87+
}
3388

89+
StringBuilder result = new StringBuilder();
3490
int j = 0;
3591
for (int i = 0; i < message.length(); i++) {
3692
char c = message.charAt(i);
@@ -40,11 +96,10 @@ public String decrypt(final String message, final String key) {
4096
} else {
4197
result.append((char) ('z' - (25 - (c - key.toLowerCase().charAt(j))) % 26));
4298
}
99+
j = ++j % key.length();
43100
} else {
44101
result.append(c);
45102
}
46-
47-
j = ++j % key.length();
48103
}
49104
return result.toString();
50105
}
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.thealgorithms.ciphers;
22

33
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertThrows;
45

56
import org.junit.jupiter.api.Test;
67

@@ -9,28 +10,71 @@ class VigenereTest {
910
Vigenere vigenere = new Vigenere();
1011

1112
@Test
12-
void vigenereEncryptTest() {
13-
// given
13+
void testVigenereEncryptDecrypt() {
1414
String text = "Hello World!";
1515
String key = "suchsecret";
1616

17-
// when
18-
String cipherText = vigenere.encrypt(text, key);
17+
String encryptedText = vigenere.encrypt(text, key);
18+
String decryptedText = vigenere.decrypt(encryptedText, key);
1919

20-
// then
21-
assertEquals("Zynsg Yfvev!", cipherText);
20+
assertEquals("Zynsg Aqipw!", encryptedText);
21+
assertEquals("Hello World!", decryptedText);
2222
}
2323

2424
@Test
25-
void vigenereDecryptTest() {
26-
// given
27-
String encryptedText = "Zynsg Yfvev!";
28-
String key = "suchsecret";
25+
void testWithEmptyMessage() {
26+
String text = "";
27+
String key = "anykey";
2928

30-
// when
29+
String encryptedText = vigenere.encrypt(text, key);
3130
String decryptedText = vigenere.decrypt(encryptedText, key);
3231

33-
// then
34-
assertEquals("Hello World!", decryptedText);
32+
assertEquals("", encryptedText);
33+
assertEquals("", decryptedText);
34+
}
35+
36+
@Test
37+
void testWithEmptyKey() {
38+
String text = "This should remain the same";
39+
String key = "";
40+
41+
assertThrows(IllegalArgumentException.class, () -> vigenere.encrypt(text, key));
42+
assertThrows(IllegalArgumentException.class, () -> vigenere.decrypt(text, key));
43+
}
44+
45+
@Test
46+
void testWithNumbersInMessage() {
47+
String text = "Vigenere123!";
48+
String key = "cipher";
49+
50+
String encryptedText = vigenere.encrypt(text, key);
51+
String decryptedText = vigenere.decrypt(encryptedText, key);
52+
53+
assertEquals("Xqvlrvtm123!", encryptedText);
54+
assertEquals(text, decryptedText);
55+
}
56+
57+
@Test
58+
void testLongerKeyThanMessage() {
59+
String text = "Short";
60+
String key = "VeryLongSecretKey";
61+
62+
String encryptedText = vigenere.encrypt(text, key);
63+
String decryptedText = vigenere.decrypt(encryptedText, key);
64+
65+
assertEquals("Nlfpe", encryptedText);
66+
assertEquals(text, decryptedText);
67+
}
68+
69+
@Test
70+
void testUppercaseMessageAndKey() {
71+
String text = "HELLO";
72+
String key = "SECRET";
73+
74+
String encryptedText = vigenere.encrypt(text, key);
75+
String decryptedText = vigenere.decrypt(encryptedText, key);
76+
77+
assertEquals("ZINCS", encryptedText);
78+
assertEquals(text, decryptedText);
3579
}
3680
}

0 commit comments

Comments
 (0)