Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix part of #161 : Introduce html parser #226

Closed
wants to merge 62 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
e19af2b
Introduce first pass interface for ExplorationProgressController.
BenHenning Sep 25, 2019
43766b0
Fill in the stubbed logic for ExplorationProgressController. Still no
BenHenning Sep 26, 2019
c8eaa66
Fix lateinit issue in ExplorationProgressController due to wrongly or…
BenHenning Sep 27, 2019
a0eb3ce
Fix a variaty of issues in the exp progress controller, properly hook…
BenHenning Sep 29, 2019
1ea9d01
Merge branch 'develop' into introduce-exploration-progress-controller
BenHenning Sep 29, 2019
41141b6
Created a separate ExplorationRetriever, hooked up
BenHenning Oct 1, 2019
ccbac0e
Merge branch 'develop' into introduce-exploration-progress-controller
BenHenning Oct 1, 2019
5f326fc
Change the locking mechanism for ExplorationProgressController to work
BenHenning Oct 3, 2019
b5b7485
Finish tests for ExplorationProgressController and add test classific…
BenHenning Oct 4, 2019
a3c4667
Merge branch 'develop' into introduce-exploration-progress-controller
BenHenning Oct 4, 2019
4a9aad1
ObservableViewModel
Oct 7, 2019
38c0275
Merge remote-tracking branch 'upstream/introduce-exploration-progress…
Oct 7, 2019
0705586
Load exploration and open ExplorationActivity
Oct 7, 2019
d38bbe1
Test case for load exploration
Oct 7, 2019
f337b70
fetch exploration
veena14cs Oct 7, 2019
0fb1729
Connection with StateFragment
Oct 7, 2019
d04f66a
update
veena14cs Oct 7, 2019
ca0c356
update
veena14cs Oct 7, 2019
a3c7d55
Merge branch 'introduce-load-exploration-part-1' into exploration-pla…
veena14cs Oct 7, 2019
fe5ab82
working on fetching customization_args
veena14cs Oct 11, 2019
e45fb0a
Update StateFragmentPresenter.kt
veena14cs Oct 11, 2019
86dc073
resolved conflicts
veena14cs Oct 11, 2019
c6bbfdb
Separated this in its own PR
veena14cs Oct 11, 2019
0edaca1
Delete UrlImageParser.kt
veena14cs Oct 11, 2019
9f02fba
Update StateFragmentPresenter.kt
veena14cs Oct 11, 2019
af8610b
Update build.gradle
veena14cs Oct 11, 2019
5039d84
Create HtmlParser.kt
veena14cs Oct 11, 2019
aed513e
Update HtmlParser.kt
veena14cs Oct 11, 2019
ee29f6c
Update HtmlParser.kt
veena14cs Oct 11, 2019
a56e298
Update HtmlParser.kt
veena14cs Oct 15, 2019
f4f037b
working on testcases
veena14cs Oct 16, 2019
d35ceda
Update HtmlParserTestActivty.kt
veena14cs Oct 17, 2019
03b4e1a
Update HtmlParserTestActivty.kt
veena14cs Oct 17, 2019
3e46d44
added testcases.
veena14cs Oct 17, 2019
1e76982
Update AndroidManifest.xml
veena14cs Oct 17, 2019
2cbf7a0
Update InteractionAdapter.kt
veena14cs Oct 17, 2019
4cfd636
Update InteractionAdapter.kt
veena14cs Oct 17, 2019
eac6442
Update HtmlParser.kt
veena14cs Oct 17, 2019
bd070c7
corrected variable names.
veena14cs Oct 17, 2019
c051b56
updated variables.
veena14cs Oct 17, 2019
83c09a1
Update HtmlParser.kt
veena14cs Oct 17, 2019
8e5328e
Update HtmlParser.kt
veena14cs Oct 17, 2019
cff9dd8
Update HtmlParserTestActivty.kt
veena14cs Oct 17, 2019
76c136a
Update HtmlParser.kt
veena14cs Oct 17, 2019
7a3085f
Merge branch 'develop' into introduce-html-parser
veena14cs Oct 17, 2019
84aa993
Delete InteractionAdapter.kt
veena14cs Oct 17, 2019
80ecb88
deteted unused xml files
veena14cs Oct 17, 2019
84efb79
Update HtmlParser.kt
veena14cs Oct 17, 2019
44fcd0c
Update HtmlParserTestActivty.kt
veena14cs Oct 17, 2019
f38ae47
Update HtmlParser.kt
veena14cs Oct 17, 2019
7babef9
Update HtmlParserTestActivty.kt
veena14cs Oct 17, 2019
2c25558
updated tests
veena14cs Oct 17, 2019
074f1c4
updated test
veena14cs Oct 18, 2019
160ab10
moved to testing package
veena14cs Oct 18, 2019
ee6c427
Update HtmlParserTestActivty.kt
veena14cs Oct 18, 2019
0f96296
fix issues.
veena14cs Oct 18, 2019
b68e7bd
fixed issues
veena14cs Oct 18, 2019
b29d4ec
fixed issues.
veena14cs Oct 18, 2019
dff9130
Update activity_test_html_parser.xml
veena14cs Oct 18, 2019
1ce598b
fixes
veena14cs Oct 18, 2019
ad66f23
Update HtmlParserTest.kt
veena14cs Oct 18, 2019
717b3f9
Update HtmlParserTest.kt
veena14cs Oct 18, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,6 @@
android:theme="@style/SplashScreenTheme">
</activity>
<activity android:name=".testing.BindableAdapterTestActivity"/>
<activity android:name=".testing.HtmlParserTestActivity"/>
</application>
</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.oppia.app.testing

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.text.Spannable
import android.widget.TextView
import org.oppia.app.R
import org.oppia.util.parser.HtmlParser

