2
0

Re-organize the project into a better hierarchy.

This commit is contained in:
Maarten Billemont
2017-03-06 13:37:05 -05:00
parent 67e18895ab
commit c6b285a9c0
1452 changed files with 43 additions and 350 deletions

View File

@@ -0,0 +1,177 @@
package com.lyndir.masterpassword;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.primitives.UnsignedInteger;
import com.lyndir.lhunath.opal.system.logging.Logger;
import com.lyndir.lhunath.opal.system.util.ConversionUtils;
import com.lyndir.lhunath.opal.system.util.NNFunctionNN;
import java.io.IOException;
import java.util.Deque;
import java.util.List;
import java.util.concurrent.Callable;
import javax.annotation.Nonnull;
import javax.xml.parsers.*;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.ext.DefaultHandler2;
/**
* @author lhunath, 2015-12-22
*/
public class MPTestSuite implements Callable<Boolean> {
@SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( MPTestSuite.class );
private static final String DEFAULT_RESOURCE_NAME = "mpw_tests.xml";
private MPTests tests;
private Listener listener;
public MPTestSuite()
throws UnavailableException {
this( DEFAULT_RESOURCE_NAME );
}
public MPTestSuite(String resourceName)
throws UnavailableException {
try {
tests = new MPTests();
tests.cases = Lists.newLinkedList();
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
parser.parse( Thread.currentThread().getContextClassLoader().getResourceAsStream( resourceName ), new DefaultHandler2() {
private Deque<String> currentTags = Lists.newLinkedList();
private Deque<StringBuilder> currentTexts = Lists.newLinkedList();
private MPTests.Case currentCase;
@Override
public void startElement(final String uri, final String localName, final String qName, final Attributes attributes)
throws SAXException {
super.startElement( uri, localName, qName, attributes );
currentTags.push( qName );
currentTexts.push( new StringBuilder() );
if ("case".equals( qName )) {
currentCase = new MPTests.Case();
currentCase.identifier = attributes.getValue( "id" );
currentCase.parent = attributes.getValue( "parent" );
}
}
@Override
public void endElement(final String uri, final String localName, final String qName)
throws SAXException {
super.endElement( uri, localName, qName );
Preconditions.checkState( qName.equals( currentTags.pop() ) );
String text = currentTexts.pop().toString();
if ("case".equals( qName ))
tests.cases.add( currentCase );
if ("algorithm".equals( qName ))
currentCase.algorithm = ConversionUtils.toInteger( text ).orNull();
if ("fullName".equals( qName ))
currentCase.fullName = text;
if ("masterPassword".equals( qName ))
currentCase.masterPassword = text;
if ("keyID".equals( qName ))
currentCase.keyID = text;
if ("siteName".equals( qName ))
currentCase.siteName = text;
if ("siteCounter".equals( qName ))
currentCase.siteCounter = text.isEmpty()? null: UnsignedInteger.valueOf( text );
if ("siteType".equals( qName ))
currentCase.siteType = text;
if ("siteVariant".equals( qName ))
currentCase.siteVariant = text;
if ("siteContext".equals( qName ))
currentCase.siteContext = text;
if ("result".equals( qName ))
currentCase.result = text;
}
@Override
public void characters(final char[] ch, final int start, final int length)
throws SAXException {
super.characters( ch, start, length );
currentTexts.peek().append( ch, start, length );
}
} );
}
catch (IllegalArgumentException | ParserConfigurationException | SAXException | IOException e) {
throw new UnavailableException( e );
}
for (MPTests.Case testCase : tests.getCases())
testCase.initializeParentHierarchy( tests );
}
public void setListener(final Listener listener) {
this.listener = listener;
}
public MPTests getTests() {
return tests;
}
public boolean forEach(String testName, NNFunctionNN<MPTests.Case, Boolean> testFunction) {
List<MPTests.Case> cases = tests.getCases();
for (int c = 0; c < cases.size(); c++) {
MPTests.Case testCase = cases.get( c );
if (testCase.getResult().isEmpty())
continue;
progress( Logger.Target.INFO, c, cases.size(), //
"[%s] on %s...", testName, testCase.getIdentifier() );
if (!testFunction.apply( testCase )) {
progress( Logger.Target.ERROR, cases.size(), cases.size(), //
"[%s] on %s: FAILED!", testName, testCase.getIdentifier() );
return false;
}
progress( Logger.Target.INFO, c + 1, cases.size(), //
"[%s] on %s: passed!", testName, testCase.getIdentifier() );
}
return true;
}
private void progress(final Logger.Target target, final int current, final int max, final String format, final Object... args) {
logger.log( target, format, args );
if (listener != null)
listener.progress( current, max, format, args );
}
@Override
public Boolean call()
throws Exception {
return forEach( "mpw", new NNFunctionNN<MPTests.Case, Boolean>() {
@Nonnull
@Override
public Boolean apply(@Nonnull final MPTests.Case testCase) {
MasterKey masterKey = MasterKey.create( testCase.getAlgorithm(), testCase.getFullName(), testCase.getMasterPassword() );
String sitePassword = masterKey.encode( testCase.getSiteName(), testCase.getSiteType(), testCase.getSiteCounter(),
testCase.getSiteVariant(), testCase.getSiteContext() );
return testCase.getResult().equals( sitePassword );
}
} );
}
public static class UnavailableException extends Exception {
public UnavailableException(final Throwable cause) {
super( cause );
}
}
public interface Listener {
void progress(int current, int max, String messageFormat, Object... args);
}
}

