Skip to content
Draft
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
1 change: 1 addition & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
<PackageVersion Include="Fake.DotNet.Paket" Version="6.1.4" />
<PackageVersion Include="Fake.IO.FileSystem" Version="6.1.4" />
<PackageVersion Include="Fake.Tools.Git" Version="6.1.4" />
<PackageVersion Include="FSharp.Control.FusionTasks" Version="2.6.0" />
<PackageVersion Include="FSharp.Compiler.Service" Version="43.12.204" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.5.1" />
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="10.0.300" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
namespace FSharp.Control.R3.Tests.AsyncObservable

open System.Threading.Tasks
open global.FSharp.Control
open Microsoft.VisualStudio.TestTools.UnitTesting
open global.R3
Comment on lines +4 to +6
open FSharp.Control.R3
open FSharp.Control.R3.Async
open FSharp.Control.R3.Tests

[<TestClass>]
type AggregationCategoryTests () =
[<TestMethod>]
member _.``aggregate should match direct AggregateAsync`` () : Task = task {
let source = TestHelpers.createObservable [| 1; 2; 3 |]
let expected =
ObservableExtensions.AggregateAsync (source, 0, (fun acc x -> acc + x), TestHelpers.cancellationToken)
let! expectedValue = expected
let! actual = source |> Observable.aggregate 0 (fun acc x -> acc + x)
Assert.AreEqual (expectedValue, actual, "Async aggregate must match direct AggregateAsync result.")
}