/** This is a dummy activity to test Html parsing. */
class HtmlParserTestActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_test_html_parser)

val testHtmlContentTextView = findViewById(R.id.test_html_content_text_view) as TextView
val rawDummyString = "\u003cp\u003e\"Let's try one last question,\" said Mr. Baker. \"Here's a pineapple cake cut into pieces.\"\u003c/p\u003e\u003coppia-noninteractive-image alt-with-value=\"\u0026amp;quot;Pineapple cake with 7/9 having cherries.\u0026amp;quot;\" caption-with-value=\"\u0026amp;quot;\u0026amp;quot;\" filepath-with-value=\"\u0026amp;quot;pineapple_cake_height_479_width_480.png\u0026amp;quot;\"\u003e\u003c/oppia-noninteractive-image\u003e\u003cp\u003e\u00a0\u003c/p\u003e\u003cp\u003e\u003cstrong\u003eQuestion 6\u003c/strong\u003e: What fraction of the cake has big red cherries in the pineapple slices?\u003c/p\u003e"
val htmlResult: Spannable = HtmlParser(applicationContext, /* entityType= */ "", /* entityId= */ "").parseOppiaHtml(
rawDummyString,
testHtmlContentTextView
)
testHtmlContentTextView.text = htmlResult
}
}
10 changes: 10 additions & 0 deletions app/src/main/res/layout/activity_test_html_parser.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/test_html_content_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</FrameLayout>
85 changes: 85 additions & 0 deletions app/src/sharedTest/java/org/oppia/app/testing/HtmlParserTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package org.oppia.app.testing

import android.app.Activity
import android.content.Intent
import android.content.pm.ActivityInfo
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
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withId
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 junit.framework.Assert.assertEquals
import junit.framework.Assert.assertTrue
import junit.framework.TestCase.assertNotSame
import org.hamcrest.Matchers.not
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.oppia.app.R
import org.oppia.util.parser.HtmlParser

