Skip to content

Commit

Permalink
Fix part #361: HTML formatting throughout app (#404)
Browse files Browse the repository at this point in the history
* Update HtmlParser.kt

* Update UrlImageParser.kt

* nit changes.

* update changes

* Update HtmlParserTest.kt

* Update HtmlParserTest.kt

* Update HtmlParserTest.kt

* updated testcase

* Update HtmlParserTest.kt

* Update HtmlParserTest.kt

* Update HtmlParser.kt

* Update UrlImageParser.kt

* Update HtmlParserTest.kt

* Update HtmlParserTest.kt

* Update HtmlParser.kt

* Update UrlImageParser.kt

* Update HtmlParserTest.kt

* Update HtmlParser.kt

* updated imports

* Update HtmlParser.kt
  • Loading branch information
veena14cs authored Nov 25, 2019
1 parent db77b67 commit e3ed84a
Show file tree
Hide file tree
Showing 2 changed files with 158 additions and 2 deletions.
128 changes: 128 additions & 0 deletions app/src/sharedTest/java/org/oppia/app/parser/HtmlParserTest.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package org.oppia.app.parser

import android.app.Activity
import android.app.Application
import android.content.Context
import android.content.Intent
import android.text.Spannable
import android.widget.TextView
import androidx.test.core.app.ApplicationProvider
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.intent.Intents
Expand All @@ -13,6 +16,14 @@ import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.rule.ActivityTestRule
import com.google.common.truth.Truth.assertThat
import dagger.Binds
import dagger.BindsInstance
import dagger.Component
import dagger.Module
import dagger.Provides
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestCoroutineDispatcher
import org.hamcrest.Matchers.not
import org.junit.After
import org.junit.Before
Expand All @@ -21,9 +32,24 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.oppia.app.R
import org.oppia.app.testing.HtmlParserTestActivity
import org.oppia.util.caching.CacheAssetsLocally
import org.oppia.util.logging.EnableConsoleLog
import org.oppia.util.logging.EnableFileLog
import org.oppia.util.logging.GlobalLogLevel
import org.oppia.util.logging.LogLevel
import org.oppia.util.parser.DefaultGcsPrefix
import org.oppia.util.parser.DefaultGcsResource
import org.oppia.util.parser.GlideImageLoader
import org.oppia.util.parser.HtmlParser
import org.oppia.util.parser.ImageDownloadUrlTemplate
import org.oppia.util.parser.ImageLoader
import org.oppia.util.threading.BackgroundDispatcher
import org.oppia.util.threading.BlockingDispatcher
import javax.inject.Inject
import javax.inject.Qualifier
import javax.inject.Singleton