View File

@@ -0,0 +1,208 @@
package com.lyndir.masterpassword;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*;
import com.google.common.primitives.UnsignedInteger;
import com.lyndir.lhunath.opal.system.logging.Logger;
import com.lyndir.lhunath.opal.system.util.*;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* @author lhunath, 14-12-05
*/
public class MPTests {
private static final String ID_DEFAULT = "default";
@SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( MPTests.class );
List<Case> cases;
@Nonnull
public List<Case> getCases() {
return checkNotNull( 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 );
}
public Case getDefaultCase() {
try {
return getCase( ID_DEFAULT );
}
catch (IllegalArgumentException e) {
throw new IllegalStateException( "Missing default case in test suite. Add a case with id: " + ID_DEFAULT, e );
}
}
public static class Case {
String identifier;
String parent;
Integer algorithm;
String fullName;
String masterPassword;
String keyID;
String siteName;
UnsignedInteger siteCounter;
String siteType;
String siteVariant;
String siteContext;
String result;
private transient Case parentCase;
public void initializeParentHierarchy(MPTests tests) {
if (parent != null) {
parentCase = tests.getCase( parent );
parentCase.initializeParentHierarchy( tests );
}
algorithm = ifNotNullElse( algorithm, new NNSupplier<Integer>() {
@Nonnull
@Override
public Integer get() {
return checkNotNull( parentCase.algorithm );
}
} );
fullName = ifNotNullElse( fullName, new NNSupplier<String>() {
@Nonnull
@Override
public String get() {
return checkNotNull( parentCase.fullName );
}
} );
masterPassword = ifNotNullElse( masterPassword, new NNSupplier<String>() {
@Nonnull
@Override
public String get() {
return checkNotNull( parentCase.masterPassword );
}
} );
keyID = ifNotNullElse( keyID, new NNSupplier<String>() {
@Nonnull
@Override
public String get() {
return checkNotNull( parentCase.keyID );
}
} );
siteName = ifNotNullElse( siteName, new NNSupplier<String>() {
@Nonnull
@Override
public String get() {
return checkNotNull( parentCase.siteName );
}
} );
siteCounter = ifNotNullElse( siteCounter, new NNSupplier<UnsignedInteger>() {
@Nonnull
@Override
public UnsignedInteger get() {
return checkNotNull( parentCase.siteCounter );
}
} );
siteType = ifNotNullElse( siteType, new NNSupplier<String>() {
@Nonnull
@Override
public String get() {
return checkNotNull( parentCase.siteType );
}
} );
siteVariant = ifNotNullElse( siteVariant, new NNSupplier<String>() {
@Nonnull
@Override
public String get() {
return checkNotNull( parentCase.siteVariant );
}
} );
siteContext = ifNotNullElse( siteContext, new NNSupplier<String>() {
@Nonnull
@Override
public String get() {
return parentCase == null? "": checkNotNull( parentCase.siteContext );
}
} );
result = ifNotNullElse( result, new NNSupplier<String>() {
@Nonnull
@Override
public String get() {
return parentCase == null? "": checkNotNull( parentCase.result );
}
} );
}
@Nonnull
public String getIdentifier() {
return identifier;
}
@Nullable
public Case getParentCase() {
return parentCase;
}
@Nonnull
public MasterKey.Version getAlgorithm() {
return MasterKey.Version.fromInt( checkNotNull( algorithm ) );
}
@Nonnull
public String getFullName() {
return checkNotNull( fullName );
}
@Nonnull
public char[] getMasterPassword() {
return checkNotNull( masterPassword ).toCharArray();
}
@Nonnull
public String getKeyID() {
return checkNotNull( keyID );
}
@Nonnull
public String getSiteName() {
return checkNotNull( siteName );
}
public UnsignedInteger getSiteCounter() {
return ifNotNullElse( siteCounter, UnsignedInteger.valueOf( 1 ) );
}
@Nonnull
public MPSiteType getSiteType() {
return MPSiteType.forName( checkNotNull( siteType ) );
}
@Nonnull
public MPSiteVariant getSiteVariant() {
return MPSiteVariant.forName( checkNotNull( siteVariant ) );
}
@Nonnull
public String getSiteContext() {
return checkNotNull( siteContext );
}
@Nonnull
public String getResult() {
return checkNotNull( result );
}
@Override
public String toString() {
return identifier;
}
}
}

