1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2024-12-23 19:38:00 +01:00

Merge pull request #92 from IvanPizhenko/91-imporve-class-userid

issue #91 Improve class UserId
This commit is contained in:
Paul Schaub 2021-02-21 15:23:50 +01:00 committed by GitHub
commit b30fc2beec
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 285 additions and 84 deletions

View file

@ -1,5 +1,5 @@
/* /*
* Copyright 2020 Paul Schaub. * Copyright 2020 Paul Schaub. Copyright 2021 Flowcrypt a.s.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -13,13 +13,66 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.pgpainless.key.util; package org.pgpainless.key.util;
public final class UserId implements CharSequence { public final class UserId implements CharSequence {
public static final class Builder {
private String name;
private String comment;
private String email;
private Builder() {
}
private Builder(String name, String comment, String email) {
this.name = name;
this.comment = comment;
this.email = email;
}
public Builder withName(String name) {
checkNotNull("name", name);
this.name = name;
return this;
}
public Builder withComment(String comment) {
checkNotNull("comment", comment);
this.comment = comment;
return this;
}
public Builder withEmail(String email) {
checkNotNull("email", email);
this.email = email;
return this;
}
public Builder noName() {
name = null;
return this;
}
public Builder noComment() {
comment = null;
return this;
}
public Builder noEmail() {
email = null;
return this;
}
public UserId build() {
return new UserId(name, comment, email);
}
}
private final String name; private final String name;
private final String comment; private final String comment;
private final String email; private final String email;
private long hash = Long.MAX_VALUE;
private UserId(String name, String comment, String email) { private UserId(String name, String comment, String email) {
this.name = name; this.name = name;
@ -27,85 +80,36 @@ public final class UserId implements CharSequence {
this.email = email; this.email = email;
} }
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
if (name != null) {
sb.append(name);
}
if (comment != null) {
sb.append(" (").append(comment).append(')');
}
if (email != null) {
sb.append(sb.length() != 0 ? ' ' : "").append(email);
}
return sb.toString();
}
public static UserId onlyEmail(String email) { public static UserId onlyEmail(String email) {
if (email == null) { checkNotNull("email", email);
throw new IllegalArgumentException("Email must not be null.");
}
return new UserId(null, null, email); return new UserId(null, null, email);
} }
public static UserId nameAndEmail(String name, String email) { public static UserId nameAndEmail(String name, String email) {
return withName(name).noComment().withEmail(email); checkNotNull("name", name);
checkNotNull("email", email);
return new UserId(name, null, email);
} }
public static WithComment withName(String name) { public static Builder newBuilder() {
if (name == null) { return new Builder();
throw new IllegalArgumentException("Name must not be null.");
}
return new WithComment(name);
} }
public static class WithComment { public Builder toBuilder() {
return new Builder(name, comment, email);
private final String name;
public WithComment(String name) {
this.name = name;
} }
public WithEmail withComment(String comment) { public String getName() {
if (comment == null) { return name;
throw new IllegalArgumentException("Comment must not be null.");
}
return new WithEmail(name, comment);
} }
public WithEmail noComment() { public String getComment() {
return new WithEmail(name, null); return comment;
} }
public UserId build() { public String getEmail() {
return new UserId(name, null, null); return email;
} }
}
public static class WithEmail {
private final String name;
private final String comment;
public WithEmail(String name, String comment) {
this.name = name;
this.comment = comment;
}
public UserId withEmail(String email) {
if (email == null) {
throw new IllegalArgumentException("Email must not be null.");
}
return new UserId(name, comment, email.matches("^<.+>$") ? email : '<' + email + '>');
}
public UserId noEmail() {
return new UserId(name, comment, null);
}
}
@Override @Override
public int length() { public int length() {
@ -122,4 +126,69 @@ public final class UserId implements CharSequence {
return toString().subSequence(i, i1); return toString().subSequence(i, i1);
} }
@Override
public String toString() {
return asString(false);
}
/**
* Returns a string representation of the object.
* @param ignoreEmptyValues Flag which indicates that empty string values should not be outputted.
* @return a string representation of the object.
*/
public String asString(boolean ignoreEmptyValues) {
StringBuilder sb = new StringBuilder();
if (name != null && (!ignoreEmptyValues || !name.isEmpty())) {
sb.append(name);
}
if (comment != null && (!ignoreEmptyValues || !comment.isEmpty())) {
sb.append(" (").append(comment).append(')');
}
if (email != null && (!ignoreEmptyValues || !email.isEmpty())) {
final boolean moreThanJustEmail = sb.length() > 0;
if (moreThanJustEmail) sb.append(" <");
sb.append(email);
if (moreThanJustEmail) sb.append('>');
}
return sb.toString();
}
@Override
public boolean equals(Object o) {
if (o == null) return false;
if (o == this) return true;
if (!(o instanceof UserId)) return false;
final UserId other = (UserId) o;
return isEqualComponent(name, other.name, false)
&& isEqualComponent(comment, other.comment, false)
&& isEqualComponent(email, other.email, true);
}
@Override
public int hashCode() {
if (hash != Long.MAX_VALUE) {
return (int) hash;
} else {
int hash = 7;
hash = 31 * hash + (name == null ? 0 : name.hashCode());
hash = 31 * hash + (comment == null ? 0 : comment.hashCode());
hash = 31 * hash + (email == null ? 0 : email.toLowerCase().hashCode());
this.hash = hash;
return hash;
}
}
private static boolean isEqualComponent(String value, String otherValue, boolean ignoreCase) {
final boolean valueIsNull = (value == null);
final boolean otherValueIsNull = (otherValue == null);
return (valueIsNull && otherValueIsNull)
|| (!valueIsNull && !otherValueIsNull
&& (ignoreCase ? value.equalsIgnoreCase(otherValue) : value.equals(otherValue)));
}
private static void checkNotNull(String paramName, String value) {
if (value == null) {
throw new IllegalArgumentException(paramName + " must be not null");
}
}
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright 2020 Paul Schaub. * Copyright 2020 Paul Schaub. Copyright 2021 Flowcrypt a.s.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -15,37 +15,36 @@
*/ */
package org.pgpainless.key; package org.pgpainless.key;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.pgpainless.key.util.UserId; import org.pgpainless.key.util.UserId;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class UserIdTest { public class UserIdTest {
@Test @Test
public void throwForNullName() { public void throwForNullName() {
assertThrows(IllegalArgumentException.class, () -> UserId.withName(null)); assertThrows(IllegalArgumentException.class, () -> UserId.newBuilder().withName(null));
} }
@Test @Test
public void throwForNullComment() { public void throwForNullComment() {
assertThrows(IllegalArgumentException.class, () -> UserId.withName("foo") assertThrows(IllegalArgumentException.class, () -> UserId.newBuilder().withComment(null));
.withComment(null));
} }
@Test @Test
public void throwForNullEmail() { public void throwForNullEmail() {
assertThrows(IllegalArgumentException.class, () -> UserId.withName("foo") assertThrows(IllegalArgumentException.class, () -> UserId.newBuilder().withEmail(null));
.withComment("bar")
.withEmail(null));
} }
@Test @Test
public void testFormatOnlyName() { public void testFormatOnlyName() {
assertEquals( assertEquals(
"Juliet Capulet", "Juliet Capulet",
UserId.withName("Juliet Capulet") UserId.newBuilder().withName("Juliet Capulet")
.build().toString()); .build().toString());
} }
@ -53,26 +52,28 @@ public class UserIdTest {
public void testFormatNameAndComment() { public void testFormatNameAndComment() {
assertEquals( assertEquals(
"Juliet Capulet (from the play)", "Juliet Capulet (from the play)",
UserId.withName("Juliet Capulet") UserId.newBuilder().withName("Juliet Capulet")
.withComment("from the play") .withComment("from the play")
.noEmail().toString()); .noEmail().build().toString());
} }
@Test @Test
public void testFormatNameCommentAndMail() { public void testFormatNameCommentAndMail() {
assertEquals("Juliet Capulet (from the play) <juliet@capulet.lit>", assertEquals("Juliet Capulet (from the play) <juliet@capulet.lit>",
UserId.withName("Juliet Capulet") UserId.newBuilder().withName("Juliet Capulet")
.withComment("from the play") .withComment("from the play")
.withEmail("juliet@capulet.lit") .withEmail("juliet@capulet.lit")
.build()
.toString()); .toString());
} }
@Test @Test
public void testFormatNameAndEmail() { public void testFormatNameAndEmail() {
assertEquals("Juliet Capulet <juliet@capulet.lit>", assertEquals("Juliet Capulet <juliet@capulet.lit>",
UserId.withName("Juliet Capulet") UserId.newBuilder().withName("Juliet Capulet")
.noComment() .noComment()
.withEmail("juliet@capulet.lit") .withEmail("juliet@capulet.lit")
.build()
.toString()); .toString());
} }
@ -86,4 +87,134 @@ public class UserIdTest {
UserId userId = UserId.nameAndEmail("Maurice Moss", "moss.m@reynholm.co.uk"); UserId userId = UserId.nameAndEmail("Maurice Moss", "moss.m@reynholm.co.uk");
assertEquals("Maurice Moss <moss.m@reynholm.co.uk>", userId.toString()); assertEquals("Maurice Moss <moss.m@reynholm.co.uk>", userId.toString());
} }
@Test
void testBuilderWithName() {
final UserId userId = UserId.newBuilder().withName("John Smith").build();
assertEquals("John Smith", userId.getName());
assertNull(userId.getComment());
assertNull(userId.getEmail());
}
@Test
void testBuilderWithComment() {
final UserId userId = UserId.newBuilder().withComment("Sales Dept.").build();
assertNull(userId.getName());
assertEquals("Sales Dept.", userId.getComment());
assertNull(userId.getEmail());
}
@Test
void testBuilderWithEmail() {
final UserId userId = UserId.newBuilder().withEmail("john.smith@example.com").build();
assertNull(userId.getName());
assertNull(userId.getComment());
assertEquals("john.smith@example.com", userId.getEmail());
}
@Test
void testBuilderWithAll() {
final UserId userId = UserId.newBuilder().withEmail("john.smith@example.com")
.withName("John Smith")
.withEmail("john.smith@example.com")
.withComment("Sales Dept.").build();
assertEquals("John Smith", userId.getName());
assertEquals("Sales Dept.", userId.getComment());
assertEquals("john.smith@example.com", userId.getEmail());
}
@Test
void testBuilderNoName() {
final UserId.Builder builder = UserId.newBuilder()
.withEmail("john.smith@example.com")
.withName("John Smith")
.withComment("Sales Dept.").build().toBuilder();
final UserId userId = builder.noName().build();
assertNull(userId.getName());
assertEquals("Sales Dept.", userId.getComment());
assertEquals("john.smith@example.com", userId.getEmail());
}
@Test
void testBuilderNoComment() {
final UserId.Builder builder = UserId.newBuilder()
.withEmail("john.smith@example.com")
.withName("John Smith")
.withComment("Sales Dept.").build().toBuilder();
final UserId userId = builder.noComment().build();
assertEquals("John Smith", userId.getName());
assertNull(userId.getComment());
assertEquals("john.smith@example.com", userId.getEmail());
}
@Test
void testBuilderNoEmail() {
final UserId.Builder builder = UserId.newBuilder()
.withEmail("john.smith@example.com")
.withName("John Smith")
.withComment("Sales Dept.").build().toBuilder();
final UserId userId = builder.noEmail().build();
assertEquals("John Smith", userId.getName());
assertEquals("Sales Dept.", userId.getComment());
assertNull(userId.getEmail());
}
@Test
void testEmailOnlyFormatting() {
final UserId userId = UserId.onlyEmail("john.smith@example.com");
assertEquals("john.smith@example.com", userId.toString());
}
@Test
void testEmptyNameAndValidEmailFormatting() {
final UserId userId = UserId.nameAndEmail("", "john.smith@example.com");
assertEquals("john.smith@example.com", userId.toString());
assertEquals("john.smith@example.com", userId.asString(false));
assertEquals("john.smith@example.com", userId.asString(true));
}
@Test
void testEmptyNameAndEmptyCommentAndValidEmailFormatting() {
final UserId userId = UserId.newBuilder()
.withComment("")
.withName("")
.withEmail("john.smith@example.com")
.build();
assertEquals(" () <john.smith@example.com>", userId.toString());
assertEquals(" () <john.smith@example.com>", userId.asString(false));
assertEquals("john.smith@example.com", userId.asString(true));
}
@Test
void testEqualsWithDifferentCaseEmails() {
final String name = "John Smith";
final String comment = "Sales Dept.";
final String email = "john.smith@example.com";
final String upperEmail = email.toUpperCase();
final UserId userId1 = UserId.newBuilder().withComment(comment).withName(name).withEmail(email).build();
final UserId userId2 = UserId.newBuilder().withComment(comment).withName(name).withEmail(upperEmail).build();
assertEquals(userId1, userId2);
}
@Test
void testNotEqualWithDifferentNames() {
final String name1 = "John Smith";
final String name2 = "Don Duck";
final String comment = "Sales Dept.";
final String email = "john.smith@example.com";
final UserId userId1 = UserId.newBuilder().withComment(comment).withName(name1).withEmail(email).build();
final UserId userId2 = UserId.newBuilder().withComment(comment).withName(name2).withEmail(email).build();
assertNotEquals(userId1, userId2);
}
@Test
void testNotEqualWithDifferentComments() {
final String name = "John Smith";
final String comment1 = "Sales Dept.";
final String comment2 = "Legal Dept.";
final String email = "john.smith@example.com";
final UserId userId1 = UserId.newBuilder().withComment(comment1).withName(name).withEmail(email).build();
final UserId userId2 = UserId.newBuilder().withComment(comment2).withName(name).withEmail(email).build();
assertNotEquals(userId1, userId2);
}
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright 2021 Ivan Pizhenko, Paul Schaub. * Copyright 2021 Paul Schaub. Copyright 2021 Flowcrypt a.s.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -39,7 +39,8 @@ public class SelectUserIdTest {
.simpleEcKeyRing("<alice@wonderland.lit>"); .simpleEcKeyRing("<alice@wonderland.lit>");
secretKeys = PGPainless.modifyKeyRing(secretKeys) secretKeys = PGPainless.modifyKeyRing(secretKeys)
.addUserId( .addUserId(
UserId.withName("Alice Liddell").noComment().withEmail("crazy@the-rabbit.hole"), UserId.newBuilder().withName("Alice Liddell").noComment()
.withEmail("crazy@the-rabbit.hole").build(),
SecretKeyRingProtector.unprotectedKeys()) SecretKeyRingProtector.unprotectedKeys())
.done(); .done();