// TODO(#277): Add tests for UrlImageParser.
/** Tests for [HtmlParser]. */
@RunWith(AndroidJUnit4::class)
class HtmlParserTest {
Expand All @@ -39,11 +65,19 @@ class HtmlParserTest {

@Before
fun setUp() {
setUpTestApplicationComponent()
Intents.init()
val intent = Intent(Intent.ACTION_PICK)
launchedActivity = activityTestRule.launchActivity(intent)
}

private fun setUpTestApplicationComponent() {
DaggerHtmlParserTest_TestApplicationComponent.builder()
.setApplication(ApplicationProvider.getApplicationContext())
.build()
.inject(this)
}

@Test
fun testHtmlContent_handleCustomOppiaTags_parsedHtmlDisplaysStyledText() {
val textView = activityTestRule.activity.findViewById(R.id.test_html_content_text_view) as TextView
Expand Down Expand Up @@ -83,4 +117,98 @@ class HtmlParserTest {
fun tearDown() {
Intents.release()
}

@Qualifier
annotation class TestDispatcher

// TODO(#89): Move this to a common test application component.
@Module
class TestModule {
@Provides
@Singleton
fun provideContext(application: Application): Context {
return application
}

@ExperimentalCoroutinesApi
@Singleton
@Provides
@TestDispatcher
fun provideTestDispatcher(): CoroutineDispatcher {
return TestCoroutineDispatcher()
}

@Singleton
@Provides
@BackgroundDispatcher
fun provideBackgroundDispatcher(@TestDispatcher testDispatcher: CoroutineDispatcher): CoroutineDispatcher {
return testDispatcher
}

@Singleton
@Provides
@BlockingDispatcher
fun provideBlockingDispatcher(@TestDispatcher testDispatcher: CoroutineDispatcher): CoroutineDispatcher {
return testDispatcher
}

@Provides
@CacheAssetsLocally
fun provideCacheAssetsLocally(): Boolean = false

@Provides
@DefaultGcsPrefix
@Singleton
fun provideDefaultGcsPrefix(): String {
return "https://storage.googleapis.com/"
}

@Provides
@DefaultGcsResource
@Singleton
fun provideDefaultGcsResource(): String {
return "oppiaserver-resources/"
}

@Provides
@ImageDownloadUrlTemplate
@Singleton
fun provideImageDownloadUrlTemplate(): String {
return "%s/%s/assets/image/%s"
}

// TODO(#59): Either isolate these to their own shared test module, or use the real logging
// module in tests to avoid needing to specify these settings for tests.
@EnableConsoleLog
@Provides
fun provideEnableConsoleLog(): Boolean = true

@EnableFileLog
@Provides
fun provideEnableFileLog(): Boolean = false

@GlobalLogLevel
@Provides
fun provideGlobalLogLevel(): LogLevel = LogLevel.VERBOSE
}

@Module
abstract class ImageTestModule {
@Binds
abstract fun provideGlideImageLoader(impl: GlideImageLoader): ImageLoader
}

@Singleton
@Component(modules = [TestModule::class, ImageTestModule::class])
interface TestApplicationComponent {
@Component.Builder
interface Builder {
@BindsInstance
fun setApplication(application: Application): Builder

fun build(): TestApplicationComponent
}

fun inject(htmlParserTest: HtmlParserTest)
}
}
32 changes: 30 additions & 2 deletions utility/src/main/java/org/oppia/util/parser/HtmlParser.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package org.oppia.util.parser

import android.text.Html
import android.text.Spannable
import android.text.SpannableStringBuilder
import android.widget.TextView
import javax.inject.Inject

Expand Down Expand Up @@ -32,6 +33,7 @@ class HtmlParser private constructor(
if (htmlContent.contains("\n\n")) {
htmlContent = htmlContent.replace("\n\n", "")
}

if (htmlContent.contains(CUSTOM_IMG_TAG)) {
htmlContent = htmlContent.replace(CUSTOM_IMG_TAG, REPLACE_IMG_TAG, /* ignoreCase= */false)
htmlContent = htmlContent.replace(
Expand All @@ -43,10 +45,36 @@ class HtmlParser private constructor(

val imageGetter = urlImageParserFactory.create(htmlContentTextView, entityType, entityId, imageCenterAlign)
return if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
Html.fromHtml(htmlContent, Html.FROM_HTML_MODE_LEGACY, imageGetter, /* tagHandler= */ null) as Spannable
trimSpannable(
Html.fromHtml(
htmlContent,
Html.FROM_HTML_MODE_LEGACY,
imageGetter, /* tagHandler= */
null
) as SpannableStringBuilder
)
} else {
Html.fromHtml(htmlContent, imageGetter, /* tagHandler= */ null) as Spannable
trimSpannable(Html.fromHtml(htmlContent, imageGetter, /* tagHandler= */ null) as SpannableStringBuilder)
}
}

private fun trimSpannable(spannable: SpannableStringBuilder): SpannableStringBuilder {
var trimStart = 0
var trimEnd = 0

var text = spannable.toString()

if (text.startsWith("\n")) {
text = text.substring(1)
trimStart += 1
}

if (text.endsWith("\n")) {
text = text.substring(0, text.length - 1)
trimEnd += 2
}

return spannable.delete(0, trimStart).delete(spannable.length - trimEnd, spannable.length)
}

class Factory @Inject constructor(private val urlImageParserFactory: UrlImageParser.Factory) {
Expand Down

0 comments on commit e3ed84a

Please sign in to comment.