View File

@@ -0,0 +1,279 @@
<tests>
<!-- Default values for all parameters. -->
<case id="default">
<algorithm>-1</algorithm>
<fullName>Robert Lee Mitchell</fullName>
<masterPassword>banana colored duckling</masterPassword>
<keyID>98EEF4D1DF46D849574A82A03C3177056B15DFFCA29BB3899DE4628453675302</keyID>
<siteName>masterpasswordapp.com</siteName>
<siteCounter>1</siteCounter>
<siteType>GeneratedLong</siteType>
<siteVariant>Password</siteVariant>
<result><!-- abstract --></result>
</case>
<!-- Algorithm 3 -->
<case id="v3" parent="default">
<algorithm>3</algorithm>
<result>Jejr5[RepuSosp</result>
</case>
<case id="v3_mb_fullName" parent="v3">
<fullName></fullName>
<keyID>1717AA1F9BF5BA56CD0965CDA3D78E6D2E6A1EA8C067A8EA621F3DDAD4A87EB8</keyID>
<result>NopaDajh8=Fene</result>
</case>
<case id="v3_mb_masterPassword" parent="v3">
<masterPassword></masterPassword>
<keyID>351432B8528A5ABECAB768CA95015097DE76FE14C41E10AF36C67DCFB8917E08</keyID>
<result>QesuHirv5-Xepl</result>
</case>
<case id="v3_mb_siteName" parent="v3">
<siteName></siteName>
<result>LiheCuwhSerz6)</result>
</case>
<case id="v3_loginName" parent="v3">
<siteVariant>Login</siteVariant>
<siteType>GeneratedName</siteType>
<result>wohzaqage</result>
</case>
<case id="v3_securityAnswer" parent="v3">
<siteVariant>Answer</siteVariant>
<siteType>GeneratedPhrase</siteType>
<result>xin diyjiqoja hubu</result>
</case>
<case id="v3_securityAnswer_context" parent="v3_securityAnswer">
<siteContext>question</siteContext>
<result>xogx tem cegyiva jab</result>
</case>
<case id="v3_type_maximum" parent="v3">
<siteType>GeneratedMaximum</siteType>
<result>W6@692^B1#&amp;@gVdSdLZ@</result>
</case>
<case id="v3_type_medium" parent="v3">
<siteType>GeneratedMedium</siteType>
<result>Jej2$Quv</result>
</case>
<case id="v3_type_basic" parent="v3">
<siteType>GeneratedBasic</siteType>
<result>WAo2xIg6</result>
</case>
<case id="v3_type_short" parent="v3">
<siteType>GeneratedShort</siteType>
<result>Jej2</result>
</case>
<case id="v3_type_pin" parent="v3">
<siteType>GeneratedPIN</siteType>
<result>7662</result>
</case>
<case id="v3_type_name" parent="v3">
<siteType>GeneratedName</siteType>
<result>jejraquvo</result>
</case>
<case id="v3_type_phrase" parent="v3">
<siteType>GeneratedPhrase</siteType>
<result>jejr quv cabsibu tam</result>
</case>
<case id="v3_counter_ceiling" parent="v3">
<siteCounter>4294967295</siteCounter>
<result>XambHoqo6[Peni</result>
</case>
<!-- Algorithm 2 -->
<case id="v2" parent="default">
<algorithm>2</algorithm>
<result>Jejr5[RepuSosp</result>
</case>
<case id="v2_mb_fullName" parent="v2">
<fullName></fullName>
<keyID>1717AA1F9BF5BA56CD0965CDA3D78E6D2E6A1EA8C067A8EA621F3DDAD4A87EB8</keyID>
<result>WaqoGuho2[Xaxw</result>
</case>
<case id="v2_mb_masterPassword" parent="v2">
<masterPassword></masterPassword>
<keyID>351432B8528A5ABECAB768CA95015097DE76FE14C41E10AF36C67DCFB8917E08</keyID>
<result>QesuHirv5-Xepl</result>
</case>
<case id="v2_mb_siteName" parent="v2">
<siteName></siteName>
<result>LiheCuwhSerz6)</result>
</case>
<case id="v2_loginName" parent="v2">
<siteVariant>Login</siteVariant>
<siteType>GeneratedName</siteType>
<result>wohzaqage</result>
</case>
<case id="v2_securityAnswer" parent="v2">
<siteVariant>Answer</siteVariant>
<siteType>GeneratedPhrase</siteType>
<result>xin diyjiqoja hubu</result>
</case>
<case id="v2_securityAnswer_context" parent="v2_securityAnswer">
<siteContext>question</siteContext>
<result>xogx tem cegyiva jab</result>
</case>
<case id="v2_type_maximum" parent="v2">
<siteType>GeneratedMaximum</siteType>
<result>W6@692^B1#&amp;@gVdSdLZ@</result>
</case>
<case id="v2_type_medium" parent="v2">
<siteType>GeneratedMedium</siteType>
<result>Jej2$Quv</result>
</case>
<case id="v2_type_basic" parent="v2">
<siteType>GeneratedBasic</siteType>
<result>WAo2xIg6</result>
</case>
<case id="v2_type_short" parent="v2">
<siteType>GeneratedShort</siteType>
<result>Jej2</result>
</case>
<case id="v2_type_pin" parent="v2">
<siteType>GeneratedPIN</siteType>
<result>7662</result>
</case>
<case id="v2_type_name" parent="v2">
<siteType>GeneratedName</siteType>
<result>jejraquvo</result>
</case>
<case id="v2_type_phrase" parent="v2">
<siteType>GeneratedPhrase</siteType>
<result>jejr quv cabsibu tam</result>
</case>
<case id="v2_counter_ceiling" parent="v2">
<siteCounter>4294967295</siteCounter>
<result>XambHoqo6[Peni</result>
</case>
<!-- Algorithm 1 -->
<case id="v1" parent="default">
<algorithm>1</algorithm>
<result>Jejr5[RepuSosp</result>
</case>
<case id="v1_mb_fullName" parent="v1">
<fullName></fullName>
<keyID>1717AA1F9BF5BA56CD0965CDA3D78E6D2E6A1EA8C067A8EA621F3DDAD4A87EB8</keyID>
<result>WaqoGuho2[Xaxw</result>
</case>
<case id="v1_mb_masterPassword" parent="v1">
<masterPassword></masterPassword>
<keyID>351432B8528A5ABECAB768CA95015097DE76FE14C41E10AF36C67DCFB8917E08</keyID>
<result>QesuHirv5-Xepl</result>
</case>
<case id="v1_mb_siteName" parent="v1">
<siteName></siteName>
<result>WawiYarp2@Kodh</result>
</case>
<case id="v1_loginName" parent="v1">
<siteVariant>Login</siteVariant>
<siteType>GeneratedName</siteType>
<result>wohzaqage</result>
</case>
<case id="v1_securityAnswer" parent="v1">
<siteVariant>Answer</siteVariant>
<siteType>GeneratedPhrase</siteType>
<result>xin diyjiqoja hubu</result>
</case>
<case id="v1_securityAnswer_context" parent="v1_securityAnswer">
<siteContext>question</siteContext>
<result>xogx tem cegyiva jab</result>
</case>
<case id="v1_type_maximum" parent="v1">
<siteType>GeneratedMaximum</siteType>
<result>W6@692^B1#&amp;@gVdSdLZ@</result>
</case>
<case id="v1_type_medium" parent="v1">
<siteType>GeneratedMedium</siteType>
<result>Jej2$Quv</result>
</case>
<case id="v1_type_basic" parent="v1">
<siteType>GeneratedBasic</siteType>
<result>WAo2xIg6</result>
</case>
<case id="v1_type_short" parent="v1">
<siteType>GeneratedShort</siteType>
<result>Jej2</result>
</case>
<case id="v1_type_pin" parent="v1">
<siteType>GeneratedPIN</siteType>
<result>7662</result>
</case>
<case id="v1_type_name" parent="v1">
<siteType>GeneratedName</siteType>
<result>jejraquvo</result>
</case>
<case id="v1_type_phrase" parent="v1">
<siteType>GeneratedPhrase</siteType>
<result>jejr quv cabsibu tam</result>
</case>
<case id="v1_counter_ceiling" parent="v1">
<siteCounter>4294967295</siteCounter>
<result>XambHoqo6[Peni</result>
</case>
<!-- Algorithm 0 -->
<case id="v0" parent="default">
<algorithm>0</algorithm>
<result>Feji5@ReduWosh</result>
</case>
<case id="v0_mb_fullName" parent="v0">
<fullName></fullName>
<keyID>1717AA1F9BF5BA56CD0965CDA3D78E6D2E6A1EA8C067A8EA621F3DDAD4A87EB8</keyID>
<result>HajrYudo7@Mamh</result>
</case>
<case id="v0_mb_masterPassword" parent="v0">
<masterPassword></masterPassword>
<keyID>351432B8528A5ABECAB768CA95015097DE76FE14C41E10AF36C67DCFB8917E08</keyID>
<result>MewmDini0]Meho</result>
</case>
<case id="v0_mb_siteName" parent="v0">
<siteName></siteName>
<result>HahiVana2@Nole</result>
</case>
<case id="v0_loginName" parent="v0">
<siteVariant>Login</siteVariant>
<siteType>GeneratedName</siteType>
<result>lozwajave</result>
</case>
<case id="v0_securityAnswer" parent="v0">
<siteVariant>Answer</siteVariant>
<siteType>GeneratedPhrase</siteType>
<result>miy lirfijoja dubu</result>
</case>
<case id="v0_securityAnswer_context" parent="v0_securityAnswer">
<siteContext>question</siteContext>
<result>movm bex gevrica jaf</result>
</case>
<case id="v0_type_maximum" parent="v0">
<siteType>GeneratedMaximum</siteType>
<result>w1!3bA3icmRAc)SS@lwl</result>
</case>
<case id="v0_type_medium" parent="v0">
<siteType>GeneratedMedium</siteType>
<result>Fej7]Jug</result>
</case>
<case id="v0_type_basic" parent="v0">
<siteType>GeneratedBasic</siteType>
<result>wvH7irC1</result>
</case>
<case id="v0_type_short" parent="v0">
<siteType>GeneratedShort</siteType>
<result>Fej7</result>
</case>
<case id="v0_type_pin" parent="v0">
<siteType>GeneratedPIN</siteType>
<result>2117</result>
</case>
<case id="v0_type_name" parent="v0">
<siteType>GeneratedName</siteType>
<result>fejrajugo</result>
</case>
<case id="v0_type_phrase" parent="v0">
<siteType>GeneratedPhrase</siteType>
<result>fejr jug gabsibu bax</result>
</case>
<case id="v0_counter_ceiling" parent="v0">
<siteCounter>4294967295</siteCounter>
<result>QateDojh1@Hecn</result>
</case>
</tests>