/**
* Copyright 2012 Facebook
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.facebook.widget;
import android.test.suitebuilder.annotation.LargeTest;
import android.test.suitebuilder.annotation.MediumTest;
import android.test.suitebuilder.annotation.SmallTest;
import com.facebook.*;
import com.facebook.widget.LoginButton;
import junit.framework.Assert;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
public class LoginButtonTest extends SessionTestsBase {
static final int STRAY_CALLBACK_WAIT_MILLISECONDS = 50;
@SmallTest
@MediumTest
@LargeTest
public void testLoginButton() throws Throwable {
MockTokenCachingStrategy cache = new MockTokenCachingStrategy(null, 0);
final ScriptedSession session = new ScriptedSession(getActivity(), "SomeId", cache);
SessionTestsBase.SessionStatusCallbackRecorder statusRecorder = new SessionTestsBase.SessionStatusCallbackRecorder();
session.addAuthorizeResult("A token of thanks", new ArrayList<String>(), AccessTokenSource.TEST_USER);
session.addCallback(statusRecorder);
// Verify state with no token in cache
Assert.assertEquals(SessionState.CREATED, session.getState());
// Add another status recorder to ensure that the callback we hand to LoginButton
// also gets called as expected. We expect to get the same order of calls as statusRecorder does.
final SessionStatusCallbackRecorder loginButtonStatusRecorder = new SessionStatusCallbackRecorder();
// Create the button. To get session status updates, we need to actually attach the
// button to a window, which must be done on the UI thread.
final LoginButton button = new LoginButton(getActivity());
runAndBlockOnUiThread(0, new Runnable() {
@Override
public void run() {
getActivity().setContentView(button);
button.setSession(session);
button.setSessionStatusCallback(loginButtonStatusRecorder);
button.performClick();
}
});
statusRecorder.waitForCall(session, SessionState.OPENING, null);
loginButtonStatusRecorder.waitForCall(session, SessionState.OPENING, null);
statusRecorder.waitForCall(session, SessionState.OPENED, null);
loginButtonStatusRecorder.waitForCall(session, SessionState.OPENED, null);
// Verify token information is cleared.
session.closeAndClearTokenInformation();
assertTrue(cache.getSavedState() == null);
statusRecorder.waitForCall(session, SessionState.CLOSED, null);
loginButtonStatusRecorder.waitForCall(session, SessionState.CLOSED, null);
// Wait a bit so we can fail if any unexpected calls arrive on the
// recorder.
stall(STRAY_CALLBACK_WAIT_MILLISECONDS);
statusRecorder.close();
}
@SmallTest
@MediumTest
@LargeTest
public void testLoginFail() {
MockTokenCachingStrategy cache = new MockTokenCachingStrategy(null, 0);
ScriptedSession session = new ScriptedSession(getActivity(), "SomeId", cache);
final Exception openException = new Exception("Open failed!");
final AtomicBoolean clicked = new AtomicBoolean(false);
// Verify state with no token in cache
assertEquals(SessionState.CREATED, session.getState());
final LoginButton button = new LoginButton(getActivity());
LoginButton.OnErrorListener listener = new LoginButton.OnErrorListener() {
@Override
public void onError(FacebookException exception) {
synchronized (this) {
assertEquals(exception.getCause().getMessage(), openException.getMessage());
clicked.set(true);
this.notifyAll();
}
}
};
button.setOnErrorListener(listener);
button.setSession(session);
session.addAuthorizeResult(openException);
button.onAttachedToWindow();
button.performClick();
try {
synchronized (listener) {
listener.wait(DEFAULT_TIMEOUT_MILLISECONDS);
}
} catch (InterruptedException e) {
fail("Interrupted during open");
}
if (!clicked.get()) {
fail("Did not get exception");
}
}
@SmallTest
@MediumTest
@LargeTest
public void testCanAddReadPermissions() {
MockTokenCachingStrategy cache = new MockTokenCachingStrategy(null, 0);
ScriptedSession session = new ScriptedSession(getActivity(), "SomeId", cache);
SessionTestsBase.SessionStatusCallbackRecorder statusRecorder = new SessionTestsBase.SessionStatusCallbackRecorder();
// Verify state with no token in cache
assertEquals(SessionState.CREATED, session.getState());
final LoginButton button = new LoginButton(getActivity());
button.setSession(session);
button.setReadPermissions(Arrays.asList(new String[] {"read_permission", "read_another"}));
session.addAuthorizeResult("A token of thanks", new ArrayList<String>(), AccessTokenSource.TEST_USER);
session.addCallback(statusRecorder);
button.performClick();
statusRecorder.waitForCall(session, SessionState.OPENING, null);
statusRecorder.waitForCall(session, SessionState.OPENED, null);
// Verify token information is cleared.
session.closeAndClearTokenInformation();
assertTrue(cache.getSavedState() == null);
statusRecorder.waitForCall(session, SessionState.CLOSED, null);
// Wait a bit so we can fail if any unexpected calls arrive on the
// recorder.
stall(STRAY_CALLBACK_WAIT_MILLISECONDS);
statusRecorder.close();
}
@SmallTest
@MediumTest
@LargeTest
public void testCanAddPublishPermissions() {
MockTokenCachingStrategy cache = new MockTokenCachingStrategy(null, 0);
ScriptedSession session = new ScriptedSession(getActivity(), "SomeId", cache);
SessionTestsBase.SessionStatusCallbackRecorder statusRecorder =
new SessionTestsBase.SessionStatusCallbackRecorder();
// Verify state with no token in cache
assertEquals(SessionState.CREATED, session.getState());
final LoginButton button = new LoginButton(getActivity());
button.setSession(session);
button.setPublishPermissions(Arrays.asList(new String[] {"publish_permission", "publish_another"}));
session.addAuthorizeResult("A token of thanks", new ArrayList<String>(), AccessTokenSource.TEST_USER);
session.addCallback(statusRecorder);
button.performClick();
statusRecorder.waitForCall(session, SessionState.OPENING, null);
statusRecorder.waitForCall(session, SessionState.OPENED, null);
// Verify token information is cleared.
session.closeAndClearTokenInformation();
assertTrue(cache.getSavedState() == null);
statusRecorder.waitForCall(session, SessionState.CLOSED, null);
// Wait a bit so we can fail if any unexpected calls arrive on the
// recorder.
stall(STRAY_CALLBACK_WAIT_MILLISECONDS);
statusRecorder.close();
}
@SmallTest
@MediumTest
@LargeTest
public void testCantAddReadThenPublishPermissions() {
final LoginButton button = new LoginButton(getActivity());
button.setReadPermissions(Arrays.asList(new String[] {"read_permission", "read_another"}));
try {
button.setPublishPermissions(Arrays.asList(new String[] {"read_permission", "read_a_third"}));
fail("Should not be able to reach here");
} catch (Exception e) {
assertTrue(e instanceof UnsupportedOperationException);
}
}
@SmallTest
@MediumTest
@LargeTest
public void testCantAddPublishThenReadPermissions() {
final LoginButton button = new LoginButton(getActivity());
button.setPublishPermissions(Arrays.asList(new String[] {"publish_permission", "publish_another"}));
try {
button.setReadPermissions(Arrays.asList(new String[] {"publish_permission", "publish_a_third"}));
fail("Should not be able to reach here");
} catch (Exception e) {
assertTrue(e instanceof UnsupportedOperationException);
}
}
@SmallTest
@MediumTest
@LargeTest
public void testCanAddReadThenPublishPermissionsWithClear() {
final LoginButton button = new LoginButton(getActivity());
button.setReadPermissions(Arrays.asList(new String[] {"read_permission", "read_another"}));
button.clearPermissions();
button.setPublishPermissions(Arrays.asList(new String[] {"publish_permission", "publish_another"}));
}
@SmallTest
@MediumTest
@LargeTest
public void testCantAddMorePermissionsToOpenSession() {
MockTokenCachingStrategy cache = new MockTokenCachingStrategy(null, 0);
ScriptedSession session = new ScriptedSession(getActivity(), "SomeId", cache);
SessionTestsBase.SessionStatusCallbackRecorder statusRecorder =
new SessionTestsBase.SessionStatusCallbackRecorder();
// Verify state with no token in cache
assertEquals(SessionState.CREATED, session.getState());
final LoginButton button = new LoginButton(getActivity());
button.setSession(session);
session.addAuthorizeResult("A token of thanks",
Arrays.asList(new String[] {"read_permission", "read_another"}), AccessTokenSource.TEST_USER);
session.addCallback(statusRecorder);
button.performClick();
statusRecorder.waitForCall(session, SessionState.OPENING, null);
statusRecorder.waitForCall(session, SessionState.OPENED, null);
// this should be fine
button.setReadPermissions(Arrays.asList(new String[] {"read_permission", "read_another"}));
button.setReadPermissions(Arrays.asList(new String[] {"read_permission", "read_a_third"}));
List<String> permissions = button.getPermissions();
assertTrue(permissions.contains("read_permission"));
assertTrue(permissions.contains("read_another"));
assertFalse(permissions.contains("read_a_third"));
// Verify token information is cleared.
session.closeAndClearTokenInformation();
assertTrue(cache.getSavedState() == null);
statusRecorder.waitForCall(session, SessionState.CLOSED, null);
// Wait a bit so we can fail if any unexpected calls arrive on the
// recorder.
stall(STRAY_CALLBACK_WAIT_MILLISECONDS);
statusRecorder.close();
}
@SmallTest
@MediumTest
@LargeTest
public void testCanSetDefaultAudience() {
SessionTestsBase.MockTokenCachingStrategy cache = new SessionTestsBase.MockTokenCachingStrategy(null, 0);
ScriptedSession session = new ScriptedSession(getActivity(), "SomeId", cache);
SessionTestsBase.SessionStatusCallbackRecorder statusRecorder =
new SessionTestsBase.SessionStatusCallbackRecorder();
// Verify state with no token in cache
assertEquals(SessionState.CREATED, session.getState());
final LoginButton button = new LoginButton(getActivity());
button.setSession(session);
button.setPublishPermissions(Arrays.asList(new String[] {"publish_permission", "publish_another"}));
button.setDefaultAudience(SessionDefaultAudience.FRIENDS);
session.addAuthorizeResult("A token of thanks", new ArrayList<String>(), AccessTokenSource.TEST_USER);
session.addCallback(statusRecorder);
button.performClick();
statusRecorder.waitForCall(session, SessionState.OPENING, null);
statusRecorder.waitForCall(session, SessionState.OPENED, null);
assertNotNull(session.getLastRequest());
assertEquals(SessionDefaultAudience.FRIENDS, session.getLastRequestAudience());
// Verify token information is cleared.
session.closeAndClearTokenInformation();
assertTrue(cache.getSavedState() == null);
statusRecorder.waitForCall(session, SessionState.CLOSED, null);
// Wait a bit so we can fail if any unexpected calls arrive on the
// recorder.
stall(STRAY_CALLBACK_WAIT_MILLISECONDS);
statusRecorder.close();
}
}