Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .config/dotnet-tools.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"rollForward": false
},
"fantomas": {
"version": "8.0.4",
"version": "8.0.5",
"commands": [
"fantomas"
],
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ jobs:
just setup
just restore

#- name: Check formatting
# run: just format-check
- name: Check formatting
run: just format-check

- name: Build
run: just build
Expand Down
6 changes: 4 additions & 2 deletions src/otp/File.fs
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,14 @@ let delDir (path: string) : Result<unit, string> = nativeOnly
let listDir (path: string) : Result<string list, string> = nativeOnly

/// Reads metadata for a filesystem entry, following symbolic links.
let readFileInfo (path: string) : Result<FileInfo, string> = readFileInfoRaw path |> mapFileInfoResult
let readFileInfo (path: string) : Result<FileInfo, string> =
readFileInfoRaw path |> mapFileInfoResult

/// Reads metadata for a filesystem entry without following a symbolic link.
/// A missing path is returned as `Error "enoent"`, consistently with the other
/// typed file functions.
let readLinkInfo (path: string) : Result<FileInfo, string> = readLinkInfoRaw path |> mapFileInfoResult
let readLinkInfo (path: string) : Result<FileInfo, string> =
readLinkInfoRaw path |> mapFileInfoResult

/// Renames (moves) a file. Handles binary_to_list conversion for both paths.
[<Emit("(fun() -> case file:rename(binary_to_list($0), binary_to_list($1)) of ok -> {ok, ok}; {error, FileRenameReason__} -> {error, erlang:atom_to_binary(FileRenameReason__)} end end)()")>]
Expand Down
7 changes: 4 additions & 3 deletions src/otp/GenTcp.fs
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ module ConnectOptions =
}

[<Emit("gen_tcp:connect(binary_to_list($0), $1, [binary, {active, false}, {packet, $2}])")>]
let private connectDefaultRaw (host: string) (port: int) (packetMode: PacketMode) : Result<Socket, Dynamic> =
nativeOnly
let private connectDefaultRaw (host: string) (port: int) (packetMode: PacketMode) : Result<Socket, Dynamic> = nativeOnly

[<Emit("gen_tcp:connect(binary_to_list($0), $1, [binary, {active, false}, {packet, $2}], $3)")>]
let private connectTimeoutRaw
Expand All @@ -59,7 +58,9 @@ let private formatError (reason: Dynamic) : string = nativeOnly
let connect (host: string) (port: int) (options: ConnectOptions) : Result<Socket, string> =
match options.connectTimeoutMs with
| Some timeoutMs when timeoutMs < 0 -> Error "connect timeout must be non-negative"
| Some timeoutMs -> connectTimeoutRaw host port options.packetMode timeoutMs |> Result.mapError formatError
| Some timeoutMs ->
connectTimeoutRaw host port options.packetMode timeoutMs
|> Result.mapError formatError
| None -> connectDefaultRaw host port options.packetMode |> Result.mapError formatError

/// Connects a passive binary, line-delimited client using OTP's default timeout.
Expand Down
44 changes: 25 additions & 19 deletions src/otp/Port.fs
Original file line number Diff line number Diff line change
Expand Up @@ -25,26 +25,30 @@ type PortMonitor = private PortMonitor of obj
/// opts into OTP link semantics; it is false by default so an unexpected child
/// exit cannot terminate the caller.
type PortOptions =
{ arguments: string list
maxLineLength: int
exitStatus: bool
useStdio: bool
stderrToStdout: bool
workingDirectory: string option
environment: (string * string) list
linkOwner: bool }
{
arguments: string list
maxLineLength: int
exitStatus: bool
useStdio: bool
stderrToStdout: bool
workingDirectory: string option
environment: (string * string) list
linkOwner: bool
}

/// Safe defaults for a line-oriented stdin/stdout process connection.
module PortOptions =
let defaultOptions =
{ arguments = []
maxLineLength = 8192
exitStatus = true
useStdio = true
stderrToStdout = false
workingDirectory = None
environment = []
linkOwner = false }
{
arguments = []
maxLineLength = 8192
exitStatus = true
useStdio = true
stderrToStdout = false
workingDirectory = None
environment = []
linkOwner = false
}

/// A message delivered by a port opened with line mode. `ExitStatus` is
/// delivered when `PortOptions.exitStatus` is enabled.
Expand Down Expand Up @@ -112,9 +116,11 @@ let private launchOptions (options: PortOptions) =
| Some path -> [ workingDirectoryOption path ]
| None -> []

[ binaryOption
lineOption options.maxLineLength
argumentsOption options.arguments ]
[
binaryOption
lineOption options.maxLineLength
argumentsOption options.arguments
]
@ optional options.exitStatus exitStatusOption
@ optional options.useStdio useStdioOption
@ optional options.stderrToStdout stderrToStdoutOption
Expand Down
12 changes: 7 additions & 5 deletions src/otp/Supervisor.fs
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,13 @@ let shutdownInfinity: Shutdown = nativeOnly
/// A child specification (map form). `Start` is the `{Module, Function, Args}`
/// entry point that returns `{ok, Pid}`. Compiles to an Erlang child-spec map.
type ChildSpec =
{ Id: Atom
Start: Atom * Atom * obj list
Restart: Restart
Shutdown: Shutdown
Type: ChildType }
{
Id: Atom
Start: Atom * Atom * obj list
Restart: Restart
Shutdown: Shutdown
Type: ChildType
}

