From 3d064fa68de9953536ba5c427b2b9e0b70021b27 Mon Sep 17 00:00:00 2001 From: Maarten Billemont Date: Fri, 5 Dec 2014 02:17:28 -0500 Subject: [PATCH] A full test script for various inputs and a Java TestNG implementation that tests it. --- .../lyndir/masterpassword/MPElementType.java | 17 ++ .../masterpassword/MPElementVariant.java | 17 ++ .../com/lyndir/masterpassword/MPWTests.java | 189 ++++++++++++++++++ .../lyndir/masterpassword/MasterKeyTest.java | 78 ++++---- .../src/test/resources/logback.xml | 15 ++ .../src/test/resources/mpw_tests.xml | 72 +++++++ 6 files changed, 348 insertions(+), 40 deletions(-) create mode 100644 MasterPassword/Java/masterpassword-algorithm/src/test/java/com/lyndir/masterpassword/MPWTests.java create mode 100644 MasterPassword/Java/masterpassword-algorithm/src/test/resources/logback.xml create mode 100644 MasterPassword/Java/masterpassword-algorithm/src/test/resources/mpw_tests.xml diff --git a/MasterPassword/Java/masterpassword-algorithm/src/main/java/com/lyndir/masterpassword/MPElementType.java b/MasterPassword/Java/masterpassword-algorithm/src/main/java/com/lyndir/masterpassword/MPElementType.java index b2cc8338..ac69d9e0 100644 --- a/MasterPassword/Java/masterpassword-algorithm/src/main/java/com/lyndir/masterpassword/MPElementType.java +++ b/MasterPassword/Java/masterpassword-algorithm/src/main/java/com/lyndir/masterpassword/MPElementType.java @@ -122,6 +122,23 @@ public enum MPElementType { throw logger.bug( "No type for option: %s", option ); } + /** + * @param name The name of the type to look up. It is matched case insensitively. + * + * @return The type registered with the given name. + */ + public static MPElementType forName(final String name) { + + if (name == null) + return null; + + for (final MPElementType type : values()) + if (type.name().equalsIgnoreCase( name )) + return type; + + throw logger.bug( "No type for name: %s", name ); + } + /** * @param typeClass The class for which we look up types. * diff --git a/MasterPassword/Java/masterpassword-algorithm/src/main/java/com/lyndir/masterpassword/MPElementVariant.java b/MasterPassword/Java/masterpassword-algorithm/src/main/java/com/lyndir/masterpassword/MPElementVariant.java index c212bd36..dbbea3b6 100644 --- a/MasterPassword/Java/masterpassword-algorithm/src/main/java/com/lyndir/masterpassword/MPElementVariant.java +++ b/MasterPassword/Java/masterpassword-algorithm/src/main/java/com/lyndir/masterpassword/MPElementVariant.java @@ -60,4 +60,21 @@ public enum MPElementVariant { throw logger.bug( "No variant for option: %s", option ); } + /** + * @param name The name of the variant to look up. It is matched case insensitively. + * + * @return The variant registered with the given name. + */ + public static MPElementVariant forName(final String name) { + + if (name == null) + return null; + + for (final MPElementVariant type : values()) + if (type.name().equalsIgnoreCase( name )) + return type; + + throw logger.bug( "No variant for name: %s", name ); + } + } diff --git a/MasterPassword/Java/masterpassword-algorithm/src/test/java/com/lyndir/masterpassword/MPWTests.java b/MasterPassword/Java/masterpassword-algorithm/src/test/java/com/lyndir/masterpassword/MPWTests.java new file mode 100644 index 00000000..a95ae75e --- /dev/null +++ b/MasterPassword/Java/masterpassword-algorithm/src/test/java/com/lyndir/masterpassword/MPWTests.java @@ -0,0 +1,189 @@ +package com.lyndir.masterpassword; + +import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*; + +import com.google.common.base.Verify; +import com.lyndir.lhunath.opal.system.logging.Logger; +import com.lyndir.lhunath.opal.system.util.NFunctionNN; +import com.lyndir.lhunath.opal.system.util.NNSupplier; +import java.util.List; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.xml.bind.annotation.*; + + +/** + * @author lhunath, 14-12-05 + */ +@XmlRootElement(name = "tests") +public class MPWTests { + + public static final String ID_DEFAULT = "default"; + + @SuppressWarnings("UnusedDeclaration") + private static final Logger logger = Logger.get( MPWTests.class ); + + @XmlElement(name = "case") + private List cases; + + public List getCases() { + return cases; + } + + public Case getCase(String identifier) { + for (Case testCase : getCases()) + if (identifier.equals( testCase.getIdentifier() )) + return testCase; + + throw new IllegalArgumentException( "No case for identifier: " + identifier ); + } + + @XmlRootElement(name = "case") + public static class Case { + + @XmlAttribute(name = "id") + private String identifier; + @XmlAttribute + private String parent; + @XmlElement + private String fullName; + @XmlElement + private String masterPassword; + @XmlElement + private String keyID; + @XmlElement + private String siteName; + @XmlElement + private Integer siteCounter; + @XmlElement + private String siteType; + @XmlElement + private String siteVariant; + @XmlElement + private String siteContext; + @XmlElement + private String result; + + private transient Case parentCase; + + public void setTests(MPWTests tests) { + + if (parent != null) { + parentCase = tests.getCase( parent ); + fullName = ifNotNullElse( fullName, new NNSupplier() { + @Nonnull + @Override + public String get() { + return parentCase.getFullName(); + } + } ); + masterPassword = ifNotNullElse( masterPassword, new NNSupplier() { + @Nonnull + @Override + public String get() { + return parentCase.getMasterPassword(); + } + } ); + keyID = ifNotNullElse( keyID, new NNSupplier() { + @Nonnull + @Override + public String get() { + return parentCase.getKeyID(); + } + } ); + siteName = ifNotNullElse( siteName, new NNSupplier() { + @Nonnull + @Override + public String get() { + return parentCase.getSiteName(); + } + } ); + siteCounter = ifNotNullElse( siteCounter, new NNSupplier() { + @Nonnull + @Override + public Integer get() { + return parentCase.getSiteCounter(); + } + } ); + siteType = ifNotNullElse( siteType, new NNSupplier() { + @Nonnull + @Override + public String get() { + return parentCase.getSiteType().name(); + } + } ); + siteVariant = ifNotNullElse( siteVariant, new NNSupplier() { + @Nonnull + @Override + public String get() { + return parentCase.getSiteVariant().name(); + } + } ); + siteContext = ifNotNullElse( siteContext, new NNSupplier() { + @Nonnull + @Override + public String get() { + return parentCase.getSiteContext(); + } + } ); + result = ifNotNullElse( result, new NNSupplier() { + @Nonnull + @Override + public String get() { + return parentCase.getResult(); + } + } ); + } + } + + public String getIdentifier() { + return identifier; + } + + @Nullable + public Case getParentCase() { + return parentCase; + } + + public String getFullName() { + return fullName; + } + + public String getMasterPassword() { + return masterPassword; + } + + public String getKeyID() { + return keyID; + } + + public String getSiteName() { + return siteName; + } + + public int getSiteCounter() { + return siteCounter; + } + + public MPElementType getSiteType() { + return MPElementType.forName( siteType ); + } + + public MPElementVariant getSiteVariant() { + return MPElementVariant.forName( siteVariant ); + } + + public String getSiteContext() { + return siteContext; + } + + public String getResult() { + return result; + } + + @Override + public String toString() { + return identifier; + } + } +} diff --git a/MasterPassword/Java/masterpassword-algorithm/src/test/java/com/lyndir/masterpassword/MasterKeyTest.java b/MasterPassword/Java/masterpassword-algorithm/src/test/java/com/lyndir/masterpassword/MasterKeyTest.java index f83398a7..15498cac 100644 --- a/MasterPassword/Java/masterpassword-algorithm/src/test/java/com/lyndir/masterpassword/MasterKeyTest.java +++ b/MasterPassword/Java/masterpassword-algorithm/src/test/java/com/lyndir/masterpassword/MasterKeyTest.java @@ -2,65 +2,62 @@ package com.lyndir.masterpassword; import static org.testng.Assert.*; +import com.google.common.io.Resources; +import com.lyndir.lhunath.opal.system.logging.Logger; +import java.net.URL; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.Unmarshaller; +import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; public class MasterKeyTest { - private static final String FULL_NAME = "Robert Lee Mitchell"; - private static final String MASTER_PASSWORD = "banana colored duckling"; - private static final String SITE_NAME = "masterpasswordapp.com"; + @SuppressWarnings("UnusedDeclaration") + private static final Logger logger = Logger.get( MasterKeyTest.class ); + + private MPWTests tests; + private MPWTests.Case defaultCase; + + @BeforeMethod + public void setUp() + throws Exception { + + URL testCasesResource = Resources.getResource( "mpw_tests.xml" ); + tests = (MPWTests) JAXBContext.newInstance( MPWTests.class ).createUnmarshaller().unmarshal( testCasesResource ); + for (MPWTests.Case testCase : tests.getCases()) + testCase.setTests( tests ); + defaultCase = tests.getCase( MPWTests.ID_DEFAULT ); + } @Test public void testEncode() throws Exception { - MasterKey masterKey = new MasterKey( FULL_NAME, MASTER_PASSWORD ); - - assertEquals( masterKey.encode( SITE_NAME, MPElementType.GeneratedLong, 1, MPElementVariant.Password, null ), // - "Jejr5[RepuSosp" ); - - assertEquals( masterKey.encode( "\u26C4", MPElementType.GeneratedMaximum, 1, MPElementVariant.Password, null ), // - "bp7rJKc7kaXc4sxOwG0*" ); - - assertEquals( masterKey.encode( "\u26C4", MPElementType.GeneratedLong, 1, MPElementVariant.Password, null ), // - "LiheCuwhSerz6)" ); - - assertEquals( masterKey.encode( "\u26C4", MPElementType.GeneratedMedium, 1, MPElementVariant.Password, null ), // - "LihPih8+" ); - - assertEquals( masterKey.encode( "\u26C4", MPElementType.GeneratedBasic, 1, MPElementVariant.Password, null ), // - "bpW62jmW" ); - - assertEquals( masterKey.encode( "\u26C4", MPElementType.GeneratedShort, 1, MPElementVariant.Password, null ), // - "Lih6" ); - - assertEquals( masterKey.encode( "\u26C4", MPElementType.GeneratedPIN, 1, MPElementVariant.Password, null ), // - "9216" ); - - assertEquals( masterKey.encode( "\u26C4", MPElementType.GeneratedName, 1, MPElementVariant.Password, null ), // - "lihpihohi" ); - - assertEquals( masterKey.encode( "\u26C4", MPElementType.GeneratedPhrase, 1, MPElementVariant.Password, null ), // - "li pihwe puz bemozno" ); - - assertEquals( masterKey.encode( "\u26C4", MPElementType.GeneratedMaximum, (int) 4294967295L, MPElementVariant.Password, null ), - "r*)Ekr(FiduISCj*pg5-" ); + for (MPWTests.Case testCase : tests.getCases()) { + MasterKey masterKey = new MasterKey( testCase.getFullName(), testCase.getMasterPassword() ); + assertEquals( masterKey.encode( testCase.getSiteName(), testCase.getSiteType(), testCase.getSiteCounter(), + testCase.getSiteVariant(), testCase.getSiteContext() ), testCase.getResult(), + "Failed test case: " + testCase ); + } } @Test public void testGetUserName() throws Exception { - assertEquals( new MasterKey( FULL_NAME, "banana colored duckling" ).getUserName(), FULL_NAME ); + assertEquals( new MasterKey( defaultCase.getFullName(), defaultCase.getMasterPassword() ).getUserName(), + defaultCase.getFullName() ); } @Test public void testGetKeyID() throws Exception { - assertEquals( new MasterKey( FULL_NAME, "banana colored duckling" ).getKeyID(), - "98EEF4D1DF46D849574A82A03C3177056B15DFFCA29BB3899DE4628453675302" ); + for (MPWTests.Case testCase : tests.getCases()) { + MasterKey masterKey = new MasterKey( testCase.getFullName(), testCase.getMasterPassword() ); + assertEquals( masterKey.getKeyID(), testCase.getKeyID(), "Failed test case: " + testCase ); + } } @Test @@ -68,10 +65,11 @@ public class MasterKeyTest { throws Exception { try { - MasterKey masterKey = new MasterKey( FULL_NAME, MASTER_PASSWORD ); + MasterKey masterKey = new MasterKey( defaultCase.getFullName(), defaultCase.getMasterPassword() ); masterKey.invalidate(); - masterKey.encode( SITE_NAME, MPElementType.GeneratedLong, 1, MPElementVariant.Password, null ); - assertFalse( true, "Master key was not invalidated." ); + masterKey.encode( defaultCase.getSiteName(), defaultCase.getSiteType(), defaultCase.getSiteCounter(), + defaultCase.getSiteVariant(), defaultCase.getSiteContext() ); + assertTrue( false, "Master key should have been invalidated, but was still usable." ); } catch (IllegalStateException ignored) { } diff --git a/MasterPassword/Java/masterpassword-algorithm/src/test/resources/logback.xml b/MasterPassword/Java/masterpassword-algorithm/src/test/resources/logback.xml new file mode 100644 index 00000000..3d4d25c6 --- /dev/null +++ b/MasterPassword/Java/masterpassword-algorithm/src/test/resources/logback.xml @@ -0,0 +1,15 @@ + + + + + %-8relative %22c{0} [%-5level] %msg%n + + + + + + + + + + diff --git a/MasterPassword/Java/masterpassword-algorithm/src/test/resources/mpw_tests.xml b/MasterPassword/Java/masterpassword-algorithm/src/test/resources/mpw_tests.xml new file mode 100644 index 00000000..4b6280c0 --- /dev/null +++ b/MasterPassword/Java/masterpassword-algorithm/src/test/resources/mpw_tests.xml @@ -0,0 +1,72 @@ + + + Robert Lee Mitchell + banana colored duckling + 98EEF4D1DF46D849574A82A03C3177056B15DFFCA29BB3899DE4628453675302 + masterpasswordapp.com + 1 + GeneratedLong + Password + + Jejr5[RepuSosp + + + + 1717AA1F9BF5BA56CD0965CDA3D78E6D2E6A1EA8C067A8EA621F3DDAD4A87EB8 + NopaDajh8=Fene + + + + 351432B8528A5ABECAB768CA95015097DE76FE14C41E10AF36C67DCFB8917E08 + QesuHirv5-Xepl + + + + LiheCuwhSerz6) + + + Login + WohzKifuDilo5, + + + Answer + XineDiyj2)Tozz + + + question + XineDiyj2)Tozz + + + GeneratedMaximum + W6@692^B1#&@gVdSdLZ@ + + + GeneratedMedium + Jej2$Quv + + + GeneratedBasic + WAo2xIg6 + + + GeneratedShort + Jej2 + + + GeneratedPIN + 7662 + + + GeneratedName + jejraquvo + + + GeneratedPhrase + jejr quv cabsibu tam + + + 4294967295 + XambHoqo6[Peni + + +