Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
The Tor Project
Applications
android-components
Commits
a1cd163c
Commit
a1cd163c
authored
Aug 12, 2020
by
Arturo Mejia
Browse files
Closes issue #7983: Generate a file name when the content provider doesn't provide one.
parent
147bfeda
Changes
9
Hide whitespace changes
Inline
Side-by-side
components/browser/engine-gecko-beta/src/main/java/mozilla/components/browser/engine/gecko/prompt/GeckoPromptDelegate.kt
View file @
a1cd163c
...
...
@@ -4,10 +4,8 @@
package
mozilla.components.browser.engine.gecko.prompt
import
android.content.ContentResolver
import
android.content.Context
import
android.net.Uri
import
android.provider.OpenableColumns
import
androidx.annotation.VisibleForTesting
import
mozilla.components.browser.engine.gecko.GeckoEngineSession
import
mozilla.components.concept.storage.Login
...
...
@@ -18,7 +16,7 @@ import mozilla.components.concept.engine.prompt.PromptRequest.MultipleChoice
import
mozilla.components.concept.engine.prompt.PromptRequest.SingleChoice
import
mozilla.components.concept.engine.prompt.ShareData
import
mozilla.components.support.base.log.logger.Logger
import
mozilla.components.support.ktx.
kotlin.sanitize
FileName
import
mozilla.components.support.ktx.
android.net.get
FileName
import
mozilla.components.support.ktx.kotlin.toDate
import
org.mozilla.geckoview.AllowOrDeny
import
org.mozilla.geckoview.GeckoResult
...
...
@@ -32,8 +30,10 @@ import org.mozilla.geckoview.GeckoSession.PromptDelegate.DateTimePrompt.Type.TIM
import
org.mozilla.geckoview.GeckoSession.PromptDelegate.DateTimePrompt.Type.WEEK
import
org.mozilla.geckoview.GeckoSession.PromptDelegate.PromptResponse
import
org.mozilla.geckoview.Autocomplete
import
java.io.File
import
java.io.FileOutputStream
import
java.io.IOException
import
java.io.InputStream
import
java.security.InvalidParameterException
import
java.text.SimpleDateFormat
import
java.util.Date
...
...
@@ -541,9 +541,7 @@ internal class GeckoPromptDelegate(private val geckoEngineSession: GeckoEngineSe
val
temporalFile
=
java
.
io
.
File
(
cacheUploadDirectory
,
getFileName
(
contentResolver
))
try
{
contentResolver
.
openInputStream
(
this
)
!!
.
use
{
inStream
->
FileOutputStream
(
temporalFile
).
use
{
outStream
->
inStream
.
copyTo
(
outStream
)
}
copyFile
(
temporalFile
,
inStream
)
}
}
catch
(
e
:
IOException
)
{
Logger
(
"GeckoPromptDelegate"
).
warn
(
"Could not convert uri to file uri"
,
e
)
...
...
@@ -551,15 +549,11 @@ internal class GeckoPromptDelegate(private val geckoEngineSession: GeckoEngineSe
return
Uri
.
parse
(
"file:///${temporalFile.absolutePath}"
)
}
private
fun
Uri
.
getFileName
(
contentResolver
:
ContentResolver
):
String
{
val
returnUri
=
this
var
fileName
=
""
contentResolver
.
query
(
returnUri
,
null
,
null
,
null
,
null
)
?.
use
{
cursor
->
val
nameIndex
=
cursor
.
getColumnIndex
(
OpenableColumns
.
DISPLAY_NAME
)
cursor
.
moveToFirst
()
fileName
=
cursor
.
getString
(
nameIndex
)
@VisibleForTesting
internal
fun
copyFile
(
temporalFile
:
File
,
inStream
:
InputStream
):
Long
{
return
FileOutputStream
(
temporalFile
).
use
{
outStream
->
inStream
.
copyTo
(
outStream
)
}
return
fileName
.
sanitizeFileName
()
}
}
...
...
components/browser/engine-gecko-beta/src/test/java/mozilla/components/browser/engine/gecko/prompt/GeckoPromptDelegateTest.kt
View file @
a1cd163c
...
...
@@ -13,6 +13,7 @@ import mozilla.components.concept.engine.prompt.PromptRequest
import
mozilla.components.concept.engine.prompt.PromptRequest.MultipleChoice
import
mozilla.components.concept.engine.prompt.PromptRequest.SingleChoice
import
mozilla.components.support.ktx.kotlin.toDate
import
mozilla.components.support.test.any
import
mozilla.components.support.test.mock
import
mozilla.components.support.test.robolectric.testContext
import
mozilla.components.support.test.whenever
...
...
@@ -24,6 +25,8 @@ import org.junit.Assert.assertTrue
import
org.junit.Before
import
org.junit.Test
import
org.junit.runner.RunWith
import
org.mockito.Mockito.spy
import
org.mockito.Mockito.doReturn
import
org.mozilla.gecko.util.GeckoBundle
import
org.mozilla.geckoview.GeckoRuntime
import
org.mozilla.geckoview.GeckoSession
...
...
@@ -35,7 +38,6 @@ import org.mozilla.geckoview.GeckoSession.PromptDelegate.DateTimePrompt.Type.WEE
import
org.mozilla.geckoview.GeckoSession.PromptDelegate.FilePrompt.Capture.ANY
import
org.mozilla.geckoview.GeckoSession.PromptDelegate.FilePrompt.Capture.NONE
import
org.mozilla.geckoview.GeckoSession.PromptDelegate.FilePrompt.Capture.USER
import
org.robolectric.Shadows.shadowOf
import
java.io.FileInputStream
import
java.security.InvalidParameterException
import
java.util.Calendar
...
...
@@ -549,20 +551,24 @@ class GeckoPromptDelegateTest {
@Test
fun
`Calling
onFilePrompt
must
provide
a
FilePicker
PromptRequest`
()
{
val
context
=
testContext
val
context
=
spy
(
testContext
)
val
contentResolver
=
spy
(
context
.
contentResolver
)
val
mockSession
=
GeckoEngineSession
(
runtime
)
var
onSingleFileSelectedWasCalled
=
false
var
onMultipleFilesSelectedWasCalled
=
false
var
onDismissWasCalled
=
false
val
mockUri
:
Uri
=
mock
()
val
mockFileInput
:
FileInputStream
=
mock
()
val
shadowContentResolver
=
shadowOf
(
context
.
contentResolver
)
shadowContentResolver
.
registerInputStream
(
mockUri
,
mockFileInput
)
doReturn
(
contentResolver
).
`when`
(
context
).
contentResolver
doReturn
(
mock
<
FileInputStream
>()).
`when`
(
contentResolver
).
openInputStream
(
mozilla
.
components
.
support
.
test
.
any
())
var
filePickerRequest
:
PromptRequest
.
File
=
mock
()
val
promptDelegate
=
GeckoPromptDelegate
(
mockSession
)
val
promptDelegate
=
spy
(
GeckoPromptDelegate
(
mockSession
))
// Prevent the file from being copied
doReturn
(
0L
).
`when`
(
promptDelegate
).
copyFile
(
any
(),
any
())
mockSession
.
register
(
object
:
EngineSession
.
Observer
{
override
fun
onPromptRequest
(
promptRequest
:
PromptRequest
)
{
filePickerRequest
=
promptRequest
as
PromptRequest
.
File
...
...
components/browser/engine-gecko-nightly/src/main/java/mozilla/components/browser/engine/gecko/prompt/GeckoPromptDelegate.kt
View file @
a1cd163c
...
...
@@ -4,10 +4,8 @@
package
mozilla.components.browser.engine.gecko.prompt
import
android.content.ContentResolver
import
android.content.Context
import
android.net.Uri
import
android.provider.OpenableColumns
import
androidx.annotation.VisibleForTesting
import
mozilla.components.browser.engine.gecko.GeckoEngineSession
import
mozilla.components.concept.storage.Login
...
...
@@ -18,7 +16,7 @@ import mozilla.components.concept.engine.prompt.PromptRequest.MultipleChoice
import
mozilla.components.concept.engine.prompt.PromptRequest.SingleChoice
import
mozilla.components.concept.engine.prompt.ShareData
import
mozilla.components.support.base.log.logger.Logger
import
mozilla.components.support.ktx.
kotlin.sanitize
FileName
import
mozilla.components.support.ktx.
android.net.get
FileName
import
mozilla.components.support.ktx.kotlin.toDate
import
org.mozilla.geckoview.AllowOrDeny
import
org.mozilla.geckoview.GeckoResult
...
...
@@ -32,8 +30,10 @@ import org.mozilla.geckoview.GeckoSession.PromptDelegate.DateTimePrompt.Type.TIM
import
org.mozilla.geckoview.GeckoSession.PromptDelegate.DateTimePrompt.Type.WEEK
import
org.mozilla.geckoview.GeckoSession.PromptDelegate.PromptResponse
import
org.mozilla.geckoview.Autocomplete
import
java.io.File
import
java.io.FileOutputStream
import
java.io.IOException
import
java.io.InputStream
import
java.security.InvalidParameterException
import
java.text.SimpleDateFormat
import
java.util.Date
...
...
@@ -541,9 +541,7 @@ internal class GeckoPromptDelegate(private val geckoEngineSession: GeckoEngineSe
val
temporalFile
=
java
.
io
.
File
(
cacheUploadDirectory
,
getFileName
(
contentResolver
))
try
{
contentResolver
.
openInputStream
(
this
)
!!
.
use
{
inStream
->
FileOutputStream
(
temporalFile
).
use
{
outStream
->
inStream
.
copyTo
(
outStream
)
}
copyFile
(
temporalFile
,
inStream
)
}
}
catch
(
e
:
IOException
)
{
Logger
(
"GeckoPromptDelegate"
).
warn
(
"Could not convert uri to file uri"
,
e
)
...
...
@@ -551,15 +549,11 @@ internal class GeckoPromptDelegate(private val geckoEngineSession: GeckoEngineSe
return
Uri
.
parse
(
"file:///${temporalFile.absolutePath}"
)
}
private
fun
Uri
.
getFileName
(
contentResolver
:
ContentResolver
):
String
{
val
returnUri
=
this
var
fileName
=
""
contentResolver
.
query
(
returnUri
,
null
,
null
,
null
,
null
)
?.
use
{
cursor
->
val
nameIndex
=
cursor
.
getColumnIndex
(
OpenableColumns
.
DISPLAY_NAME
)
cursor
.
moveToFirst
()
fileName
=
cursor
.
getString
(
nameIndex
)
@VisibleForTesting
internal
fun
copyFile
(
temporalFile
:
File
,
inStream
:
InputStream
):
Long
{
return
FileOutputStream
(
temporalFile
).
use
{
outStream
->
inStream
.
copyTo
(
outStream
)
}
return
fileName
.
sanitizeFileName
()
}
}
...
...
components/browser/engine-gecko-nightly/src/test/java/mozilla/components/browser/engine/gecko/prompt/GeckoPromptDelegateTest.kt
View file @
a1cd163c
...
...
@@ -13,6 +13,7 @@ import mozilla.components.concept.engine.prompt.PromptRequest
import
mozilla.components.concept.engine.prompt.PromptRequest.MultipleChoice
import
mozilla.components.concept.engine.prompt.PromptRequest.SingleChoice
import
mozilla.components.support.ktx.kotlin.toDate
import
mozilla.components.support.test.any
import
mozilla.components.support.test.mock
import
mozilla.components.support.test.robolectric.testContext
import
mozilla.components.support.test.whenever
...
...
@@ -24,6 +25,8 @@ import org.junit.Assert.assertTrue
import
org.junit.Before
import
org.junit.Test
import
org.junit.runner.RunWith
import
org.mockito.Mockito.spy
import
org.mockito.Mockito.doReturn
import
org.mozilla.gecko.util.GeckoBundle
import
org.mozilla.geckoview.GeckoRuntime
import
org.mozilla.geckoview.GeckoSession
...
...
@@ -35,7 +38,6 @@ import org.mozilla.geckoview.GeckoSession.PromptDelegate.DateTimePrompt.Type.WEE
import
org.mozilla.geckoview.GeckoSession.PromptDelegate.FilePrompt.Capture.ANY
import
org.mozilla.geckoview.GeckoSession.PromptDelegate.FilePrompt.Capture.NONE
import
org.mozilla.geckoview.GeckoSession.PromptDelegate.FilePrompt.Capture.USER
import
org.robolectric.Shadows.shadowOf
import
java.io.FileInputStream
import
java.security.InvalidParameterException
import
java.util.Calendar
...
...
@@ -549,20 +551,24 @@ class GeckoPromptDelegateTest {
@Test
fun
`Calling
onFilePrompt
must
provide
a
FilePicker
PromptRequest`
()
{
val
context
=
testContext
val
context
=
spy
(
testContext
)
val
contentResolver
=
spy
(
context
.
contentResolver
)
val
mockSession
=
GeckoEngineSession
(
runtime
)
var
onSingleFileSelectedWasCalled
=
false
var
onMultipleFilesSelectedWasCalled
=
false
var
onDismissWasCalled
=
false
val
mockUri
:
Uri
=
mock
()
val
mockFileInput
:
FileInputStream
=
mock
()
val
shadowContentResolver
=
shadowOf
(
context
.
contentResolver
)
shadowContentResolver
.
registerInputStream
(
mockUri
,
mockFileInput
)
doReturn
(
contentResolver
).
`when`
(
context
).
contentResolver
doReturn
(
mock
<
FileInputStream
>()).
`when`
(
contentResolver
).
openInputStream
(
any
())
var
filePickerRequest
:
PromptRequest
.
File
=
mock
()
val
promptDelegate
=
GeckoPromptDelegate
(
mockSession
)
val
promptDelegate
=
spy
(
GeckoPromptDelegate
(
mockSession
))
// Prevent the file from being copied
doReturn
(
0L
).
`when`
(
promptDelegate
).
copyFile
(
any
(),
any
())
mockSession
.
register
(
object
:
EngineSession
.
Observer
{
override
fun
onPromptRequest
(
promptRequest
:
PromptRequest
)
{
filePickerRequest
=
promptRequest
as
PromptRequest
.
File
...
...
components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/prompt/GeckoPromptDelegate.kt
View file @
a1cd163c
...
...
@@ -4,10 +4,8 @@
package
mozilla.components.browser.engine.gecko.prompt
import
android.content.ContentResolver
import
android.content.Context
import
android.net.Uri
import
android.provider.OpenableColumns
import
androidx.annotation.VisibleForTesting
import
mozilla.components.browser.engine.gecko.GeckoEngineSession
import
mozilla.components.concept.storage.Login
...
...
@@ -18,7 +16,7 @@ import mozilla.components.concept.engine.prompt.PromptRequest.MultipleChoice
import
mozilla.components.concept.engine.prompt.PromptRequest.SingleChoice
import
mozilla.components.concept.engine.prompt.ShareData
import
mozilla.components.support.base.log.logger.Logger
import
mozilla.components.support.ktx.
kotlin.sanitize
FileName
import
mozilla.components.support.ktx.
android.net.get
FileName
import
mozilla.components.support.ktx.kotlin.toDate
import
org.mozilla.geckoview.AllowOrDeny
import
org.mozilla.geckoview.GeckoResult
...
...
@@ -32,8 +30,10 @@ import org.mozilla.geckoview.GeckoSession.PromptDelegate.DateTimePrompt.Type.TIM
import
org.mozilla.geckoview.GeckoSession.PromptDelegate.DateTimePrompt.Type.WEEK
import
org.mozilla.geckoview.GeckoSession.PromptDelegate.PromptResponse
import
org.mozilla.geckoview.Autocomplete
import
java.io.File
import
java.io.FileOutputStream
import
java.io.IOException
import
java.io.InputStream
import
java.security.InvalidParameterException
import
java.text.SimpleDateFormat
import
java.util.Date
...
...
@@ -541,9 +541,7 @@ internal class GeckoPromptDelegate(private val geckoEngineSession: GeckoEngineSe
val
temporalFile
=
java
.
io
.
File
(
cacheUploadDirectory
,
getFileName
(
contentResolver
))
try
{
contentResolver
.
openInputStream
(
this
)
!!
.
use
{
inStream
->
FileOutputStream
(
temporalFile
).
use
{
outStream
->
inStream
.
copyTo
(
outStream
)
}
copyFile
(
temporalFile
,
inStream
)
}
}
catch
(
e
:
IOException
)
{
Logger
(
"GeckoPromptDelegate"
).
warn
(
"Could not convert uri to file uri"
,
e
)
...
...
@@ -551,15 +549,11 @@ internal class GeckoPromptDelegate(private val geckoEngineSession: GeckoEngineSe
return
Uri
.
parse
(
"file:///${temporalFile.absolutePath}"
)
}
private
fun
Uri
.
getFileName
(
contentResolver
:
ContentResolver
):
String
{
val
returnUri
=
this
var
fileName
=
""
contentResolver
.
query
(
returnUri
,
null
,
null
,
null
,
null
)
?.
use
{
cursor
->
val
nameIndex
=
cursor
.
getColumnIndex
(
OpenableColumns
.
DISPLAY_NAME
)
cursor
.
moveToFirst
()
fileName
=
cursor
.
getString
(
nameIndex
)
@VisibleForTesting
internal
fun
copyFile
(
temporalFile
:
File
,
inStream
:
InputStream
):
Long
{
return
FileOutputStream
(
temporalFile
).
use
{
outStream
->
inStream
.
copyTo
(
outStream
)
}
return
fileName
.
sanitizeFileName
()
}
}
...
...
components/browser/engine-gecko/src/test/java/mozilla/components/browser/engine/gecko/prompt/GeckoPromptDelegateTest.kt
View file @
a1cd163c
...
...
@@ -13,6 +13,7 @@ import mozilla.components.concept.engine.prompt.PromptRequest
import
mozilla.components.concept.engine.prompt.PromptRequest.MultipleChoice
import
mozilla.components.concept.engine.prompt.PromptRequest.SingleChoice
import
mozilla.components.support.ktx.kotlin.toDate
import
mozilla.components.support.test.any
import
mozilla.components.support.test.mock
import
mozilla.components.support.test.robolectric.testContext
import
mozilla.components.support.test.whenever
...
...
@@ -24,6 +25,8 @@ import org.junit.Assert.assertTrue
import
org.junit.Before
import
org.junit.Test
import
org.junit.runner.RunWith
import
org.mockito.Mockito.spy
import
org.mockito.Mockito.doReturn
import
org.mozilla.gecko.util.GeckoBundle
import
org.mozilla.geckoview.GeckoRuntime
import
org.mozilla.geckoview.GeckoSession
...
...
@@ -35,7 +38,6 @@ import org.mozilla.geckoview.GeckoSession.PromptDelegate.DateTimePrompt.Type.WEE
import
org.mozilla.geckoview.GeckoSession.PromptDelegate.FilePrompt.Capture.ANY
import
org.mozilla.geckoview.GeckoSession.PromptDelegate.FilePrompt.Capture.NONE
import
org.mozilla.geckoview.GeckoSession.PromptDelegate.FilePrompt.Capture.USER
import
org.robolectric.Shadows.shadowOf
import
java.io.FileInputStream
import
java.security.InvalidParameterException
import
java.util.Calendar
...
...
@@ -549,20 +551,23 @@ class GeckoPromptDelegateTest {
@Test
fun
`Calling
onFilePrompt
must
provide
a
FilePicker
PromptRequest`
()
{
val
context
=
testContext
val
context
=
spy
(
testContext
)
val
contentResolver
=
spy
(
context
.
contentResolver
)
val
mockSession
=
GeckoEngineSession
(
runtime
)
var
onSingleFileSelectedWasCalled
=
false
var
onMultipleFilesSelectedWasCalled
=
false
var
onDismissWasCalled
=
false
val
mockUri
:
Uri
=
mock
()
val
mockFileInput
:
FileInputStream
=
mock
()
val
shadowContentResolver
=
shadowOf
(
context
.
contentResolver
)
shadowContentResolver
.
registerInputStream
(
mockUri
,
mockFileInput
)
doReturn
(
contentResolver
).
`when`
(
context
).
contentResolver
doReturn
(
mock
<
FileInputStream
>()).
`when`
(
contentResolver
).
openInputStream
(
any
())
var
filePickerRequest
:
PromptRequest
.
File
=
mock
()
val
promptDelegate
=
GeckoPromptDelegate
(
mockSession
)
val
promptDelegate
=
spy
(
GeckoPromptDelegate
(
mockSession
))
// Prevent the file from being copied
doReturn
(
0L
).
`when`
(
promptDelegate
).
copyFile
(
any
(),
any
())
mockSession
.
register
(
object
:
EngineSession
.
Observer
{
override
fun
onPromptRequest
(
promptRequest
:
PromptRequest
)
{
filePickerRequest
=
promptRequest
as
PromptRequest
.
File
...
...
components/support/ktx/src/main/java/mozilla/components/support/ktx/android/net/Uri.kt
View file @
a1cd163c
...
...
@@ -8,8 +8,13 @@ import android.content.ContentResolver
import
android.content.Context
import
android.net.Uri
import
android.os.Build
import
android.provider.OpenableColumns
import
android.webkit.MimeTypeMap
import
androidx.annotation.VisibleForTesting
import
mozilla.components.support.ktx.kotlin.sanitizeFileName
import
java.io.File
import
java.io.IOException
import
java.util.UUID
private
val
commonPrefixes
=
listOf
(
"www."
,
"mobile."
,
"m."
)
...
...
@@ -85,3 +90,55 @@ fun Uri.isUnderPrivateAppDirectory(context: Context): Boolean {
else
->
false
}
}
/**
* Return a file name for [this] give Uri.
* @return A file name for the content, or generated file name if the URL is invalid or the type is unknown
*/
fun
Uri
.
getFileName
(
contentResolver
:
ContentResolver
):
String
{
return
when
(
this
.
scheme
)
{
ContentResolver
.
SCHEME_FILE
->
File
(
path
?:
""
).
name
.
sanitizeFileName
()
ContentResolver
.
SCHEME_CONTENT
->
getFileNameForContentUris
(
contentResolver
)
else
->
{
generateFileName
(
getFileExtension
(
contentResolver
))
}
}
}
/**
* Return a file extension for [this] give Uri (only supports content:// schemes).
* @return A file extension for the content, or empty string if the URL is invalid or the type is unknown
*/
fun
Uri
.
getFileExtension
(
contentResolver
:
ContentResolver
):
String
{
return
MimeTypeMap
.
getSingleton
().
getExtensionFromMimeType
(
contentResolver
.
getType
(
this
))
?:
""
}
@VisibleForTesting
internal
fun
Uri
.
getFileNameForContentUris
(
contentResolver
:
ContentResolver
):
String
{
var
fileName
=
""
contentResolver
.
query
(
this
,
null
,
null
,
null
,
null
)
?.
use
{
cursor
->
val
nameIndex
=
cursor
.
getColumnIndex
(
OpenableColumns
.
DISPLAY_NAME
)
val
fileExtension
=
getFileExtension
(
contentResolver
)
fileName
=
if
(
nameIndex
==
-
1
)
{
generateFileName
(
fileExtension
)
}
else
{
cursor
.
moveToFirst
()
cursor
.
getString
(
nameIndex
)
?:
generateFileName
(
fileExtension
)
}
}
return
fileName
.
sanitizeFileName
()
}
/**
* Generate a file name using a randomUUID + the current timestamp.
*/
@VisibleForTesting
internal
fun
generateFileName
(
fileExtension
:
String
=
""
):
String
{
val
randomId
=
UUID
.
randomUUID
().
toString
().
removePrefix
(
"-"
).
trim
()
val
timeStamp
=
System
.
currentTimeMillis
()
return
if
(
fileExtension
.
isNotEmpty
())
{
"$randomId$timeStamp.$fileExtension"
}
else
{
"$randomId$timeStamp"
}
}
components/support/ktx/src/test/java/mozilla/components/support/ktx/android/net/UriTest.kt
View file @
a1cd163c
...
...
@@ -4,14 +4,22 @@
package
mozilla.components.support.ktx.android.net
import
android.content.ContentResolver
import
android.database.Cursor
import
android.webkit.MimeTypeMap
import
androidx.core.net.toUri
import
androidx.test.ext.junit.runners.AndroidJUnit4
import
mozilla.components.support.test.mock
import
org.junit.Assert.assertEquals
import
org.junit.Assert.assertFalse
import
org.junit.Assert.assertNull
import
org.junit.Assert.assertTrue
import
org.junit.Test
import
org.junit.runner.RunWith
import
org.mockito.ArgumentMatchers.anyInt
import
org.mockito.Mockito.any
import
org.mockito.Mockito.doReturn
import
org.robolectric.Shadows
@RunWith
(
AndroidJUnit4
::
class
)
class
UriTest
{
...
...
@@ -109,4 +117,122 @@ class UriTest {
assertTrue
(
"https://foo.bar:443/bobo"
.
toUri
().
sameOriginAs
(
"https://foo.bar:443/obob"
.
toUri
()))
assertTrue
(
"https://foo.bar:333"
.
toUri
().
sameOriginAs
(
"https://foo.bar:333"
.
toUri
()))
}
@Test
fun
testGenerateFileName
()
{
val
fileExtension
=
"txt"
var
fileName
=
generateFileName
(
fileExtension
)
assertTrue
(
fileName
.
contains
(
fileExtension
))
fileName
=
generateFileName
()
assertFalse
(
fileName
.
contains
(
"."
))
}
@Test
fun
testGetFileExtension
()
{
val
resolver
=
mock
<
ContentResolver
>()
val
uri
=
"content://media/external/file/37162"
.
toUri
()
Shadows
.
shadowOf
(
MimeTypeMap
.
getSingleton
()).
addExtensionMimeTypMapping
(
"txt"
,
"text/plain"
)
doReturn
(
"text/plain"
).
`when`
(
resolver
).
getType
(
any
())
assertEquals
(
"txt"
,
uri
.
getFileExtension
(
resolver
))
}
@Test
fun
`getFileNameForContentUris
for
urls
with
DISPLAY_NAME`
()
{
val
resolver
=
mock
<
ContentResolver
>()
val
uri
=
"content://media/external/file/37162"
.
toUri
()
val
cursor
=
mock
<
Cursor
>()
Shadows
.
shadowOf
(
MimeTypeMap
.
getSingleton
()).
addExtensionMimeTypMapping
(
"txt"
,
"text/plain"
)
doReturn
(
"text/plain"
).
`when`
(
resolver
).
getType
(
any
())
doReturn
(
cursor
).
`when`
(
resolver
).
query
(
any
(),
any
(),
any
(),
any
(),
any
())
doReturn
(
1
).
`when`
(
cursor
).
getColumnIndex
(
any
())
doReturn
(
"myFile.txt"
).
`when`
(
cursor
).
getString
(
anyInt
())
assertEquals
(
"myFile.txt"
,
uri
.
getFileNameForContentUris
(
resolver
))
}
@Test
fun
`getFileNameForContentUris
for
urls
without
DISPLAY_NAME`
()
{
val
resolver
=
mock
<
ContentResolver
>()
val
uri
=
"content://media/external/file/37162"
.
toUri
()
val
cursor
=
mock
<
Cursor
>()
Shadows
.
shadowOf
(
MimeTypeMap
.
getSingleton
()).
addExtensionMimeTypMapping
(
"txt"
,
"text/plain"
)
doReturn
(
"text/plain"
).
`when`
(
resolver
).
getType
(
any
())
doReturn
(
cursor
).
`when`
(
resolver
).
query
(
any
(),
any
(),
any
(),
any
(),
any
())
doReturn
(-
1
).
`when`
(
cursor
).
getColumnIndex
(
any
())
val
fileName
=
uri
.
getFileNameForContentUris
(
resolver
)
assertTrue
(
fileName
.
contains
(
".txt"
))
assertTrue
(
fileName
.
isNotEmpty
())
}
@Test
fun
`getFileNameForContentUris
for
urls
with
null
DISPLAY_NAME`
()
{
val
resolver
=
mock
<
ContentResolver
>()
val
uri
=
"content://media/external/file/37162"
.
toUri
()
val
cursor
=
mock
<
Cursor
>()
Shadows
.
shadowOf
(
MimeTypeMap
.
getSingleton
()).
addExtensionMimeTypMapping
(
"txt"
,
"text/plain"
)
doReturn
(
"text/plain"
).
`when`
(
resolver
).
getType
(
any
())
doReturn
(
cursor
).
`when`
(
resolver
).
query
(
any
(),
any
(),
any
(),
any
(),
any
())
doReturn
(
1
).
`when`
(
cursor
).
getColumnIndex
(
any
())
doReturn
(
null
).
`when`
(
cursor
).
getString
(
anyInt
())
val
fileName
=
uri
.
getFileNameForContentUris
(
resolver
)
assertTrue
(
fileName
.
contains
(
".txt"
))
assertTrue
(
fileName
.
isNotEmpty
())
}
@Test
fun
`getFileName
for
file
uri
schemes`
()
{
val
resolver
=
mock
<
ContentResolver
>()
val
uri
=
"file:///home/user/myfile.html"
.
toUri
()
assertEquals
(
"myfile.html"
,
uri
.
getFileName
(
resolver
))
}
@Test
fun
`getFileName
for
content
uri
schemes`
()
{
val
resolver
=
mock
<
ContentResolver
>()
val
uri
=
"content://media/external/file/37162"
.
toUri
()
val
cursor
=
mock
<
Cursor
>()
Shadows
.
shadowOf
(
MimeTypeMap
.
getSingleton
()).
addExtensionMimeTypMapping
(
"txt"
,
"text/plain"
)
doReturn
(
"text/plain"
).
`when`
(
resolver
).
getType
(
any
())
doReturn
(
cursor
).
`when`
(
resolver
).
query
(
any
(),
any
(),
any
(),
any
(),
any
())
doReturn
(
1
).
`when`
(
cursor
).
getColumnIndex
(
any
())
doReturn
(
null
).
`when`
(
cursor
).
getString
(
anyInt
())
val
fileName
=
uri
.
getFileName
(
resolver
)
assertTrue
(
fileName
.
contains
(
".txt"
))
assertTrue
(
fileName
.
isNotEmpty
())
}
@Test
fun
`getFileName
for
UNKNOWN
uri
schemes
will
generate
file
name`
()
{
val
resolver
=
mock
<
ContentResolver
>()
val
uri
=
"UNKNOWN://media/external/file/37162"
.
toUri
()
Shadows
.
shadowOf
(
MimeTypeMap
.
getSingleton
()).
addExtensionMimeTypMapping
(
"txt"
,
"text/plain"
)
doReturn
(
"text/plain"
).
`when`
(
resolver
).
getType
(
any
())