Skip to content

Commit 8db7989

Browse files
committed
File reading now works on Native
1 parent 1afb5a8 commit 8db7989

File tree

8 files changed

+107
-199
lines changed

8 files changed

+107
-199
lines changed

sconfig/jvm-native/src/test/scala/org/ekrich/config/impl/ConfigFactoryJvmNativeTest.scala sconfig/jvm-native/src/test/scala/org/ekrich/config/impl/ConfigFactoryDocumentTest.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ package org.ekrich.config.impl
33
// import org.junit.Assert._
44
// import org.junit.Test
55

6-
class ConfigFactoryJvmNativeTest {
6+
class ConfigFactoryDocumentTest {
77
// Empty for now - Scala.js has parody with Scala Native for now
88
}

sconfig/jvm/src/test/scala/org/ekrich/config/impl/ConfigDocumentFactoryJvmTest.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class ConfigDocumentFactoryJvmTest extends TestUtils {
1515
val configDocument =
1616
ConfigDocumentFactory.parseFile(resourceFile("/test03.conf"))
1717
val fileReader = new BufferedReader(
18-
new FileReader("src/test/resources/test03.conf")
18+
new FileReader(resourceFile("/test03.conf"))
1919
)
2020
var line = fileReader.readLine()
2121
val sb = new StringBuilder()

sconfig/native/src/main/scala/java/net/URL.scala

+3-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ class URL(from: String) {
1414

1515
def toURI(): java.net.URI = ???
1616

17-
def toExternalForm(): java.lang.String = ???
17+
def toExternalForm(): java.lang.String = from
18+
19+
override def toString(): java.lang.String = toExternalForm()
1820

1921
// added
2022
def getFile(): String = ???

sconfig/native/src/test/scala/org/ekrich/config/impl/ConfigDocumentFactoryJvmTest.scala sconfig/native/src/test/scala/org/ekrich/config/impl/ConfigDocumentFactoryNativeTest.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@ import org.junit.Test
88

99
import FileUtils._
1010

11-
class ConfigDocumentFactoryJvmTest extends TestUtils {
11+
class ConfigDocumentFactoryNativeTest extends TestUtils {
1212

1313
@Test
1414
def configDocumentFileParse: Unit = {
1515
val configDocument =
1616
ConfigDocumentFactory.parseFile(resourceFile("/test03.conf"))
1717
val fileReader = new BufferedReader(
18-
new FileReader("src/test/resources/test03.conf")
18+
new FileReader(resourceFile("/test03.conf"))
1919
)
2020
var line = fileReader.readLine()
2121
val sb = new StringBuilder()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/**
2+
* Copyright (C) 2011 Typesafe Inc. <http://typesafe.com>
3+
*/
4+
package org.ekrich.config.impl
5+
6+
import java.io.File
7+
import java.util.Locale
8+
9+
/**
10+
* Extracted from TestUtils as they contain File and Path and are not useful on
11+
* Scala.js
12+
*
13+
* Note: Some functions may only be used in this file so they could be made
14+
* private.
15+
*/
16+
object FileUtils {
17+
// Some functions duplicated in TestUtils
18+
19+
def isWindows: Boolean =
20+
sys.props
21+
.get("os.name")
22+
.exists(_.toLowerCase(Locale.ROOT).contains("windows"))
23+
24+
def userDrive: String =
25+
if (isWindows)
26+
sys.props.get("user.dir").fold("")(_.takeWhile(_ != File.separatorChar))
27+
else ""
28+
29+
val resourceDir = {
30+
val f = new File("sconfig/native/src/test/resources")
31+
if (!f.exists()) {
32+
val here = new File(".").getAbsolutePath
33+
throw new Exception(
34+
s"""Tests must be run from the root project directory containing
35+
| ${f.getPath()}, however the current directory is
36+
| ${here}""".stripMargin
37+
)
38+
}
39+
f
40+
}
41+
42+
def resourceFile(filename: String): File =
43+
new File(resourceDir, filename)
44+
45+
def jsonQuotedResourceFile(filename: String): String =
46+
quoteJsonString(resourceFile(filename).toString)
47+
48+
def quoteJsonString(s: String): String =
49+
ConfigImplUtil.renderJsonString(s)
50+
51+
def writeFile(f: File, content: String): Unit = {
52+
val writer = new java.io.PrintWriter(f, "UTF-8")
53+
writer.append(content)
54+
writer.close()
55+
}
56+
57+
def deleteRecursive(f: File): Unit = {
58+
if (f.exists) {
59+
if (f.isDirectory) {
60+
val children = f.listFiles()
61+
if (children ne null) {
62+
for (c <- children)
63+
deleteRecursive(c)
64+
}
65+
}
66+
f.delete()
67+
}
68+
}
69+
70+
def withScratchDirectory[T](
71+
testcase: String
72+
)(body: File => T): Unit = {
73+
val target = new File("target")
74+
if (!target.isDirectory)
75+
throw new RuntimeException(s"Expecting $target to exist")
76+
val suffix = java.lang.Integer
77+
.toHexString(java.util.concurrent.ThreadLocalRandom.current.nextInt)
78+
val scratch = new File(target, s"$testcase-$suffix")
79+
scratch.mkdirs()
80+
try {
81+
body(scratch)
82+
} finally {
83+
deleteRecursive(scratch)
84+
}
85+
}
86+
}

sconfig/native/src/test/scala/org/ekrich/config/impl/TestUtils.scala

+11-194
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,24 @@
44
package org.ekrich.config.impl
55

66
import org.junit.Assert._
7-
import org.ekrich.config.ConfigOrigin
7+
88
import java.io.Reader
99
import java.io.StringReader
10-
import org.ekrich.config.ConfigParseOptions
11-
import org.ekrich.config.ConfigSyntax
12-
import org.ekrich.config.ConfigFactory
13-
import java.io.ByteArrayOutputStream
14-
import java.io.ObjectOutputStream
15-
import java.io.ByteArrayInputStream
16-
import java.io.ObjectInputStream
17-
import java.io.NotSerializableException
18-
import java.io.OutputStream
19-
import java.io.InputStream
20-
import scala.annotation.tailrec
2110
import java.net.URL
2211
import java.util.concurrent.Executors
2312
import java.util.concurrent.Callable
24-
import org.ekrich.config._
13+
14+
import scala.annotation.tailrec
15+
import scala.jdk.CollectionConverters._
16+
import scala.language.implicitConversions
2517
import scala.reflect.ClassTag
2618
import scala.reflect.classTag
27-
import scala.jdk.CollectionConverters._
28-
import language.implicitConversions
19+
20+
import org.ekrich.config._
21+
import org.ekrich.config.ConfigOrigin
22+
import org.ekrich.config.ConfigFactory
23+
import org.ekrich.config.ConfigParseOptions
24+
import org.ekrich.config.ConfigSyntax
2925

3026
abstract trait TestUtils {
3127
protected def intercept[E <: Throwable: ClassTag](block: => Any): E = {
@@ -151,20 +147,6 @@ abstract trait TestUtils {
151147
a
152148
}
153149

154-
private def copyViaSerialize(o: java.io.Serializable): AnyRef = {
155-
val byteStream = new ByteArrayOutputStream()
156-
val objectStream = new ObjectOutputStream(byteStream)
157-
objectStream.writeObject(o)
158-
objectStream.close()
159-
val bytes = byteStream.toByteArray()
160-
// outputStringLiteral(bytes) // uncomment to print
161-
val inStream = new ByteArrayInputStream(bytes)
162-
val inObjectStream = new ObjectInputStream(inStream)
163-
val copy = inObjectStream.readObject()
164-
inObjectStream.close()
165-
copy
166-
}
167-
168150
def outputStringLiteral(bytes: Array[Byte]): Unit = {
169151
val hex = encodeLegibleBinary(bytes)
170152
outputStringLiteral(hex)
@@ -180,142 +162,6 @@ abstract trait TestUtils {
180162
}
181163
}
182164

183-
protected def checkSerializationCompat[T: ClassTag](
184-
expectedHex: String,
185-
o: T,
186-
changedOK: Boolean = false
187-
): Unit = {
188-
// be sure we can still deserialize the old one
189-
val inStream = new ByteArrayInputStream(decodeLegibleBinary(expectedHex))
190-
var failure: Option[Exception] = None
191-
var inObjectStream: ObjectInputStream = null
192-
val deserialized =
193-
try {
194-
inObjectStream = new ObjectInputStream(inStream) // this can throw too
195-
inObjectStream.readObject()
196-
} catch {
197-
case e: Exception =>
198-
failure = Some(e)
199-
null
200-
} finally {
201-
if (inObjectStream != null)
202-
inObjectStream.close()
203-
}
204-
205-
val why = failure
206-
.map({ e => ": " + e.getClass.getSimpleName + ": " + e.getMessage })
207-
.getOrElse("")
208-
209-
val byteStream = new ByteArrayOutputStream()
210-
val objectStream = new ObjectOutputStream(byteStream)
211-
objectStream.writeObject(o)
212-
objectStream.close()
213-
val hex = encodeLegibleBinary(byteStream.toByteArray())
214-
def showCorrectResult(): Unit = {
215-
if (expectedHex != hex) {
216-
System.err.println(
217-
"Correct result literal for " + o.getClass.getSimpleName + " serialization:"
218-
)
219-
System.err.println(
220-
"\"\" + "
221-
) // line up all the lines by using empty string on first line
222-
outputStringLiteral(hex)
223-
}
224-
}
225-
226-
try {
227-
assertEquals(
228-
"Can no longer deserialize the old format of " + o.getClass.getSimpleName + why,
229-
o,
230-
deserialized
231-
)
232-
assertFalse(failure.isDefined) // should have thrown if we had a failure
233-
234-
if (!changedOK)
235-
assertEquals(
236-
o.getClass.getSimpleName + " serialization has changed (though we still deserialized the old serialization)",
237-
expectedHex,
238-
hex
239-
)
240-
} catch {
241-
case e: Throwable =>
242-
showCorrectResult()
243-
throw e
244-
}
245-
}
246-
247-
// no ObjectOutputStream / Serialization on Scala.js
248-
protected def checkNotSerializable(o: AnyRef): Unit = {
249-
val byteStream = new ByteArrayOutputStream()
250-
val objectStream = new ObjectOutputStream(byteStream)
251-
val e = intercept[NotSerializableException] {
252-
objectStream.writeObject(o)
253-
}
254-
objectStream.close()
255-
}
256-
257-
protected def checkSerializable[T: ClassTag](expectedHex: String, o: T): T = {
258-
val t = checkSerializable(o)
259-
checkSerializationCompat(expectedHex, o)
260-
t
261-
}
262-
263-
protected def checkSerializableOldFormat[T: ClassTag](
264-
expectedHex: String,
265-
o: T
266-
): T = {
267-
val t = checkSerializable(o)
268-
checkSerializationCompat(expectedHex, o, changedOK = true)
269-
t
270-
}
271-
272-
protected def checkSerializableNoMeaningfulEquals[T: ClassTag](o: T): T = {
273-
assertTrue(
274-
o.getClass.getSimpleName + " not an instance of Serializable",
275-
o.isInstanceOf[java.io.Serializable]
276-
)
277-
278-
val a = o.asInstanceOf[java.io.Serializable]
279-
280-
val b =
281-
try {
282-
copyViaSerialize(a)
283-
} catch {
284-
case nf: ClassNotFoundException =>
285-
throw new AssertionError(
286-
"failed to make a copy via serialization, " +
287-
"possibly caused by http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6446627",
288-
nf
289-
)
290-
case e: Exception =>
291-
e.printStackTrace(System.err)
292-
throw new AssertionError("failed to make a copy via serialization", e)
293-
}
294-
295-
assertTrue(
296-
"deserialized type " + b.getClass.getSimpleName + " doesn't match serialized type " + a.getClass.getSimpleName,
297-
classTag[T].runtimeClass.isAssignableFrom(b.getClass)
298-
)
299-
300-
b.asInstanceOf[T]
301-
}
302-
303-
protected def checkSerializable[T: ClassTag](o: T): T = {
304-
checkEqualObjects(o, o)
305-
306-
assertTrue(
307-
o.getClass.getSimpleName + " not an instance of Serializable",
308-
o.isInstanceOf[java.io.Serializable]
309-
)
310-
311-
val b = checkSerializableNoMeaningfulEquals(o)
312-
313-
checkEqualObjects(o, b)
314-
checkEqualOrigins(o, b)
315-
316-
b
317-
}
318-
319165
// origin() is not part of value equality but is serialized, so
320166
// we check it separately
321167
protected def checkEqualOrigins[T](a: T, b: T): Unit = (a, b) match {
@@ -984,33 +830,4 @@ abstract trait TestUtils {
984830
problems.size
985831
)
986832
}
987-
988-
protected def checkSerializableWithCustomSerializer[T: ClassTag](o: T): T = {
989-
val byteStream = new ByteArrayOutputStream()
990-
val objectStream = new CustomObjectOutputStream(byteStream)
991-
objectStream.writeObject(o)
992-
objectStream.close()
993-
val inStream = new ByteArrayInputStream(byteStream.toByteArray)
994-
val inObjectStream = new CustomObjectInputStream(inStream)
995-
val copy = inObjectStream.readObject()
996-
inObjectStream.close()
997-
copy.asInstanceOf[T]
998-
}
999-
1000-
class CustomObjectOutputStream(out: OutputStream)
1001-
extends ObjectOutputStream(out) {
1002-
override def writeUTF(str: String): Unit = {
1003-
val bytes = str.getBytes
1004-
writeLong(bytes.length)
1005-
write(bytes)
1006-
}
1007-
}
1008-
1009-
class CustomObjectInputStream(in: InputStream) extends ObjectInputStream(in) {
1010-
override def readUTF(): String = {
1011-
val bytes = new Array[Byte](readLong().toByte)
1012-
read(bytes)
1013-
new String(bytes)
1014-
}
1015-
}
1016833
}

sconfig/shared/src/main/scala/org/ekrich/config/impl/SimpleConfigOrigin.scala

+3
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ object SimpleConfigOrigin {
3030
private[impl] def newFile(filename: String): SimpleConfigOrigin = {
3131
var url: String = null
3232
try {
33+
// TODO: Change to Use URI - string bases URL is the same anyway.
34+
// eventually we could change public API to use URI and support
35+
// JS and Native to use different fetching libraries
3336
val uri = new File(filename).toURI()
3437
url = new PlatformUri(uri).toURL().toExternalForm()
3538
} catch {

0 commit comments

Comments
 (0)