Skip to content

Commit

Permalink
#1289 FSharp.Core 7.0 proxies and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Jand42 committed Dec 14, 2022
1 parent 471d3a7 commit 534026e
Show file tree
Hide file tree
Showing 8 changed files with 259 additions and 13 deletions.
2 changes: 1 addition & 1 deletion paket.lock
Original file line number Diff line number Diff line change
Expand Up @@ -872,4 +872,4 @@ GROUP wsbuild

GIT
remote: https://github.com/dotnet-websharper/build-script
(2a22acbfb930c9a34b4843b86d924a2a247cb558)
(9e8c1e75760322e6dff2e976414bd85ec6c0cdbe)
47 changes: 47 additions & 0 deletions src/stdlib/WebSharper.Collections/BalancedTree.fs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ namespace WebSharper.Collections

open WebSharper
open WebSharper.JavaScript
open System.Collections.Generic

/// Provides balanced binary search tree operations.
[<JavaScript>]
Expand Down Expand Up @@ -203,6 +204,30 @@ module internal BalancedTree =
let Add<'T when 'T : comparison> (x: 'T) (t: Tree<'T>) : Tree<'T> =
Put (fun _ x -> x) x t

/// Changes a node into the tree, replacing or removing existing one if found.
let Change<'T when 'T : comparison> (k: 'T) (f: 'T option -> 'T option) (ot: Tree<'T>) : Tree<'T> =
let (t, spine) = Lookup k ot
if IsEmpty t then
match f None with
| Some x ->
Rebuild spine (Branch x Empty Empty)
| None ->
ot
else
match f (Some t.Node) with
| Some x ->
Rebuild spine (Branch x t.Left t.Right)
| None ->
if IsEmpty t.Right then
Rebuild spine t.Left
elif IsEmpty t.Left then
Rebuild spine t.Right
else
Seq.append (Ascend t.Left) (Ascend t.Right)
|> Seq.toArray
|> OfSorted
|> Rebuild spine

/// Checks if a tree contains a given key.
let rec Contains (v: 'T) (t: Tree<'T>) : bool =
not (IsEmpty (fst (Lookup v t)))
Expand All @@ -212,7 +237,29 @@ module internal BalancedTree =
let x = fst (Lookup v t)
if IsEmpty x then None else Some x.Node

