Skip to content

Commit

Permalink
Add support to read dcf file from res/raw (#1778)
Browse files Browse the repository at this point in the history
Add support in DesignSettings and DocServer to use R.raw.* Add unit test
for loading HelloWorld dcf file from res/raw Add test methods in
DesignSettings and DocServer
Add more steps to clear state in ClearStateTestRule

Test: ./gradlew designcompose:testDebugUnitTest# Please enter the commit
message for your changes. Lines starting
  • Loading branch information
dipenpradhan authored Nov 11, 2024
1 parent 24823f7 commit 635ca57
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 5 deletions.
40 changes: 38 additions & 2 deletions designcompose/src/main/java/com/android/designcompose/DocServer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@

package com.android.designcompose

import android.content.res.Resources
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.annotation.RawRes
import androidx.annotation.RestrictTo
import androidx.annotation.VisibleForTesting
import androidx.compose.runtime.Composable
Expand All @@ -39,6 +41,7 @@ import com.android.designcompose.common.DocumentServerParams
import java.io.BufferedInputStream
import java.io.File
import java.io.FileInputStream
import java.io.InputStream
import java.lang.ref.WeakReference
import java.net.ConnectException
import java.net.SocketException
Expand Down Expand Up @@ -96,6 +99,11 @@ object DesignSettings {
internal var isDocumentLive = mutableStateOf(false)
private var fontDb: HashMap<String, FontFamily> = HashMap()
internal var fileFetchStatus: HashMap<DesignDocId, DesignDocStatus> = HashMap()
internal var rawResourceId: Int = Resources.ID_NULL

@VisibleForTesting
@RestrictTo(RestrictTo.Scope.TESTS)
fun testOnlyClearFileFetchStatus() = fileFetchStatus.clear()

@VisibleForTesting
@RestrictTo(RestrictTo.Scope.TESTS)
Expand Down Expand Up @@ -149,6 +157,18 @@ object DesignSettings {
toastsEnabled = false
}

/**
* Sets the raw resource id for serialized doc. Once set, the design doc will only be read from
* res/raw/the_dcf_file. Live updates do not work when this is set. All other files will be
* ignored: downloaded/cached files, assets/figma/
*
* @param resourceId of the raw dcf file placed in res/raw
* @sample R.raw.the_dcf_file
*/
fun setRawResourceId(@RawRes resourceId: Int) {
rawResourceId = resourceId
}

fun addFontFamily(name: String, family: FontFamily) {
fontDb[name] = family
}
Expand Down Expand Up @@ -236,6 +256,10 @@ internal object DocServer {
scheduleLiveUpdate()
}
}

@VisibleForTesting
@RestrictTo(RestrictTo.Scope.TESTS)
fun testOnlyClearDocuments() = documents.clear()
}

