package org.edx.mobile.view; import android.content.res.Configuration; import android.content.res.Resources; import android.os.Bundle; import android.support.v4.app.FragmentActivity; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.util.DisplayMetrics; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; import android.widget.LinearLayout; import org.edx.mobile.R; import org.edx.mobile.http.OkHttpUtil; import org.edx.mobile.model.api.EnrolledCoursesResponse; import org.edx.mobile.model.course.CourseComponent; import org.edx.mobile.model.course.VideoBlockModel; import org.junit.Test; import org.robolectric.Robolectric; import org.robolectric.annotation.Config; import org.robolectric.shadows.support.v4.SupportFragmentTestUtil; import static org.assertj.android.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeNotNull; // We should add mock downloads, mock play, and state retention tests // later. Also, online/offline transition tests; although the // onOnline() and onOffline() methods don't seem to be called from // anywhere yet? // The SDK version needs to be lesser than Lollipop because of this // issue: https://github.com/robolectric/robolectric/issues/1810 @Config(sdk = 19) public class CourseUnitVideoFragmentTest extends UiTest { /** * Method for iterating through the mock course response data, and * returning the first video block leaf. * * @return The first {@link VideoBlockModel} leaf in the mock course data */ private VideoBlockModel getVideoUnit() { EnrolledCoursesResponse courseData; CourseComponent courseComponent; try { courseData = api.getEnrolledCourses().get(0); courseComponent = serviceManager.getCourseStructure( courseData.getCourse().getId(), OkHttpUtil.REQUEST_CACHE_TYPE.IGNORE_CACHE); } catch (Exception e) { throw new RuntimeException(e); } return (VideoBlockModel) courseComponent.getVideos().get(0); } /** * Testing initialization */ @Test public void initializeTest() { CourseUnitVideoFragment fragment = CourseUnitVideoFragment.newInstance(getVideoUnit(), false, false); SupportFragmentTestUtil.startVisibleFragment(fragment, FragmentUtilActivity.class, 1); assertTrue(fragment.getRetainInstance()); View view = fragment.getView(); assertNotNull(view); View messageContainer = view.findViewById(R.id.message_container); assertNotNull(messageContainer); } /** * Generic method to assert action bar visibility state on a specified orientation * * @param orientation The orientation it should be tested on * @param expected The expected visibility state */ private void assertActionBarShowing(int orientation, boolean expected) { AppCompatActivity activity = Robolectric.setupActivity(FragmentUtilActivity.class); activity.getResources().getConfiguration().orientation = orientation; CourseUnitVideoFragment fragment = CourseUnitVideoFragment.newInstance(getVideoUnit(), false, false); activity.getSupportFragmentManager() .beginTransaction().add(1, fragment, null).commit(); assertTrue(fragment.getRetainInstance()); ActionBar bar = activity.getSupportActionBar(); assumeNotNull(bar); assertEquals(expected, bar.isShowing()); } /** * Testing whether action bar is displayed in portrait orientation */ @Test @Config(qualifiers = "port") public void showActionBarOnPortraitTest() { assertActionBarShowing(Configuration.ORIENTATION_PORTRAIT, true); } /** * Testing whether action bar is hidden in landscape orientation */ @Test @Config(qualifiers = "land") public void showActionBarOnLandscapeTest() { assertActionBarShowing(Configuration.ORIENTATION_LANDSCAPE, true); } /** * Generic method for testing setup on orientation changes * * @param fragment The current fragment * @param orientation The orientation change to test */ private void testOrientationChange( CourseUnitVideoFragment fragment, int orientation) { Resources resources = fragment.getResources(); Configuration config = resources.getConfiguration(); assertNotEquals(orientation, config.orientation); config.orientation = orientation; fragment.onConfigurationChanged(config); boolean isLandscape = config.orientation == Configuration.ORIENTATION_LANDSCAPE; View view = fragment.getView(); assertNotNull(view); Window window = fragment.getActivity().getWindow(); View playerContainer = view.findViewById(R.id.player_container); if (playerContainer != null) { assertThat(playerContainer).isInstanceOf(ViewGroup.class); ViewGroup.LayoutParams layoutParams = playerContainer.getLayoutParams(); assertNotNull(layoutParams); assertThat(layoutParams).hasWidth(ViewGroup.LayoutParams.MATCH_PARENT); DisplayMetrics displayMetrics = resources.getDisplayMetrics(); int height = isLandscape ? displayMetrics.heightPixels : (displayMetrics.widthPixels * 9 / 16); assertThat(layoutParams).hasHeight(height); } } /** * Testing orientation changes */ @Test public void orientationChangeTest() { CourseUnitVideoFragment fragment = CourseUnitVideoFragment.newInstance(getVideoUnit(), false, false); SupportFragmentTestUtil.startVisibleFragment(fragment, FragmentUtilActivity.class, 1); assertNotEquals(Configuration.ORIENTATION_LANDSCAPE, fragment.getResources().getConfiguration().orientation); testOrientationChange(fragment, Configuration.ORIENTATION_LANDSCAPE); testOrientationChange(fragment, Configuration.ORIENTATION_PORTRAIT); } private static class FragmentUtilActivity extends AppCompatActivity implements CourseUnitFragment.HasComponent { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); LinearLayout view = new LinearLayout(this); // noinspection ResourceType view.setId(1); setContentView(view); } @Override public CourseComponent getComponent() { return null; } @Override public void navigateNextComponent() { } @Override public void navigatePreviousComponent() { } } }