/// Looks up minimum value.
let Min (t: Tree<'T>) : 'T =
if IsEmpty t then
raise (KeyNotFoundException())
else
let rec m t =
if IsEmpty t.Left then
t.Node
else
m t.Left
m t

/// Looks up maximum value.
let Max (t: Tree<'T>) : 'T =
if IsEmpty t then
raise (KeyNotFoundException())
else
let rec m t =
if IsEmpty t.Right then
t.Node
else
m t.Right
m t



Expand Down
5 changes: 4 additions & 1 deletion src/stdlib/WebSharper.Collections/Map.fs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ type internal FSharpMap<'K,'V when 'K : comparison>
member this.Add(k: 'K, v: 'V) : Map<'K,'V> =
As (FSharpMap<'K,'V>(tree |> T.Add {Key=k; Value=v}))

member this.Change(k: 'K, f: 'V option -> 'V option) : Map<'K,'V> =
As (FSharpMap<'K,'V>(tree |> T.Change {Key=k; Value=JS.Undefined} (fun x -> f (x |> Option.map (fun p -> p.Value)) |> Option.map (fun v -> {Key=k; Value=v}))))

member this.ContainsKey k =
tree |> T.Contains {Key=k; Value = JS.Undefined}

Expand All @@ -78,7 +81,7 @@ type internal FSharpMap<'K,'V when 'K : comparison>
match this.TryFind k with
| Some v ->v
| None ->
failwith "The given key was not present in the dictionary."
raise (KeyNotFoundException())

member this.Remove(k: 'K) : Map<'K,'V> =
As (FSharpMap(tree |> T.Remove {Key=k; Value=JS.Undefined}))
Expand Down
14 changes: 14 additions & 0 deletions src/stdlib/WebSharper.Collections/MapModule.fs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ module internal MapModule =
[<Inline>]
let Add k v (m: Map<'K,'V>) : Map<'K,'V> = m.Add(k, v)

[<Inline>]
let Change k f (m: Map<'K,'V>) : Map<'K,'V> = m.Change(k, f)

[<Inline>]
let ContainsKey k (m: Map<'K,'V>) : bool = m.ContainsKey k

Expand Down Expand Up @@ -119,6 +122,7 @@ module internal MapModule =
T.Ascend (ToTree m)
|> Seq.map (fun kv -> (kv.Key, kv.Value))

[<Inline>]
let TryFind (k: 'K) (m: Map<'K, 'V>) : option<'V> = m.TryFind k

let TryFindKey (f: 'K -> 'V -> bool) (m: Map<'K,'V>) : option<'K> =
Expand All @@ -135,6 +139,16 @@ module internal MapModule =
|> T.OfSeq
|> OfTree

[<Inline>]
let Keys (m: Map<'K, 'V>) : System.Collections.Generic.ICollection<'K> = m.Keys

[<Inline>]
let Values (m: Map<'K, 'V>) : System.Collections.Generic.ICollection<'V> = m.Values

let MinKeyValue (m: Map<'K, 'V>) =
let x = T.Min(ToTree m)
x.Key, x.Value

let MaxKeyValue (m: Map<'K, 'V>) =
let x = T.Max(ToTree m)
x.Key, x.Value
4 changes: 2 additions & 2 deletions src/stdlib/WebSharper.Main.Proxies/Dictionary.fs
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ type private D<'K,'V> = Dictionary<'K,'V>
module internal DictionaryUtil =

let notPresent () =
failwith "The given key was not present in the dictionary."
raise (KeyNotFoundException())

let alreadyAdded () =
failwith "An item with the same key has already been added."
raise (System.ArgumentException("An item with the same key has already been added."))

let equals (c: IEqualityComparer<'T>) =
FuncWithArgs(fun (x, y) -> c.Equals(x, y))
Expand Down
80 changes: 80 additions & 0 deletions src/stdlib/WebSharper.Main.Proxies/ResultModule.fs
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,83 @@ let MapError f r =
match r with
| Ok x -> Ok x
| Error e -> Error (f e)

let IsOk result =
match result with
| Ok _ -> true
| Error _ -> false

let IsError result =
match result with
| Ok _ -> false
| Error _ -> true

let DefaultValue value result =
match result with
| Error _ -> value
| Ok v -> v

let DefaultWith defThunk result =
match result with
| Error error -> defThunk error
| Ok v -> v

let Count result =
match result with
| Error _ -> 0
| Ok _ -> 1

let Fold<'T, 'Error, 'State> folder (state: 'State) (result: Result<'T, 'Error>) =
match result with
| Error _ -> state
| Ok x -> folder state x

let FoldBack<'T, 'Error, 'State> folder (result: Result<'T, 'Error>) (state: 'State) =
match result with
| Error _ -> state
| Ok x -> folder x state

let Exists predicate result =
match result with
| Error _ -> false
| Ok x -> predicate x

let ForAll predicate result =
match result with
| Error _ -> true
| Ok x -> predicate x

let Contains value result =
match result with
| Error _ -> false
| Ok v -> v = value

let Iterate action result =
match result with
| Error _ -> ()
| Ok x -> action x

let ToArray result =
match result with
| Error _ -> [||]
| Ok x -> [| x |]

let ToList result =
match result with
| Error _ -> []
| Ok x -> [ x ]

let ToSeq result =
match result with
| Error _ -> []
| Ok x -> [ x ]

let ToOption result =
match result with
| Error _ -> None
| Ok x -> Some x

let ToValueOption result =
match result with
| Error _ -> ValueNone
| Ok x -> ValueSome x
23 changes: 23 additions & 0 deletions tests/WebSharper.Collections.Tests/Map.fs
Original file line number Diff line number Diff line change
Expand Up @@ -206,4 +206,27 @@ let Tests =
equal (Map.values m |> Array.ofSeq) [| 5; 9 |]
equal (m.Values |> Array.ofSeq) [| 5; 9 |]
}

Test "Map.change" {
let m = Map.ofList [(1, 5); (2, 9)]

equal (m |> Map.change 0 (Option.map ((+) 1)) |> Map.toArray) [| 1, 5; 2, 9 |] // nothing
equal (m |> Map.change 1 (Option.map ((+) 1)) |> Map.toArray) [| 1, 6; 2, 9 |] // changing
equal (m |> Map.change 1 (fun x -> if x = Some 5 then None else x) |> Map.toArray) [| 2, 9 |] // removing
equal (m |> Map.change 0 (fun _ -> Some 0) |> Map.toArray) [| 0, 0; 1, 5; 2, 9 |] // adding
}

Test "Map.minKeyValue" {
let m = Map.ofList [(1, 5); (2, 9)]

equal (Map.minKeyValue m) (1, 5)
raises (Map.minKeyValue Map.empty)
}

Test "Map.maxKeyValue" {
let m = Map.ofList [(1, 5); (2, 9)]

equal (Map.maxKeyValue m) (2, 9)
raises (Map.maxKeyValue Map.empty)
}
}
97 changes: 88 additions & 9 deletions tests/WebSharper.Tests/Result.fs
Original file line number Diff line number Diff line change
Expand Up @@ -26,35 +26,114 @@ open WebSharper.Testing
[<JavaScript>]
let Tests =

TestCategory "Result" {
let r = Ok 3
let r2 = Error "e"

TestCategory "Result" {
Test "Contruct" {
let r = Ok 3
let r2 = Error "e"
equal (match r with Ok x -> x | _ -> 0) 3
equal (match r2 with Error x -> x | _ -> "") "e"
}

Test "Map" {
let r = Ok 3
let r2 = Error "e"
equal (r |> Result.map (fun x -> x + 1)) (Ok 4)
equal (r2 |> Result.map (fun x -> x + 1)) (Error "e")
}

Test "MapError" {
let r = Ok 3
let r2 = Error "e"
equal (r |> Result.mapError (fun x -> x + "r")) (Ok 3)
equal (r2 |> Result.mapError (fun x -> x + "r")) (Error "er")
}

Test "Bind" {
let r = Ok 3
let r2 = Error "e"
equal (r |> Result.bind (fun x -> Ok (x + 1))) (Ok 4)
equal (r |> Result.bind (fun x -> Error "err")) (Error "err")
equal (r2 |> Result.bind (fun x -> Ok())) (Error "e")
}

Test "IsOk" {
isTrue (r |> Result.isOk)
isFalse (r2 |> Result.isOk)
}

Test "IsError" {
isFalse (r |> Result.isError)
isTrue (r2 |> Result.isError)
}

Test "DefaultValue" {
equal (r |> Result.defaultValue 4) 3
equal (r2 |> Result.defaultValue 4) 4
}

Test "DefaultWith" {
equal (r |> Result.defaultWith (fun e -> if e = "e" then 4 else 5)) 3
equal (r2 |> Result.defaultWith (fun e -> if e = "e" then 4 else 5)) 4
}

Test "Count" {
equal (r |> Result.count) 1
equal (r2 |> Result.count) 0
}

Test "Fold" {
equal (r |> Result.fold (fun s x -> 10*s + x) 1) 13
equal (r2 |> Result.fold (fun s x -> 10*s + x) 1) 1
}

Test "FoldBack" {
equal (1 |> Result.foldBack (fun x s -> 10*x + s) r) 31
equal (1 |> Result.foldBack (fun x s -> 10*x + s) r2) 1
}

Test "Exists" {
isTrue (r |> Result.exists (fun x -> x > 0))
isFalse (r |> Result.exists (fun x -> x < 0))
isFalse (r2 |> Result.exists (fun x -> x > 0))
}

Test "ForAll" {
isTrue (r |> Result.forall (fun x -> x > 0))
isFalse (r |> Result.forall (fun x -> x < 0))
isTrue (r2 |> Result.forall (fun x -> x > 0))
}

Test "Contains" {
isTrue (r |> Result.contains 3)
isFalse (r |> Result.contains 4)
isFalse (r2 |> Result.contains 3)
}

Test "Iterate" {
let s = ref 1
r |> Result.iter (fun x -> s.Value <- s.Value + x)
equal s.Value 4
r2 |> Result.iter (fun x -> s.Value <- s.Value + x)
equal s.Value 4
}

Test "ToArray" {
equal (r |> Result.toArray) [| 3 |]
equal (r2 |> Result.toArray) [| |]
}

Test "ToList" {
equal (r |> Result.toList) [ 3 ]
equal (r2 |> Result.toList) [ ]
}

//Test "ToSeq" {
// equal (r |> Result.toSeq |> Seq.toArray) [| 3 |]
// equal (r2 |> Result.toSeq |> Seq.toArray) [| |]
//}

Test "ToOption" {
equal (r |> Result.toOption) (Some 3)
equal (r2 |> Result.toOption) None
}

Test "ToValueOption" {
equal (r |> Result.toValueOption) (ValueSome 3)
equal (r2 |> Result.toValueOption) ValueNone
}
}

0 comments on commit 534026e

Please sign in to comment.