internal fun DocServer.initializeLiveUpdate() {
Expand Down Expand Up @@ -508,9 +532,21 @@ internal fun DocServer.doc(
}

// Use the LocalContext to locate this doc in the precompiled DesignComposeDefinitionuments
val assetManager = context.assets
try {
val assetDoc = assetManager.open("figma/$id.dcf")
val assetDoc: InputStream =
if (DesignSettings.rawResourceId != Resources.ID_NULL) {
Log.i(
TAG,
"Loaded design doc from R.raw." +
context.resources.getResourceEntryName(DesignSettings.rawResourceId),
)
context.resources.openRawResource(DesignSettings.rawResourceId)
} else {
val fileName = "figma/$id.dcf"
Log.i(TAG, "Loaded design doc from assets/$fileName")
context.assets.open(fileName)
}

val decodedDoc = decodeDiskDoc(assetDoc, null, docId, Feedback)
if (decodedDoc != null) {
synchronized(documents) { documents[docId] = decodedDoc }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Copyright 2024 Google LLC
*
* 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.android.designcompose

import androidx.compose.runtime.Composable
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithText
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.designcompose.TestUtils.ClearStateTestRule
import com.android.designcompose.annotation.Design
import com.android.designcompose.annotation.DesignComponent
import com.android.designcompose.annotation.DesignDoc
import com.android.designcompose.test.R
import com.android.designcompose.test.assertRenderStatus
import com.android.designcompose.test.onDCDoc
import com.github.takahirom.roborazzi.RobolectricDeviceQualifiers
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.annotation.Config
import org.robolectric.annotation.GraphicsMode

const val helloWorldDocId = "pxVlixodJqZL95zo2RzTHl"

@DesignDoc(id = helloWorldDocId)
interface HelloWorld {
@DesignComponent(node = "#MainFrame", hideDesignSwitcher = true)
fun mainFrame(@Design(node = "#Name") name: String)
}

@Composable
fun HelloWorld() {
HelloWorldDoc.mainFrame(name = "Testers!")
}

@RunWith(AndroidJUnit4::class)
@GraphicsMode(GraphicsMode.Mode.NATIVE)
@Config(qualifiers = RobolectricDeviceQualifiers.SmallPhone, sdk = [34])
class DesignRawResourceTest {
// Must reset the DocServer and DesignSettings state to prevent reusing cached files
@get:Rule val clearStateTestRule = ClearStateTestRule()
@get:Rule val composeTestRule = createComposeRule()

@Test
fun testHelloWorldDoc_setRawResourceId_passes() {
with(composeTestRule) {
DesignSettings.setRawResourceId(R.raw.raw_resource_test_hello_world_doc)
composeTestRule.setContent { HelloWorld() }

onDCDoc(HelloWorldDoc).assertRenderStatus(DocRenderStatus.Rendered)
onNodeWithText("Testers!", substring = true).assertExists()
onNodeWithText("Hello", substring = true).assertExists()
}
}

@Test
fun testHelloWorldDoc_noRawResource_fails() {
with(composeTestRule) {
composeTestRule.setContent { HelloWorld() }

onDCDoc(HelloWorldDoc).assertDoesNotExist()
}
}
}
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

import static com.android.designcompose.TestUtilsKt.testOnlyTriggerLiveUpdate;

import android.content.res.Resources;

import androidx.test.platform.app.InstrumentationRegistry;

import org.junit.rules.TestRule;
Expand Down Expand Up @@ -48,11 +50,23 @@ private static void clearInteractionStates() {
InteractionStateManager.INSTANCE.getStates().clear();
}

private static void clearDocServer() {
DocServer.INSTANCE.testOnlyClearDocuments();
}

private static void clearDesignSettings() {
DesignSettings.INSTANCE.testOnlyClearFileFetchStatus();
DesignSettings.INSTANCE.setRawResourceId(Resources.ID_NULL);
}


public static class ClearStateTestRule implements TestRule {

@Override
public Statement apply(Statement base, Description description) {
clearInteractionStates();
clearDocServer();
clearDesignSettings();
return base;
}
}
Expand Down
10 changes: 7 additions & 3 deletions dev-scripts/common-functions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,14 @@ function fetch_design_switcher {

function fetch_helloworld {
DOC_ID=pxVlixodJqZL95zo2RzTHl
OUTPUT_FILE_REFERENCE_APP="$GIT_ROOT/reference-apps/helloworld/helloworld-app/src/main/assets/figma/HelloWorldDoc_$DOC_ID.dcf"
OUTPUT_FILE_RAW_RES_TEST="$GIT_ROOT/designcompose/src/testDebug/res/raw/raw_resource_test_hello_world_doc"
cargo run --bin fetch --features=fetch -- \
--doc-id="$DOC_ID" \
--nodes="#MainFrame" \
--output="$GIT_ROOT/reference-apps/helloworld/helloworld-app/src/main/assets/figma/HelloWorldDoc_$DOC_ID.dcf"

--output=$OUTPUT_FILE_REFERENCE_APP
# Reuse Hello World doc for testing doc loading from res/raw
cp $OUTPUT_FILE_REFERENCE_APP $OUTPUT_FILE_RAW_RES_TEST
}

function fetch_tutorial {
Expand Down Expand Up @@ -112,4 +115,5 @@ function fetch_state_customizations {
--doc-id="$DOC_ID" \
--nodes="#root" \
--output="$GIT_ROOT/integration-tests/validation/src/main/assets/figma/StateCustomizationsDoc_$DOC_ID.dcf"
}
}

0 comments on commit 635ca57

Please sign in to comment.