[<TestMethod>]
member _.``length should count values`` () : Task = task {
let source = TestHelpers.createObservable [| 1; 2; 3; 4 |]
let! actual = source |> Observable.length
Assert.AreEqual (4, actual, "length must return emitted value count.")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
namespace FSharp.Control.R3.Tests.AsyncObservable

open System.Threading.Tasks
open global.FSharp.Control
open Microsoft.VisualStudio.TestTools.UnitTesting
open global.R3
Comment on lines +4 to +6
open FSharp.Control.R3
open FSharp.Control.R3.Async
open FSharp.Control.R3.Tests

[<TestClass>]
type AllSelectionCategoryTests () =
[<TestMethod>]
member _.``all should match direct AllAsync`` () : Task = task {
let source = TestHelpers.createObservable [| 2; 4; 6 |]
let expected =
ObservableExtensions.AllAsync (source, (fun x -> x % 2 = 0), TestHelpers.cancellationToken)
let! expectedValue = expected
let! actual = source |> Observable.all (fun x -> x % 2 = 0)
Assert.AreEqual (expectedValue, actual, "Async all must match direct AllAsync result.")
}

[<TestMethod>]
member _.``existsAsync should detect available values`` () : Task = task {
let source = TestHelpers.createObservable [| 1 |]
let! actual = source |> Observable.existsAsync
Assert.IsTrue (actual, "existsAsync must return true for non-empty sequence.")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
namespace FSharp.Control.R3.Tests.AsyncObservable

open System.Threading.Tasks
open global.FSharp.Control
open Microsoft.VisualStudio.TestTools.UnitTesting
open global.R3
Comment on lines +4 to +6
open FSharp.Control.R3
open FSharp.Control.R3.Async
open FSharp.Control.R3.Tests

[<TestClass>]
type ConversionCategoryTests () =
[<TestMethod>]
member _.``toArray should return all values`` () : Task = task {
let source = TestHelpers.createObservable [| 1; 2; 3 |]
let! actual = source |> Observable.toArray
CollectionAssert.AreEqual ([| 1; 2; 3 |], actual, "toArray must return all source values.")
}

[<TestMethod>]
member _.``toList should return all values as list`` () : Task = task {
let source = TestHelpers.createObservable [| 1; 2; 3 |]
let! actual = source |> Observable.toList
CollectionAssert.AreEqual ([| 1; 2; 3 |], actual |> List.toArray, "toList must return all source values in order.")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace FSharp.Control.R3.Tests.AsyncObservable

open System.Threading.Tasks
open global.FSharp.Control
open Microsoft.VisualStudio.TestTools.UnitTesting
open global.R3
Comment on lines +4 to +6
open FSharp.Control.R3
open FSharp.Control.R3.Async
open FSharp.Control.R3.Tests

[<TestClass>]
type SingleElementCategoryTests () =
[<TestMethod>]
member _.``firstAsync should return first value`` () : Task = task {
let source = TestHelpers.createObservable [| 9; 8 |]
let! actual = source |> Observable.firstAsync
Assert.AreEqual (9, actual, "firstAsync must return the first emitted value.")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
namespace FSharp.Control.R3.Tests.AsyncObservable

open System.Threading.Tasks
open Microsoft.VisualStudio.TestTools.UnitTesting
open R3
open FSharp.Control.R3
open FSharp.Control.R3.Async
open FSharp.Control.R3.Tests

[<TestClass>]
type TransformationCategoryTests () =
[<TestMethod>]
member _.``mapAsync should match direct SelectAwait`` () : Task = task {
let options = ProcessingOptions.Default
let source = TestHelpers.createObservable [| 1; 2; 3 |]
let! expected =
ObservableExtensions.SelectAwait (
source,
(fun x (_ : System.Threading.CancellationToken) -> ValueTask.FromResult (x + 1)),
options.AwaitOperation,
options.ConfigureAwait,
options.CancelOnCompleted,
options.MaxConcurrent
)
|> TestHelpers.toArrayTask

let! actual =
source
|> Observable.mapAsync options (fun x -> async { return x + 1 })
|> TestHelpers.toArrayTask

CollectionAssert.AreEqual (expected, actual, "Async mapAsync must match direct SelectAwait behavior.")
}

[<TestMethod>]
member _.``iter should invoke action for each value`` () : Task = task {
let source = TestHelpers.createObservable [| 1; 2; 3 |]
let mutable sum = 0
do! source |> Observable.iter (fun x -> sum <- sum + x)
Assert.AreEqual (6, sum, "iter must invoke action for each emitted value.")
}

[<TestMethod>]
member _.``iterAsync should await async action for each value`` () : Task = task {
let options = ProcessingOptions.Default
let source = TestHelpers.createObservable [| 1; 2; 3 |]
let mutable sum = 0
do!
source
|> Observable.iterAsync options (fun x -> async { sum <- sum + x })
Assert.AreEqual (6, sum, "iterAsync must apply asynchronous action to every value.")
}

[<TestMethod>]
member _.``ofAsync should emit computation result`` () : Task = task {
let! actual =
Observable.ofAsync (async { return 7 })
|> TestHelpers.toArrayTask

CollectionAssert.AreEqual ([| 7 |], actual, "ofAsync must emit the async computation result.")
}
53 changes: 0 additions & 53 deletions tests/FSharp.Control.R3.Tests/BuilderTests.fs

This file was deleted.

8 changes: 6 additions & 2 deletions tests/FSharp.Control.R3.Tests/FSharp.Control.R3.Tests.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@
</PropertyGroup>

<ItemGroup>
<Compile Include="BuilderTests.fs" />
<Compile Include="ObservableTests.fs" />
<Compile Include="TestHelpers.fs" />
<Compile Include="Observable/*.fs" />
<Compile Include="AsyncObservable/*.fs" />
<Compile Include="TaskObservable/*.fs" />
<Compile Include="ProcessingOptionsTests.fs" />
Comment on lines +8 to +12
Comment on lines +8 to +12
</ItemGroup>

<ItemGroup>
<PackageReference Include="altcover" />
<PackageReference Include="FSharp.Control.FusionTasks" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="MSTest.TestAdapter" />
<PackageReference Include="MSTest.TestFramework" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
namespace FSharp.Control.R3.Tests.Observable

open System
open System.Threading.Tasks
open Microsoft.VisualStudio.TestTools.UnitTesting
open R3
open FSharp.Control.R3
open FSharp.Control.R3.Tests

[<TestClass>]
type AggregationCategoryTests () =
[<TestMethod>]
member _.``concat should append second sequence`` () : Task = task {
let first = TestHelpers.createObservable [| 1; 2 |]
let second = TestHelpers.createObservable [| 3; 4 |]
let! actual = Observable.concat first second |> TestHelpers.toArrayTask
CollectionAssert.AreEqual ([| 1; 2; 3; 4 |], actual, "concat must append second observable after first completes.")
}

[<TestMethod>]
member _.``merge should match direct R3 merge`` () : Task = task {
let source1 = TestHelpers.createObservable [| 1; 2 |]
let source2 = TestHelpers.createObservable [| 10; 20 |]
let! expected =
ObservableExtensions.Merge (source1, source2)
|> TestHelpers.toArrayTask
let! actual =
Observable.merge (source1, source2)
|> TestHelpers.toArrayTask
CollectionAssert.AreEqual (expected, actual, "merge wrapper must match direct R3 merge output.")
}

[<TestMethod>]
member _.``catch should continue with fallback observable`` () : Task = task {
use subject = new Subject<int> ()
let recovered =
subject
|> Observable.catch (fun (_ : exn) -> Observable.singleton 99)
let pending = TestHelpers.toArrayTask recovered
subject.OnNext 1
subject.OnCompleted (Result.Failure (Exception ("boom")))
let! actual = pending
CollectionAssert.AreEqual ([| 1; 99 |], actual, "catch must append fallback values after source error.")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
namespace FSharp.Control.R3.Tests.Observable

open System
open System.Threading.Tasks
open Microsoft.VisualStudio.TestTools.UnitTesting
open R3
open FSharp.Control.R3
open FSharp.Control.R3.Tests

[<TestClass>]
type AllSelectionCategoryTests () =
[<TestMethod>]
member _.``where should keep matching values`` () : Task = task {
let source = TestHelpers.createObservable [| 1; 2; 3; 4 |]
let! actual =
source
|> Observable.where (fun x -> x > 2)
|> TestHelpers.toArrayTask
CollectionAssert.AreEqual ([| 3; 4 |], actual, "where must keep values matching the predicate.")
}

[<TestMethod>]
member _.``filter should keep matching values`` () : Task = task {
let source = TestHelpers.createObservable [| 1; 2; 3; 4 |]
let! actual =
source
|> Observable.filter (fun x -> x % 2 = 0)
|> TestHelpers.toArrayTask
CollectionAssert.AreEqual ([| 2; 4 |], actual, "filter must keep only matching elements.")
}

[<TestMethod>]
member _.``choose should keep only Some values`` () : Task = task {
let source = TestHelpers.createObservable [| 1; 2; 3; 4 |]
let! actual =
source
|> FSharp.Control.R3.Observable.OptionExtensions.Observable.choose (fun x -> if x % 2 = 0 then Some (x * 10) else None)
|> TestHelpers.toArrayTask
CollectionAssert.AreEqual ([| 20; 40 |], actual, "choose must emit only mapped values from Some results.")
}

[<TestMethod>]
member _.``distinct should remove duplicate values`` () : Task = task {
let source = TestHelpers.createObservable [| 1; 1; 2; 2; 3 |]
let! actual = source |> Observable.distinct |> TestHelpers.toArrayTask
CollectionAssert.AreEqual ([| 1; 2; 3 |], actual, "distinct must emit unique values in encounter order.")
}

[<TestMethod>]
member _.``chunkBySize should split by fixed size`` () : Task = task {
let source = TestHelpers.createObservable [| 1; 2; 3; 4; 5 |]
let! actual =
source
|> Observable.chunkBySize 2
|> TestHelpers.toArrayTask
let chunks = actual |> Array.map Seq.toArray
Assert.AreEqual (3, chunks.Length, "chunkBySize should produce expected number of chunks.")
CollectionAssert.AreEqual ([| 1; 2 |], chunks[0], "First chunk should contain first two items.")
CollectionAssert.AreEqual ([| 3; 4 |], chunks[1], "Second chunk should contain next two items.")
CollectionAssert.AreEqual ([| 5 |], chunks[2], "Third chunk should contain the remaining item.")
}

[<TestMethod>]
member _.``chunkBy ChunkCount should match chunkBySize`` () : Task = task {
let source = TestHelpers.createObservable [| 1; 2; 3; 4 |]
let! expectedChunks =
source
|> Observable.chunkBySize 2
|> TestHelpers.toArrayTask
let! actualChunks =
source
|> Observable.chunkBy (ChunkCount 2)
|> TestHelpers.toArrayTask
let expected = expectedChunks |> Array.map Seq.toArray
let actual = actualChunks |> Array.map Seq.toArray
Assert.AreEqual (expected.Length, actual.Length, "chunkBy ChunkCount must produce same chunk count as chunkBySize.")
CollectionAssert.AreEqual (expected[0], actual[0], "First chunk must match chunkBySize output.")
CollectionAssert.AreEqual (expected[1], actual[1], "Second chunk must match chunkBySize output.")
}

[<TestMethod>]
member _.``skip should skip leading values`` () : Task = task {
let source = TestHelpers.createObservable [| 1; 2; 3; 4 |]
let! actual = source |> Observable.skip 2 |> TestHelpers.toArrayTask
CollectionAssert.AreEqual ([| 3; 4 |], actual, "skip must ignore the configured number of leading values.")
}

[<TestMethod>]
member _.``take should keep leading values`` () : Task = task {
let source = TestHelpers.createObservable [| 1; 2; 3; 4 |]
let! actual = source |> Observable.take 2 |> TestHelpers.toArrayTask
CollectionAssert.AreEqual ([| 1; 2 |], actual, "take must emit only the configured number of leading values.")
}
Loading
Loading