/** Tests for [HtmlParser]. */
@RunWith(AndroidJUnit4::class)
class HtmlParserTest {

private lateinit var launchedActivity: Activity

@get:Rule
var activityTestRule: ActivityTestRule<HtmlParserTestActivity> = ActivityTestRule(
HtmlParserTestActivity::class.java, /* initialTouchMode= */ true, /* launchActivity= */ false
)

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

@Test
fun testHtmlContent_handleCustomOppiaTags_parsedHtmldisplaysStyledText() {
activityTestRule.activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
activityTestRule.activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT

val textView = activityTestRule.activity.findViewById(R.id.test_html_content_text_view) as TextView
val htmlResult: Spannable = HtmlParser(
ApplicationProvider.getApplicationContext(), /* entityType= */ "", /* entityId= */ ""
).parseOppiaHtml(
"\u003cp\u003e\"Let's try one last question,\" said Mr. Baker. \"Here's a pineapple cake cut into pieces.\"\u003c/p\u003e\u003coppia-noninteractive-image alt-with-value=\"\u0026amp;quot;Pineapple cake with 7/9 having cherries.\u0026amp;quot;\" caption-with-value=\"\u0026amp;quot;\u0026amp;quot;\" filepath-with-value=\"\u0026amp;quot;pineapple_cake_height_479_width_480.png\u0026amp;quot;\"\u003e\u003c/oppia-noninteractive-image\u003e\u003cp\u003e\u00a0\u003c/p\u003e\u003cp\u003e\u003cstrong\u003eQuestion 6\u003c/strong\u003e: What fraction of the cake has big red cherries in the pineapple slices?\u003c/p\u003e", textView
)
assertThat(textView.text.toString()).isEqualTo(htmlResult.toString())
onView(withId(R.id.test_html_content_text_view)).check(matches(isDisplayed()))
onView(withId(R.id.test_html_content_text_view)).check(matches(withText(textView.text.toString())))
}

@Test
fun testHtmlContent_nonCustomOppiaTags_notParsed() {
activityTestRule.activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
activityTestRule.activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT

val textView = activityTestRule.activity.findViewById(R.id.test_html_content_text_view) as TextView
val htmlResult: Spannable = HtmlParser(
ApplicationProvider.getApplicationContext(), /* entityType= */ "", /* entityId= */ ""
).parseOppiaHtml(
"\u003cp\u003e\"Let's try one last question,\" said Mr. Baker. \"Here's a pineapple cake cut into pieces.\"\u003c/p\u003e\u003coppia--image alt-with-value=\"\u0026amp;quot;Pineapple cake with 7/9 having cherries.\u0026amp;quot;\" caption-with-value=\"\u0026amp;quot;\u0026amp;quot;\" filepath-value=\"\u0026amp;quot;pineapple_cake_height_479_width_480.png\u0026amp;quot;\"\u003e\u003c/oppia-noninteractive-image\u003e\u003cp\u003e\u00a0\u003c/p\u003e\u003cp\u003e\u003cstrongQuestion 6\u003c/strong\u003e: What fraction of the cake has big red cherries in the pineapple slices?\u003c/p\u003e",
textView
)
// The two strings aren't equal because this HTML contains a Non-Oppia/Non-Html tag e.g. <image> tag and attributes "filepath-value" which isn't parsed.
assertThat(textView.text.toString()).isNotEqualTo(htmlResult.toString())
onView(withId(R.id.test_html_content_text_view)).check(matches(not(textView.text.toString())))
}

@After
fun tearDown() {
Intents.release()
}
}
40 changes: 40 additions & 0 deletions utility/src/main/java/org/oppia/util/parser/HtmlParser.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package org.oppia.util.parser

import android.content.Context
import android.text.Html
import android.text.Spannable
import android.widget.TextView

private const val CUSTOM_IMG_TAG = "oppia-noninteractive-image"
private const val REPLACE_IMG_TAG = "img"
private const val CUSTOM_IMG_FILE_PATH_ATTRIBUTE = "filepath-with-value"
private const val REPLACE_IMG_FILE_PATH_ATTRIBUTE = "src"

/** Html Parser to parse custom Oppia tags with Android-compatible versions. */
class HtmlParser(private val context: Context, private val entityType: String, private val entityId: String) {

/**
* This method replaces custom Oppia tags with Android-compatible versions for a given raw HTML string, and returns the HTML [Spannable].
* @param rawString rawString argument is the string from the string-content
* @param htmlContentTextView htmlContentTextView argument is the TextView, that need to be passed as argument to ImageGetter class for image parsing
* @return Spannable Spannable represents the styled text.
*/
fun parseOppiaHtml(rawString: String, htmlContentTextView: TextView): Spannable {
var htmlContent = rawString
if (htmlContent.contains(CUSTOM_IMG_TAG)) {
htmlContent = htmlContent.replace(CUSTOM_IMG_TAG, REPLACE_IMG_TAG, /* ignoreCase= */false);
htmlContent = htmlContent.replace(
CUSTOM_IMG_FILE_PATH_ATTRIBUTE,
REPLACE_IMG_FILE_PATH_ATTRIBUTE, /* ignoreCase= */false
);
htmlContent = htmlContent.replace("&amp;quot;", "")
}
// TODO(#205): Integrate UrlImageParser below once it's available.
return if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
Html.fromHtml(htmlContent, Html.FROM_HTML_MODE_LEGACY, /* imageGetter= */null, /* tagHandler= */null) as Spannable
} else {
Html.fromHtml(htmlContent, /* imageGetter= */null, /* tagHandler= */null) as Spannable
}

}
}