// ============================================================================
// Supervisor reference
Expand Down
58 changes: 30 additions & 28 deletions test/Main.fs
Original file line number Diff line number Diff line change
Expand Up @@ -10,31 +10,33 @@ open type Scriptorium.Quill.Runner
[<EntryPoint>]
let main _ =
runTests
[ Timer.tests
Maps.tests
GenServer.tests
Base64.tests
Math.tests
Io.tests
IoLib.tests
Rand.tests
Proplists.tests
Binary.tests
Calendar.tests
GenTcp.tests
Distribution.tests
Queue.tests
Lists.tests
String.tests
Erlang.tests
Re.tests
Dynamic.tests
UriString.tests
Callbacks.tests
Os.tests
Port.tests
Supervisor.tests
Logger.tests
File.tests
Ets.tests
Jsx.tests ]
[
Timer.tests
Maps.tests
GenServer.tests
Base64.tests
Math.tests
Io.tests
IoLib.tests
Rand.tests
Proplists.tests
Binary.tests
Calendar.tests
GenTcp.tests
Distribution.tests
Queue.tests
Lists.tests
String.tests
Erlang.tests
Re.tests
Dynamic.tests
UriString.tests
Callbacks.tests
Os.tests
Port.tests
Supervisor.tests
Logger.tests
File.tests
Ets.tests
Jsx.tests
]
102 changes: 52 additions & 50 deletions test/TestBase64.fs
Original file line number Diff line number Diff line change
Expand Up @@ -12,63 +12,65 @@ module BBase64 = Fable.Beam.Base64
let tests =
testList (
"Base64",
[ test (
"encode produces non-empty string",
fun _ ->
let encoded = BBase64.encode "hello"
assertThat (encoded.Length > 0) (isTrue)
)
[
test (
"encode produces non-empty string",
fun _ ->
let encoded = BBase64.encode "hello"
assertThat (encoded.Length > 0) (isTrue)
)

test ("encode of hello", fun _ -> assertThat (BBase64.encode "hello") (isEqualTo "aGVsbG8="))
test ("encode of hello", fun _ -> assertThat (BBase64.encode "hello") (isEqualTo "aGVsbG8="))

test ("encode of empty string", fun _ -> assertThat (BBase64.encode "") (isEqualTo ""))
test ("encode of empty string", fun _ -> assertThat (BBase64.encode "") (isEqualTo ""))

test (
"decode reverses encode",
fun _ ->
let original = "hello world"
let encoded = BBase64.encode original
let decoded = BBase64.decode encoded
assertThat decoded (isEqualTo original)
)
test (
"decode reverses encode",
fun _ ->
let original = "hello world"
let encoded = BBase64.encode original
let decoded = BBase64.decode encoded
assertThat decoded (isEqualTo original)
)

test ("decode of known value", fun _ -> assertThat (BBase64.decode "aGVsbG8=") (isEqualTo "hello"))
test ("decode of known value", fun _ -> assertThat (BBase64.decode "aGVsbG8=") (isEqualTo "hello"))

test (
"encode decode roundtrip with binary data",
fun _ ->
let data = "Fable.Beam rocks!"
let encoded = BBase64.encode data
let decoded = BBase64.decode encoded
assertThat decoded (isEqualTo data)
)
test (
"encode decode roundtrip with binary data",
fun _ ->
let data = "Fable.Beam rocks!"
let encoded = BBase64.encode data
let decoded = BBase64.decode encoded
assertThat decoded (isEqualTo data)
)

test (
"mime_decode handles whitespace",
fun _ ->
let encoded = BBase64.encode "hello"
let decoded = BBase64.mimeDecode encoded
assertThat decoded (isEqualTo "hello")
)
test (
"mime_decode handles whitespace",
fun _ ->
let encoded = BBase64.encode "hello"
let decoded = BBase64.mimeDecode encoded
assertThat decoded (isEqualTo "hello")
)

test (
"tryDecode returns Some for valid base64",
fun _ ->
let result = BBase64.tryDecode "aGVsbG8="
assertThat result (isEqualTo (Some "hello"))
)
test (
"tryDecode returns Some for valid base64",
fun _ ->
let result = BBase64.tryDecode "aGVsbG8="
assertThat result (isEqualTo (Some "hello"))
)

test (
"tryDecode returns None for invalid base64",
fun _ ->
let result = BBase64.tryDecode "not!valid@base64#"
assertThat result (isEqualTo None)
)
test (
"tryDecode returns None for invalid base64",
fun _ ->
let result = BBase64.tryDecode "not!valid@base64#"
assertThat result (isEqualTo None)
)

test (
"tryMimeDecode returns Some for valid input",
fun _ ->
let result = BBase64.tryMimeDecode "aGVsbG8="
assertThat result (isEqualTo (Some "hello"))
) ]
test (
"tryMimeDecode returns Some for valid input",
fun _ ->
let result = BBase64.tryMimeDecode "aGVsbG8="
assertThat result (isEqualTo (Some "hello"))
)
]
)
Loading
Loading