[go: nahoru, domu]

blob: c60c98c29475a1018fbff23e4eb334f8665fcd1e [file] [log] [blame]
/*
* Copyright 2020 The Android Open Source Project
*
* 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 androidx.compose.ui.text.platform
import android.content.Context
import android.graphics.Typeface
import android.os.Build
import androidx.test.filters.SdkSuppress
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry
import androidx.compose.ui.text.FontTestData
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontMatcher
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontSynthesis
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.font.asFontFamily
import androidx.compose.ui.text.font.font
import androidx.compose.ui.text.font.fontFamily
import androidx.compose.ui.text.matchers.assertThat
import androidx.compose.ui.text.test.R
import com.google.common.truth.Truth.assertThat
import com.nhaarman.mockitokotlin2.any
import com.nhaarman.mockitokotlin2.eq
import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.times
import com.nhaarman.mockitokotlin2.verify
import com.nhaarman.mockitokotlin2.whenever
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.junit.MockitoJUnitRunner
@RunWith(MockitoJUnitRunner::class)
@SmallTest
class AndroidTypefaceTest {
val context = InstrumentationRegistry.getInstrumentation().targetContext
private fun androidTypefaceFromFontFamily(
context: Context,
fontFamily: FontFamily
): AndroidTypeface {
return typefaceFromFontFamily(context, fontFamily) as AndroidTypeface
}
@Test
fun createDefaultTypeface() {
val typeface = androidTypefaceFromFontFamily(context, FontFamily.Default)
val nativeTypeface = typeface.getNativeTypeface(
FontWeight.Normal, FontStyle.Normal, FontSynthesis.None)
assertThat(nativeTypeface).isNotNull()
assertThat(nativeTypeface.isBold).isFalse()
assertThat(nativeTypeface.isItalic).isFalse()
assertThat(nativeTypeface.bitmap()).isEqualToBitmap(Typeface.DEFAULT.bitmap())
}
@Test
fun fontWeightItalicCreatesItalicFont() {
val typeface = androidTypefaceFromFontFamily(context, FontFamily.Default)
val nativeTypeface = typeface.getNativeTypeface(
FontWeight.Normal, FontStyle.Italic, FontSynthesis.None)
assertThat(nativeTypeface).isNotNull()
assertThat(nativeTypeface.isBold).isFalse()
assertThat(nativeTypeface.isItalic).isTrue()
assertThat(nativeTypeface.bitmap()).isEqualToBitmap(
Typeface.defaultFromStyle(Typeface.ITALIC).bitmap())
}
@Test
fun fontWeightBoldCreatesBoldFont() {
val typeface = androidTypefaceFromFontFamily(context, FontFamily.Default)
val nativeTypeface = typeface.getNativeTypeface(
FontWeight.Bold, FontStyle.Normal, FontSynthesis.None)
assertThat(nativeTypeface).isNotNull()
assertThat(nativeTypeface.isBold).isTrue()
assertThat(nativeTypeface.isItalic).isFalse()
assertThat(nativeTypeface.bitmap()).isEqualToBitmap(
Typeface.defaultFromStyle(Typeface.BOLD).bitmap())
}
@Test
fun fontWeightBoldFontStyleItalicCreatesBoldItalicFont() {
val typeface = androidTypefaceFromFontFamily(context, FontFamily.Default)
val nativeTypeface = typeface.getNativeTypeface(
FontWeight.Bold, FontStyle.Italic, FontSynthesis.None)
assertThat(nativeTypeface).isNotNull()
assertThat(nativeTypeface.isBold).isTrue()
assertThat(nativeTypeface.isItalic).isTrue()
assertThat(nativeTypeface.bitmap()).isEqualToBitmap(
Typeface.defaultFromStyle(Typeface.BOLD_ITALIC).bitmap())
}
@Test
fun serifAndSansSerifPaintsDifferent() {
val typefaceSans = androidTypefaceFromFontFamily(context, FontFamily.SansSerif)
.getNativeTypeface(FontWeight.Normal, FontStyle.Normal, FontSynthesis.None)
val typefaceSerif = androidTypefaceFromFontFamily(context, FontFamily.Serif)
.getNativeTypeface(FontWeight.Normal, FontStyle.Normal, FontSynthesis.None)
assertThat(typefaceSans).isNotNull()
assertThat(typefaceSans).isNotNull()
assertThat(typefaceSans.bitmap()).isNotEqualToBitmap(typefaceSerif.bitmap())
}
// Following test is exactly the same as the one in TypefaceAdapterTest. Migrate once
// TypefaceAdapterTest is migrated to AndroidTypefaceTest
@Test
fun getTypefaceStyleSnapToNormalFor100to500() {
val fontWeights = arrayOf(
FontWeight.W100,
FontWeight.W200,
FontWeight.W300,
FontWeight.W400,
FontWeight.W500
)
for (fontWeight in fontWeights) {
for (fontStyle in FontStyle.values()) {
val typefaceStyle = TypefaceAdapter.getTypefaceStyle(
fontWeight = fontWeight,
fontStyle = fontStyle
)
if (fontStyle == FontStyle.Normal) {
assertThat(typefaceStyle).isEqualTo(Typeface.NORMAL)
} else {
assertThat(typefaceStyle).isEqualTo(Typeface.ITALIC)
}
}
}
}
// Following test is exactly the same as the one in TypefaceAdapterTest. Migrate once
// TypefaceAdapterTest is migrated to AndroidTypefaceTest
@Test
fun getTypefaceStyleSnapToBoldFor600to900() {
val fontWeights = arrayOf(
FontWeight.W600,
FontWeight.W700,
FontWeight.W800,
FontWeight.W900
)
for (fontWeight in fontWeights) {
for (fontStyle in FontStyle.values()) {
val typefaceStyle = TypefaceAdapter.getTypefaceStyle(
fontWeight = fontWeight,
fontStyle = fontStyle
)
if (fontStyle == FontStyle.Normal) {
assertThat(typefaceStyle).isEqualTo(Typeface.BOLD)
} else {
assertThat(typefaceStyle).isEqualTo(Typeface.BOLD_ITALIC)
}
}
}
}
@Test
@SdkSuppress(maxSdkVersion = 27)
fun fontWeights100To500SnapToNormalBeforeApi28() {
val fontWeights = arrayOf(
FontWeight.W100,
FontWeight.W200,
FontWeight.W300,
FontWeight.W400,
FontWeight.W500
)
for (fontWeight in fontWeights) {
for (fontStyle in FontStyle.values()) {
val typeface = androidTypefaceFromFontFamily(context, FontFamily.Default)
.getNativeTypeface(fontWeight, fontStyle, FontSynthesis.None)
assertThat(typeface).isNotNull()
assertThat(typeface.isBold).isFalse()
assertThat(typeface.isItalic).isEqualTo(fontStyle == FontStyle.Italic)
}
}
}
@Test
@SdkSuppress(maxSdkVersion = 27)
fun fontWeights600To900SnapToBoldBeforeApi28() {
val fontWeights = arrayOf(
FontWeight.W600,
FontWeight.W700,
FontWeight.W800,
FontWeight.W900
)
for (fontWeight in fontWeights) {
for (fontStyle in FontStyle.values()) {
val typeface = androidTypefaceFromFontFamily(context, FontFamily.Default)
.getNativeTypeface(fontWeight, fontStyle, FontSynthesis.None)
assertThat(typeface).isNotNull()
assertThat(typeface.isBold).isTrue()
assertThat(typeface.isItalic).isEqualTo(fontStyle == FontStyle.Italic)
}
}
}
@Test
@SdkSuppress(minSdkVersion = 28)
fun typefaceCreatedWithCorrectFontWeightAndFontStyle() {
for (fontWeight in FontWeight.values) {
for (fontStyle in FontStyle.values()) {
val typeface = androidTypefaceFromFontFamily(context, FontFamily.Default)
.getNativeTypeface(fontWeight, fontStyle, FontSynthesis.None)
assertThat(typeface).isNotNull()
assertThat(typeface.weight).isEqualTo(fontWeight.weight)
assertThat(typeface.isItalic).isEqualTo(fontStyle == FontStyle.Italic)
}
}
}
@Test
fun customSingleFont() {
val defaultTypeface = androidTypefaceFromFontFamily(context, FontFamily.Default)
.getNativeTypeface(FontWeight.Normal, FontStyle.Normal, FontSynthesis.None)
val fontFamily = FontTestData.FONT_100_REGULAR.asFontFamily()
val typeface = androidTypefaceFromFontFamily(context, fontFamily)
.getNativeTypeface(FontWeight.Normal, FontStyle.Normal, FontSynthesis.None)
assertThat(typeface).isNotNull()
assertThat(typeface.bitmap()).isNotEqualToBitmap(defaultTypeface.bitmap())
assertThat(typeface.isItalic).isFalse()
assertThat(typeface.isBold).isFalse()
}
@Test
fun customSingleFontBoldItalic() {
val defaultTypeface = androidTypefaceFromFontFamily(context, FontFamily.Default)
.getNativeTypeface(FontWeight.Normal, FontStyle.Normal, FontSynthesis.None)
val fontFamily = FontTestData.FONT_100_REGULAR.asFontFamily()
val typeface = androidTypefaceFromFontFamily(context, fontFamily)
.getNativeTypeface(FontWeight.Bold, FontStyle.Italic, FontSynthesis.All)
assertThat(typeface).isNotNull()
assertThat(typeface.bitmap()).isNotEqualToBitmap(defaultTypeface.bitmap())
assertThat(typeface.isItalic).isTrue()
assertThat(typeface.isBold).isTrue()
}
@Test
fun customSinglefontFamilyExactMatch() {
val fontFamily = fontFamily(
FontTestData.FONT_100_REGULAR,
FontTestData.FONT_100_ITALIC,
FontTestData.FONT_200_REGULAR,
FontTestData.FONT_200_ITALIC,
FontTestData.FONT_300_REGULAR,
FontTestData.FONT_300_ITALIC,
FontTestData.FONT_400_REGULAR,
FontTestData.FONT_400_ITALIC,
FontTestData.FONT_500_REGULAR,
FontTestData.FONT_500_ITALIC,
FontTestData.FONT_600_REGULAR,
FontTestData.FONT_600_ITALIC,
FontTestData.FONT_700_REGULAR,
FontTestData.FONT_700_ITALIC,
FontTestData.FONT_800_REGULAR,
FontTestData.FONT_800_ITALIC,
FontTestData.FONT_900_REGULAR,
FontTestData.FONT_900_ITALIC
)
for (fontWeight in FontWeight.values) {
for (fontStyle in FontStyle.values()) {
val typeface = androidTypefaceFromFontFamily(context, fontFamily)
.getNativeTypeface(fontWeight, fontStyle, FontSynthesis.None)
assertThat(typeface).isNotNull()
assertThat(typeface).isTypefaceOf(fontWeight = fontWeight, fontStyle = fontStyle)
}
}
}
@Test
fun fontMatcherCalledForCustomFont() {
// customSinglefontFamilyExactMatch tests all the possible outcomes that FontMatcher
// might return. Therefore for the best effort matching we just make sure that FontMatcher
// is called.
val fontWeight = FontWeight.W300
val fontStyle = FontStyle.Italic
val fontFamily = fontFamily(FontTestData.FONT_200_ITALIC)
val fontMatcher = mock<FontMatcher>()
whenever(fontMatcher.matchFont(any(), any(), any()))
.thenReturn(FontTestData.FONT_200_ITALIC)
AndroidFontListTypeface(
context = context,
fontFamily = fontFamily,
necessaryStyles = null,
fontMatcher = fontMatcher)
.getNativeTypeface(fontWeight, fontStyle, FontSynthesis.All)
verify(fontMatcher, times(1)).matchFont(
any(),
eq(fontWeight),
eq(fontStyle)
)
}
@Test
fun resultsAreCached_defaultTypeface() {
val typeface = androidTypefaceFromFontFamily(context, FontFamily.Default)
val nativeTypeface = typeface.getNativeTypeface(
FontWeight.Normal, FontStyle.Normal, FontSynthesis.None
)
// getting typeface with same parameters should hit the cache
// therefore return the same typeface
val otherNativeTypeface = typeface.getNativeTypeface(
FontWeight.Normal, FontStyle.Normal, FontSynthesis.None
)
assertThat(nativeTypeface).isSameInstanceAs(otherNativeTypeface)
}
@Test
fun resultsNotSame_forDifferentFontWeight() {
val typeface = androidTypefaceFromFontFamily(context, FontFamily.Default)
val nativeTypeface = typeface.getNativeTypeface(
FontWeight.Normal, FontStyle.Normal, FontSynthesis.None
)
// getting typeface with different parameters should not hit the cache
// therefore return some other typeface
val otherNativeTypeface = typeface.getNativeTypeface(
FontWeight.Bold, FontStyle.Normal, FontSynthesis.None
)
assertThat(nativeTypeface).isNotSameInstanceAs(otherNativeTypeface)
}
@Test
fun resultsNotSame_forDifferentFontStyle() {
val typeface = androidTypefaceFromFontFamily(context, FontFamily.Default)
val nativeTypeface = typeface.getNativeTypeface(
FontWeight.Normal, FontStyle.Normal, FontSynthesis.None
)
val otherNativeTypeface = typeface.getNativeTypeface(
FontWeight.Normal, FontStyle.Italic, FontSynthesis.None
)
assertThat(nativeTypeface).isNotSameInstanceAs(otherNativeTypeface)
}
@Test
fun resultsAreCached_withCustomTypeface() {
val fontFamily = FontFamily.SansSerif
val fontWeight = FontWeight.Normal
val fontStyle = FontStyle.Italic
val typeface = androidTypefaceFromFontFamily(context, fontFamily)
val nativeTypeface = typeface.getNativeTypeface(
fontWeight, fontStyle, FontSynthesis.None
)
val otherNativeTypeface = typeface.getNativeTypeface(
fontWeight, fontStyle, FontSynthesis.None
)
assertThat(nativeTypeface).isSameInstanceAs(otherNativeTypeface)
}
@Test
fun cacheCanHoldTwoResults() {
val serifTypeface = androidTypefaceFromFontFamily(context, FontFamily.Serif)
.getNativeTypeface(FontWeight.Normal, FontStyle.Normal, FontSynthesis.All)
val otherSerifTypeface = androidTypefaceFromFontFamily(context, FontFamily.Serif)
.getNativeTypeface(FontWeight.Normal, FontStyle.Normal, FontSynthesis.All)
val sansTypeface = androidTypefaceFromFontFamily(context, FontFamily.SansSerif)
.getNativeTypeface(FontWeight.Normal, FontStyle.Normal, FontSynthesis.All)
val otherSansTypeface = androidTypefaceFromFontFamily(context, FontFamily.SansSerif)
.getNativeTypeface(FontWeight.Normal, FontStyle.Normal, FontSynthesis.All)
assertThat(serifTypeface).isSameInstanceAs(otherSerifTypeface)
assertThat(sansTypeface).isSameInstanceAs(otherSansTypeface)
assertThat(sansTypeface).isNotSameInstanceAs(serifTypeface)
}
@Test(expected = IllegalStateException::class)
fun throwsExceptionIfFontIsNotIncludedInTheApp() {
val fontFamily = fontFamily(font(-1))
androidTypefaceFromFontFamily(context, fontFamily)
}
@Test(expected = IllegalStateException::class)
fun throwsExceptionIfFontIsNotReadable() {
val fontFamily = fontFamily(font(R.font.invalid_font))
androidTypefaceFromFontFamily(context, fontFamily)
}
@Test
fun fontSynthesisDefault_synthesizeTheFontToItalicBold() {
val fontFamily = FontTestData.FONT_100_REGULAR.asFontFamily()
val typeface = androidTypefaceFromFontFamily(context, fontFamily)
.getNativeTypeface(FontWeight.Bold, FontStyle.Italic, FontSynthesis.All)
// since 100 regular is not bold and not italic, passing FontWeight.bold and
// FontStyle.Italic should create a Typeface that is fake bold and fake Italic
assertThat(typeface.isBold).isTrue()
assertThat(typeface.isItalic).isTrue()
}
@Test
fun fontSynthesisStyle_synthesizeTheFontToItalic() {
val fontFamily = FontTestData.FONT_100_REGULAR.asFontFamily()
val typeface = androidTypefaceFromFontFamily(context, fontFamily)
.getNativeTypeface(FontWeight.Bold, FontStyle.Italic, FontSynthesis.Style)
// since 100 regular is not bold and not italic, passing FontWeight.bold and
// FontStyle.Italic should create a Typeface that is only fake Italic
assertThat(typeface.isBold).isFalse()
assertThat(typeface.isItalic).isTrue()
}
@Test
fun fontSynthesisWeight_synthesizeTheFontToBold() {
val fontFamily = FontTestData.FONT_100_REGULAR.asFontFamily()
val typeface = androidTypefaceFromFontFamily(context, fontFamily)
.getNativeTypeface(FontWeight.Bold, FontStyle.Italic, FontSynthesis.Weight)
// since 100 regular is not bold and not italic, passing FontWeight.bold and
// FontStyle.Italic should create a Typeface that is only fake bold
assertThat(typeface.isBold).isTrue()
assertThat(typeface.isItalic).isFalse()
}
@Test
fun fontSynthesisStyle_forMatchingItalicDoesNotSynthesize() {
val fontFamily = FontTestData.FONT_100_ITALIC.asFontFamily()
val typeface = androidTypefaceFromFontFamily(context, fontFamily)
.getNativeTypeface(FontWeight.W700, FontStyle.Italic, FontSynthesis.Style)
assertThat(typeface.isBold).isFalse()
assertThat(typeface.isItalic).isFalse()
}
@Test
fun fontSynthesisAll_doesNotSynthesizeIfFontIsTheSame_beforeApi28() {
val fontFamily = FontTestData.FONT_700_ITALIC.asFontFamily()
val typeface = androidTypefaceFromFontFamily(context, fontFamily)
.getNativeTypeface(FontWeight.W700, FontStyle.Italic, FontSynthesis.All)
assertThat(typeface.isItalic).isFalse()
if (Build.VERSION.SDK_INT < 23) {
assertThat(typeface.isBold).isFalse()
} else if (Build.VERSION.SDK_INT < 28) {
assertThat(typeface.isBold).isTrue()
} else {
assertThat(typeface.isBold).isTrue()
assertThat(typeface.weight).isEqualTo(700)
}
}
@Test
fun fontSynthesisNone_doesNotSynthesize() {
val fontFamily = FontTestData.FONT_100_REGULAR.asFontFamily()
val typeface = androidTypefaceFromFontFamily(context, fontFamily)
.getNativeTypeface(FontWeight.Bold, FontStyle.Italic, FontSynthesis.None)
assertThat(typeface.isBold).isFalse()
assertThat(typeface.isItalic).isFalse()
}
@Test
fun fontSynthesisWeight_doesNotSynthesizeIfRequestedWeightIsLessThan600() {
val fontFamily = FontTestData.FONT_100_REGULAR.asFontFamily()
// Less than 600 is not synthesized
val typeface500 = androidTypefaceFromFontFamily(context, fontFamily)
.getNativeTypeface(FontWeight.W500, FontStyle.Normal, FontSynthesis.Weight)
// 600 or more is synthesized
val typeface600 = androidTypefaceFromFontFamily(context, fontFamily)
.getNativeTypeface(FontWeight.W600, FontStyle.Normal, FontSynthesis.Weight)
assertThat(typeface500.isBold).isFalse()
assertThat(typeface600.isBold).isTrue()
}
}