/*
* SonarQube
* Copyright (C) 2009-2017 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.authentication.event;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
import static java.util.Objects.requireNonNull;
import static org.sonar.server.authentication.event.AuthenticationEvent.Source;
/**
* Matcher for {@link AuthenticationException} to be used with {@link org.junit.rules.ExpectedException} JUnit Rule.
*
* <p>
* Usage:
* <pre>
* expectedException.expect(authenticationException().from(Source.local(Method.BASIC_TOKEN)).withLogin("foo").andNoPublicMessage());
* </pre>
* </p>
*/
public class AuthenticationExceptionMatcher extends TypeSafeMatcher<Throwable> {
private final Source source;
@CheckForNull
private final String login;
@CheckForNull
private final String publicMessage;
private AuthenticationExceptionMatcher(Source source, @Nullable String login, @Nullable String publicMessage) {
this.source = requireNonNull(source, "source can't be null");
this.login = login;
this.publicMessage = publicMessage;
}
public static Builder authenticationException() {
return new Builder();
}
public static class Builder {
private Source source;
private String login;
public Builder from(Source source) {
this.source = checkSource(source);
return this;
}
public Builder withLogin(String login) {
this.login = requireNonNull(login, "expected login can't be null");
return this;
}
public Builder withoutLogin() {
this.login = null;
return this;
}
public AuthenticationExceptionMatcher andNoPublicMessage() {
return new AuthenticationExceptionMatcher(this.source, this.login, null);
}
public AuthenticationExceptionMatcher andPublicMessage(String publicMessage){
return new AuthenticationExceptionMatcher(this.source, this.login, requireNonNull(publicMessage));
}
private static Source checkSource(Source source) {
return requireNonNull(source, "expected source can't be null");
}
}
@Override
protected boolean matchesSafely(Throwable throwable) {
return check(throwable) == null;
}
private String check(Throwable throwable) {
if (!throwable.getClass().isAssignableFrom(AuthenticationException.class)) {
return "exception is not a AuthenticationException";
}
AuthenticationException authenticationException = (AuthenticationException) throwable;
if (!this.source.equals(authenticationException.getSource())) {
return "source is \"" + authenticationException.getSource() + "\"";
}
String login = authenticationException.getLogin();
if (this.login == null) {
if (login != null) {
return "login is \"" + login + "\"";
}
} else if (login == null) {
return "login is null";
} else if (!this.login.equals(login)) {
return "login is \"" + login + "\"";
}
String publicMessage = authenticationException.getPublicMessage();
if (this.publicMessage == null) {
if (publicMessage != null) {
return "publicMessage is \"" + publicMessage + "\"";
}
} else if (publicMessage == null) {
return "publicMessage is null";
} else if (!this.publicMessage.equals(publicMessage)) {
return "publicMessage is \"" + publicMessage + "\"";
}
return null;
}
@Override
public void describeTo(Description description) {
description.appendText("AuthenticationException with source ").appendText(source.toString());
if (login == null) {
description.appendText(", no login");
} else {
description.appendText(", login \"").appendText(login).appendText("\"");
}
if (publicMessage == null) {
description.appendText(" and no publicMessage");
} else {
description.appendText(" and publicMessage \"").appendText(publicMessage).appendText("\"");
}
}
@Override
protected void describeMismatchSafely(Throwable item, Description mismatchDescription) {
mismatchDescription.appendText(check(item));
}
}