From e459714d8e28c982784b6998f9bdfcc33a3e3af8 Mon Sep 17 00:00:00 2001 From: AnNyiiik Date: Sat, 4 May 2024 10:50:38 +0300 Subject: [PATCH 1/7] added solution --- HW_8/HW_8.sln | 25 +++++++++++++++++++++++++ HW_8/HW_8/HW_8.fsproj | 12 ++++++++++++ HW_8/HW_8/Library.fs | 6 ++++++ 3 files changed, 43 insertions(+) create mode 100644 HW_8/HW_8.sln create mode 100644 HW_8/HW_8/HW_8.fsproj create mode 100644 HW_8/HW_8/Library.fs diff --git a/HW_8/HW_8.sln b/HW_8/HW_8.sln new file mode 100644 index 0000000..72a35d7 --- /dev/null +++ b/HW_8/HW_8.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 25.0.1706.10 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "HW_8", "HW_8\HW_8.fsproj", "{48D9A1DC-EBF2-4F90-9ACE-B494AB3B6B43}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {48D9A1DC-EBF2-4F90-9ACE-B494AB3B6B43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {48D9A1DC-EBF2-4F90-9ACE-B494AB3B6B43}.Debug|Any CPU.Build.0 = Debug|Any CPU + {48D9A1DC-EBF2-4F90-9ACE-B494AB3B6B43}.Release|Any CPU.ActiveCfg = Release|Any CPU + {48D9A1DC-EBF2-4F90-9ACE-B494AB3B6B43}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {255CB2D0-EEC2-4344-B412-20DC11F6D1EC} + EndGlobalSection +EndGlobal diff --git a/HW_8/HW_8/HW_8.fsproj b/HW_8/HW_8/HW_8.fsproj new file mode 100644 index 0000000..728a968 --- /dev/null +++ b/HW_8/HW_8/HW_8.fsproj @@ -0,0 +1,12 @@ + + + + net7.0 + true + + + + + + + diff --git a/HW_8/HW_8/Library.fs b/HW_8/HW_8/Library.fs new file mode 100644 index 0000000..9383fe8 --- /dev/null +++ b/HW_8/HW_8/Library.fs @@ -0,0 +1,6 @@ +namespace HW_8 + +module Say = + let hello name = + printfn "Hello %s" name + From 868d023dc3090819a06e001d966215061612363f Mon Sep 17 00:00:00 2001 From: AnNyiiik Date: Wed, 29 May 2024 15:53:40 +0300 Subject: [PATCH 2/7] added solution on lazy --- HW_7/HW_7.Tests/HW_7.Tests.fsproj | 37 ++++++++++++++++++++ HW_7/HW_7.Tests/Program.fs | 5 +++ HW_7/HW_7.Tests/UnitTestLazy.fs | 56 +++++++++++++++++++++++++++++++ HW_7/HW_7.sln | 31 +++++++++++++++++ HW_7/HW_7/HW_7.fsproj | 12 +++++++ HW_7/HW_7/Lazy.fs | 44 ++++++++++++++++++++++++ 6 files changed, 185 insertions(+) create mode 100644 HW_7/HW_7.Tests/HW_7.Tests.fsproj create mode 100644 HW_7/HW_7.Tests/Program.fs create mode 100644 HW_7/HW_7.Tests/UnitTestLazy.fs create mode 100644 HW_7/HW_7.sln create mode 100644 HW_7/HW_7/HW_7.fsproj create mode 100644 HW_7/HW_7/Lazy.fs diff --git a/HW_7/HW_7.Tests/HW_7.Tests.fsproj b/HW_7/HW_7.Tests/HW_7.Tests.fsproj new file mode 100644 index 0000000..d880b26 --- /dev/null +++ b/HW_7/HW_7.Tests/HW_7.Tests.fsproj @@ -0,0 +1,37 @@ + + + + net7.0 + + false + false + true + + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive +all + + runtime; build; native; contentfiles; analyzers; buildtransitive +all + + + + + + + + + + + + + diff --git a/HW_7/HW_7.Tests/Program.fs b/HW_7/HW_7.Tests/Program.fs new file mode 100644 index 0000000..5da7e48 --- /dev/null +++ b/HW_7/HW_7.Tests/Program.fs @@ -0,0 +1,5 @@ +module Program = + + [] + let main _ = 0 + diff --git a/HW_7/HW_7.Tests/UnitTestLazy.fs b/HW_7/HW_7.Tests/UnitTestLazy.fs new file mode 100644 index 0000000..e97781c --- /dev/null +++ b/HW_7/HW_7.Tests/UnitTestLazy.fs @@ -0,0 +1,56 @@ +module HW_7.Tests + +open NUnit.Framework +open FsUnit +open System +open System.Threading +open Lazy + +let random = Random() + +let ``suppliers single thread`` = + seq { + TestCaseData(fun () -> (+) (random.Next(10)) <| random.Next(10)) + TestCaseData(fun () -> (*) (random.Next(10)) <| random.Next(100)) + } + +let ``lazy multithread`` = + seq { + TestCaseData(fun supplier -> LazyWithLock (supplier) :> ILazy) + TestCaseData(fun supplier -> LazyLockFree (supplier) :> ILazy) + } + +[] +let``SingleThreaded works correctly with value``(supplier : (unit -> int)) = + let lazyItem = LazySingleThread(supplier) :> ILazy + + let firstCalculation = lazyItem.Get() + let secondCalculation = lazyItem.Get() + let thirdCalculation = lazyItem.Get() + + firstCalculation |> should equal secondCalculation + firstCalculation |> should equal thirdCalculation + +[] +let MultithreadTestFunction (createLazy: (unit -> 'a) -> ILazy<'a>) = + + let manualResetEvent = new ManualResetEvent(false) + + let counter = ref 0 + + let supplier () = + manualResetEvent.WaitOne() |> ignore + Interlocked.Increment counter |> ignore + obj () + + manualResetEvent.Reset() |> ignore + let lazyItem = createLazy supplier + + let tasks = Seq.init 100 (fun _ -> async { return lazyItem.Get()}) + let tasksToRun = tasks |> Async.Parallel + manualResetEvent.Set() + let results = tasksToRun |> Async.RunSynchronously + + let compare_item = Seq.item 0 results + + results |> Seq.forall (fun item -> obj.ReferenceEquals(item, compare_item)) |> should equal true \ No newline at end of file diff --git a/HW_7/HW_7.sln b/HW_7/HW_7.sln new file mode 100644 index 0000000..1666a3a --- /dev/null +++ b/HW_7/HW_7.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 25.0.1706.10 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "HW_7", "HW_7\HW_7.fsproj", "{F1711BB9-3559-4373-BB05-72A984B3BD48}" +EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "HW_7.Tests", "HW_7.Tests\HW_7.Tests.fsproj", "{C60BE216-43E7-43FC-A2BF-76B1DACF93E4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F1711BB9-3559-4373-BB05-72A984B3BD48}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F1711BB9-3559-4373-BB05-72A984B3BD48}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F1711BB9-3559-4373-BB05-72A984B3BD48}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F1711BB9-3559-4373-BB05-72A984B3BD48}.Release|Any CPU.Build.0 = Release|Any CPU + {C60BE216-43E7-43FC-A2BF-76B1DACF93E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C60BE216-43E7-43FC-A2BF-76B1DACF93E4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C60BE216-43E7-43FC-A2BF-76B1DACF93E4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C60BE216-43E7-43FC-A2BF-76B1DACF93E4}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {5D56F09D-1A84-4AF5-B13B-08FBC8A8E199} + EndGlobalSection +EndGlobal diff --git a/HW_7/HW_7/HW_7.fsproj b/HW_7/HW_7/HW_7.fsproj new file mode 100644 index 0000000..1b8c425 --- /dev/null +++ b/HW_7/HW_7/HW_7.fsproj @@ -0,0 +1,12 @@ + + + + net7.0 + true + + + + + + + diff --git a/HW_7/HW_7/Lazy.fs b/HW_7/HW_7/Lazy.fs new file mode 100644 index 0000000..5308f49 --- /dev/null +++ b/HW_7/HW_7/Lazy.fs @@ -0,0 +1,44 @@ +namespace HW_7 + +open System.Threading + +module Lazy = + + type ILazy<'a> = + abstract member Get: unit -> 'a + + type LazySingleThread<'a>(supplier: unit -> 'a) = + let mutable result = None + + interface ILazy<'a> with + member this.Get() = + match result with + | Some x -> x + | None -> + let value = supplier() + result <- Some (value) + value + + type LazyWithLock<'a>(supplier: unit -> 'a) = + let mutable result = None + let lockObject = obj() + + interface ILazy<'a> with + member this.Get() = + lock lockObject (fun () -> + match result with + | Some x -> x + | None -> + let value = supplier() + result <- Some (value) + value + ) + + type LazyLockFree<'a>(supplier: unit -> 'a) = + let mutable result = None + + interface ILazy<'a> with + member this.Get() = + match System.Threading.Interlocked.CompareExchange(&result, Some(supplier()), None) with + | Some value -> value + | None -> result.Value \ No newline at end of file From 162846ba2a39863e4ef8488d15f44e5ac31b31e9 Mon Sep 17 00:00:00 2001 From: AnNyiiik Date: Fri, 31 May 2024 11:41:14 +0300 Subject: [PATCH 3/7] added odd file --- HW_6/HW_6/RounderBuilder.fs | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 HW_6/HW_6/RounderBuilder.fs diff --git a/HW_6/HW_6/RounderBuilder.fs b/HW_6/HW_6/RounderBuilder.fs new file mode 100644 index 0000000..670dd40 --- /dev/null +++ b/HW_6/HW_6/RounderBuilder.fs @@ -0,0 +1,9 @@ +module Rounder + +open System + +type RounderBuilder(accuracy : int) = + member this.Bind(x : float, func) = + func (Math.Round(x, accuracy)) + + member this.Return(x : float) = Math.Round(x, accuracy) \ No newline at end of file From 9e18e833b352f29222c7ba4ea8d9872f9309e692 Mon Sep 17 00:00:00 2001 From: AnNyiiik Date: Fri, 31 May 2024 16:52:45 +0300 Subject: [PATCH 4/7] added crawler --- HW_7/HW_7.Tests/Program.fs | 3 +- HW_7/HW_7.Tests/UnitTestLazy.fs | 16 ++++++++- HW_7/HW_7/HW_7.fsproj | 1 + HW_7/HW_7/MiniCrawler.fs | 62 +++++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 HW_7/HW_7/MiniCrawler.fs diff --git a/HW_7/HW_7.Tests/Program.fs b/HW_7/HW_7.Tests/Program.fs index 5da7e48..0c4b1d7 100644 --- a/HW_7/HW_7.Tests/Program.fs +++ b/HW_7/HW_7.Tests/Program.fs @@ -1,5 +1,4 @@ module Program = [] - let main _ = 0 - + let main _ = 0 \ No newline at end of file diff --git a/HW_7/HW_7.Tests/UnitTestLazy.fs b/HW_7/HW_7.Tests/UnitTestLazy.fs index e97781c..0f7dac4 100644 --- a/HW_7/HW_7.Tests/UnitTestLazy.fs +++ b/HW_7/HW_7.Tests/UnitTestLazy.fs @@ -1,9 +1,11 @@ module HW_7.Tests +open System.Net open NUnit.Framework open FsUnit open System open System.Threading +open MiniCrawler open Lazy let random = Random() @@ -53,4 +55,16 @@ let MultithreadTestFunction (createLazy: (unit -> 'a) -> ILazy<'a>) = let compare_item = Seq.item 0 results - results |> Seq.forall (fun item -> obj.ReferenceEquals(item, compare_item)) |> should equal true \ No newline at end of file + results |> Seq.forall (fun item -> obj.ReferenceEquals(item, compare_item)) |> should equal true + +[] +let StandartTest () = + downloadAndPrintPageSize "https://my.spbu.ru/" + |> (Async.RunSynchronously) + |> Option.get + |> should equal "https://edu.spbu.ru/maps/map.html 107400" + +[] +let TestWithIncorrectUrl () = + (fun () -> downloadAndPrintPageSize "https://se.ma.su.ru/" |> Async.RunSynchronously |> ignore) + |> should throw typeof \ No newline at end of file diff --git a/HW_7/HW_7/HW_7.fsproj b/HW_7/HW_7/HW_7.fsproj index 1b8c425..e2551f0 100644 --- a/HW_7/HW_7/HW_7.fsproj +++ b/HW_7/HW_7/HW_7.fsproj @@ -7,6 +7,7 @@ + diff --git a/HW_7/HW_7/MiniCrawler.fs b/HW_7/HW_7/MiniCrawler.fs new file mode 100644 index 0000000..59bd3f8 --- /dev/null +++ b/HW_7/HW_7/MiniCrawler.fs @@ -0,0 +1,62 @@ +namespace HW_7 + +open System.IO +open System.Net +open System.Text.RegularExpressions +open System.Threading.Tasks + +module MiniCrawler = + + let downloadAndPrintPageSize (url: string) = + + let readPage (link : string) = + async { + let request = HttpWebRequest.Create(link) + use! response = request.AsyncGetResponse() + use reader = new StreamReader(response.GetResponseStream()) + let html = reader.ReadToEnd() + return html + } + + async { + try + let html = Async.RunSynchronously (readPage url) + + + let linkRegex = new Regex(" Seq.cast + |> Seq.map (fun m -> m.Groups.[1].Value) + + let! content = + links + |> Seq.map (fun link -> + async { + try + let! content = readPage link + return Some (String.concat " " [link; content.Length.ToString()]) + with + | :? WebException -> return None + } |> Async.StartAsTask) + |> Task.WhenAll + |> Async.AwaitTask + + let mutable result = "" + let mutable counter = 0 + + for content in content do + match content with + | Some string -> + if (counter = 0) then + result <- String.concat "" [result; string] + counter <- 1 + else + result <- String.concat "\n" [result; string] + | None -> () + return Some result + with + | :? WebException -> + raise (WebException "Incorrect url") + return None + } \ No newline at end of file From 11ce655c0ded3edfe9f9efe219e9590755a0bbbd Mon Sep 17 00:00:00 2001 From: AnNyiiik Date: Fri, 31 May 2024 21:33:58 +0300 Subject: [PATCH 5/7] added crawler --- HW_7/HW_7/MiniCrawler.fs | 90 ++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/HW_7/HW_7/MiniCrawler.fs b/HW_7/HW_7/MiniCrawler.fs index 59bd3f8..6749ee7 100644 --- a/HW_7/HW_7/MiniCrawler.fs +++ b/HW_7/HW_7/MiniCrawler.fs @@ -9,54 +9,54 @@ module MiniCrawler = let downloadAndPrintPageSize (url: string) = - let readPage (link : string) = - async { - let request = HttpWebRequest.Create(link) - use! response = request.AsyncGetResponse() - use reader = new StreamReader(response.GetResponseStream()) - let html = reader.ReadToEnd() - return html - } - + let readPage (link : string) = async { - try - let html = Async.RunSynchronously (readPage url) + let request = HttpWebRequest.Create(link) + use! response = request.AsyncGetResponse() + use reader = new StreamReader(response.GetResponseStream()) + let html = reader.ReadToEnd() + return html + } + + async { + try + let html = Async.RunSynchronously (readPage url) - let linkRegex = new Regex(" Seq.cast - |> Seq.map (fun m -> m.Groups.[1].Value) + let linkRegex = new Regex(" Seq.cast + |> Seq.map (fun m -> m.Groups.[1].Value) - let! content = - links - |> Seq.map (fun link -> - async { - try - let! content = readPage link - return Some (String.concat " " [link; content.Length.ToString()]) - with - | :? WebException -> return None - } |> Async.StartAsTask) - |> Task.WhenAll - |> Async.AwaitTask + let! content = + links + |> Seq.map (fun link -> + async { + try + let! content = readPage link + return Some (String.concat " " [link; content.Length.ToString()]) + with + | :? WebException -> return None + } |> Async.StartAsTask) + |> Task.WhenAll + |> Async.AwaitTask - let mutable result = "" - let mutable counter = 0 + let mutable result = "" + let mutable counter = 0 - for content in content do - match content with - | Some string -> - if (counter = 0) then - result <- String.concat "" [result; string] - counter <- 1 - else - result <- String.concat "\n" [result; string] - | None -> () - return Some result - with - | :? WebException -> - raise (WebException "Incorrect url") - return None - } \ No newline at end of file + for content in content do + match content with + | Some string -> + if (counter = 0) then + result <- String.concat "" [result; string] + counter <- 1 + else + result <- String.concat "\n" [result; string] + | None -> () + return Some result + with + | :? WebException -> + raise (WebException "Incorrect url") + return None + } \ No newline at end of file From 360257ebe32a645c6f61c3f0a243373de82c4a2a Mon Sep 17 00:00:00 2001 From: AnNyiiik Date: Fri, 31 May 2024 23:06:59 +0300 Subject: [PATCH 6/7] changed --- HW_7/HW_7/MiniCrawler.fs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/HW_7/HW_7/MiniCrawler.fs b/HW_7/HW_7/MiniCrawler.fs index 6749ee7..b65985c 100644 --- a/HW_7/HW_7/MiniCrawler.fs +++ b/HW_7/HW_7/MiniCrawler.fs @@ -1,7 +1,7 @@ namespace HW_7 open System.IO -open System.Net +open System.Net.Http open System.Text.RegularExpressions open System.Threading.Tasks @@ -9,14 +9,13 @@ module MiniCrawler = let downloadAndPrintPageSize (url: string) = - let readPage (link : string) = + let client = new HttpClient() + + let readPageAsync (link: string) = async { - let request = HttpWebRequest.Create(link) - use! response = request.AsyncGetResponse() - use reader = new StreamReader(response.GetResponseStream()) - let html = reader.ReadToEnd() - return html + } + async { try From d2fe79ba6db1ed735f6b7e565cadda4a86c14bef Mon Sep 17 00:00:00 2001 From: AnNyiiik Date: Sat, 1 Jun 2024 15:09:45 +0300 Subject: [PATCH 7/7] added mock object to crawler tests --- HW_6/HW_6/RounderBuilder.fs | 9 -- HW_7/HW_7.Tests/HW_7.Tests.fsproj | 5 +- HW_7/HW_7.Tests/UnitTestLazy.fs | 70 ---------------- HW_7/HW_7.Tests/UnitTests.fs | 134 ++++++++++++++++++++++++++++++ HW_7/HW_7/MiniCrawler.fs | 57 ++++++------- HW_8/HW_8.sln | 25 ------ HW_8/HW_8/HW_8.fsproj | 12 --- HW_8/HW_8/Library.fs | 6 -- 8 files changed, 162 insertions(+), 156 deletions(-) delete mode 100644 HW_6/HW_6/RounderBuilder.fs delete mode 100644 HW_7/HW_7.Tests/UnitTestLazy.fs create mode 100644 HW_7/HW_7.Tests/UnitTests.fs delete mode 100644 HW_8/HW_8.sln delete mode 100644 HW_8/HW_8/HW_8.fsproj delete mode 100644 HW_8/HW_8/Library.fs diff --git a/HW_6/HW_6/RounderBuilder.fs b/HW_6/HW_6/RounderBuilder.fs deleted file mode 100644 index 670dd40..0000000 --- a/HW_6/HW_6/RounderBuilder.fs +++ /dev/null @@ -1,9 +0,0 @@ -module Rounder - -open System - -type RounderBuilder(accuracy : int) = - member this.Bind(x : float, func) = - func (Math.Round(x, accuracy)) - - member this.Return(x : float) = Math.Round(x, accuracy) \ No newline at end of file diff --git a/HW_7/HW_7.Tests/HW_7.Tests.fsproj b/HW_7/HW_7.Tests/HW_7.Tests.fsproj index d880b26..dbeaf55 100644 --- a/HW_7/HW_7.Tests/HW_7.Tests.fsproj +++ b/HW_7/HW_7.Tests/HW_7.Tests.fsproj @@ -9,7 +9,7 @@ - + @@ -29,6 +29,9 @@ + + + diff --git a/HW_7/HW_7.Tests/UnitTestLazy.fs b/HW_7/HW_7.Tests/UnitTestLazy.fs deleted file mode 100644 index 0f7dac4..0000000 --- a/HW_7/HW_7.Tests/UnitTestLazy.fs +++ /dev/null @@ -1,70 +0,0 @@ -module HW_7.Tests - -open System.Net -open NUnit.Framework -open FsUnit -open System -open System.Threading -open MiniCrawler -open Lazy - -let random = Random() - -let ``suppliers single thread`` = - seq { - TestCaseData(fun () -> (+) (random.Next(10)) <| random.Next(10)) - TestCaseData(fun () -> (*) (random.Next(10)) <| random.Next(100)) - } - -let ``lazy multithread`` = - seq { - TestCaseData(fun supplier -> LazyWithLock (supplier) :> ILazy) - TestCaseData(fun supplier -> LazyLockFree (supplier) :> ILazy) - } - -[] -let``SingleThreaded works correctly with value``(supplier : (unit -> int)) = - let lazyItem = LazySingleThread(supplier) :> ILazy - - let firstCalculation = lazyItem.Get() - let secondCalculation = lazyItem.Get() - let thirdCalculation = lazyItem.Get() - - firstCalculation |> should equal secondCalculation - firstCalculation |> should equal thirdCalculation - -[] -let MultithreadTestFunction (createLazy: (unit -> 'a) -> ILazy<'a>) = - - let manualResetEvent = new ManualResetEvent(false) - - let counter = ref 0 - - let supplier () = - manualResetEvent.WaitOne() |> ignore - Interlocked.Increment counter |> ignore - obj () - - manualResetEvent.Reset() |> ignore - let lazyItem = createLazy supplier - - let tasks = Seq.init 100 (fun _ -> async { return lazyItem.Get()}) - let tasksToRun = tasks |> Async.Parallel - manualResetEvent.Set() - let results = tasksToRun |> Async.RunSynchronously - - let compare_item = Seq.item 0 results - - results |> Seq.forall (fun item -> obj.ReferenceEquals(item, compare_item)) |> should equal true - -[] -let StandartTest () = - downloadAndPrintPageSize "https://my.spbu.ru/" - |> (Async.RunSynchronously) - |> Option.get - |> should equal "https://edu.spbu.ru/maps/map.html 107400" - -[] -let TestWithIncorrectUrl () = - (fun () -> downloadAndPrintPageSize "https://se.ma.su.ru/" |> Async.RunSynchronously |> ignore) - |> should throw typeof \ No newline at end of file diff --git a/HW_7/HW_7.Tests/UnitTests.fs b/HW_7/HW_7.Tests/UnitTests.fs new file mode 100644 index 0000000..27c6d83 --- /dev/null +++ b/HW_7/HW_7.Tests/UnitTests.fs @@ -0,0 +1,134 @@ +namespace HW_7.Tests + +open System.Net.Http +open Moq +open NUnit.Framework +open FsUnit +open System.Net +open System +open System.Threading +open HW_7.Lazy +open HW_7.MiniCrawler + +module Tests = + + let random = Random() + + let ``suppliers single thread`` = + seq { + TestCaseData(fun () -> (+) (random.Next(10)) <| random.Next(10)) + TestCaseData(fun () -> (*) (random.Next(10)) <| random.Next(100)) + } + + let ``lazy multithread`` = + seq { + TestCaseData(fun supplier -> LazyWithLock (supplier) :> ILazy) + TestCaseData(fun supplier -> LazyLockFree (supplier) :> ILazy) + } + + [] + let``SingleThreaded works correctly with value``(supplier : (unit -> int)) = + let lazyItem = LazySingleThread(supplier) :> ILazy + + let firstCalculation = lazyItem.Get() + let secondCalculation = lazyItem.Get() + let thirdCalculation = lazyItem.Get() + + firstCalculation |> should equal secondCalculation + firstCalculation |> should equal thirdCalculation + + [] + let MultithreadTestFunction (createLazy: (unit -> 'a) -> ILazy<'a>) = + + let manualResetEvent = new ManualResetEvent(false) + + let counter = ref 0 + + let supplier () = + manualResetEvent.WaitOne() |> ignore + Interlocked.Increment counter |> ignore + obj () + + manualResetEvent.Reset() |> ignore + let lazyItem = createLazy supplier + + let tasks = Seq.init 100 (fun _ -> async { return lazyItem.Get()}) + let tasksToRun = tasks |> Async.Parallel + manualResetEvent.Set() + let results = tasksToRun |> Async.RunSynchronously + + let compare_item = Seq.item 0 results + + results |> Seq.forall (fun item -> obj.ReferenceEquals(item, compare_item)) |> should equal true + + [] + let ``case two links are correct`` () = + let mockHttp = new Mock() + mockHttp.Setup(fun c -> c.GetAsync(It.IsAny())).ReturnsAsync( + let response = new HttpResponseMessage(HttpStatusCode.OK) + response.Content <- new StringContent("Page 1Page 2") + response + ) |> ignore + + + mockHttp.Setup(fun c -> c.GetAsync("https://example.com/page1")).ReturnsAsync( + let response = new HttpResponseMessage(HttpStatusCode.OK) + response.Content <- new StringContent("Page 1 content") + response + ) |> ignore + + mockHttp.Setup(fun c -> c.GetAsync("https://example.com/page2")).ReturnsAsync( + let response = new HttpResponseMessage(HttpStatusCode.OK) + response.Content <- new StringContent("Page 2 content") + response + ) |> ignore + + + let result = Async.RunSynchronously (downloadAndPrintPageSize mockHttp.Object "https://example.com") + + match result with + | Some sizes -> + Assert.AreEqual(2, sizes.Length) + Assert.Contains(("https://example.com/page1", Some 14), sizes) + Assert.Contains(("https://example.com/page2", Some 14), sizes) + | None -> Assert.Fail("Expected Some result") + + [] + let ``case one link is incorrect`` () = + let mockHttp = new Mock() + mockHttp.Setup(fun c -> c.GetAsync(It.IsAny())).ReturnsAsync( + let response = new HttpResponseMessage(HttpStatusCode.OK) + response.Content <- new StringContent("Page 1Page 2") + response + ) |> ignore + + mockHttp.Setup(fun c -> c.GetAsync("https://site.com/page_correct")).ReturnsAsync( + let response = new HttpResponseMessage(HttpStatusCode.OK) + response.Content <- new StringContent("Page 1 content") + response + ) |> ignore + + mockHttp.Setup(fun c -> c.GetAsync("https://site.com/page_incorrect")).ReturnsAsync( + let response = new HttpResponseMessage(HttpStatusCode.NotFound) + response + ) |> ignore + + let result = Async.RunSynchronously (downloadAndPrintPageSize mockHttp.Object "https://site.com") + + match result with + | Some sizes -> + Assert.AreEqual(2, sizes.Length) + Assert.Contains(("https://site.com/page_correct", Some 14), sizes) + Assert.Contains(("https://site.com/page_incorrect", None), sizes) + | None -> Assert.Fail("Expected Some result") + + [] + let ``incorrect url should throw exeption`` () = + let mockHttp = new Mock() + mockHttp.Setup(fun c -> c.GetAsync("https://page_incorrect")).ReturnsAsync( + let response = new HttpResponseMessage(HttpStatusCode.NotFound) + response.Content <- new StringContent("Page 1 content") + response + ) |> ignore + (fun () -> downloadAndPrintPageSize mockHttp.Object "https://page_incorrect" |> Async.RunSynchronously |> ignore) + |> should throw typeof diff --git a/HW_7/HW_7/MiniCrawler.fs b/HW_7/HW_7/MiniCrawler.fs index b65985c..1a36830 100644 --- a/HW_7/HW_7/MiniCrawler.fs +++ b/HW_7/HW_7/MiniCrawler.fs @@ -1,28 +1,32 @@ namespace HW_7 -open System.IO -open System.Net.Http +open System.Net open System.Text.RegularExpressions open System.Threading.Tasks +open System.Net.Http module MiniCrawler = - - let downloadAndPrintPageSize (url: string) = - let client = new HttpClient() - - let readPageAsync (link: string) = - async { - - } + type IHttpClient = + abstract member GetAsync : string -> Task + + let readPage (client: IHttpClient) (link : string) = + + async { + let! response = client.GetAsync(link) |> Async.AwaitTask + response.EnsureSuccessStatusCode() |> ignore + let! content = response.Content.ReadAsStringAsync() |> Async.AwaitTask + return content + } + + let downloadAndPrintPageSize (client: IHttpClient) (url: string) = - async { try - let html = Async.RunSynchronously (readPage url) + let html = Async.RunSynchronously (readPage client url) - let linkRegex = new Regex(" Seq.cast @@ -33,27 +37,14 @@ module MiniCrawler = |> Seq.map (fun link -> async { try - let! content = readPage link - return Some (String.concat " " [link; content.Length.ToString()]) + let! content = readPage client link + return (link, Some content.Length) with - | :? WebException -> return None - } |> Async.StartAsTask) - |> Task.WhenAll - |> Async.AwaitTask - - let mutable result = "" - let mutable counter = 0 - - for content in content do - match content with - | Some string -> - if (counter = 0) then - result <- String.concat "" [result; string] - counter <- 1 - else - result <- String.concat "\n" [result; string] - | None -> () - return Some result + | :? HttpRequestException -> return (link, None) + }) + |> Async.Parallel + + return Some content with | :? WebException -> raise (WebException "Incorrect url") diff --git a/HW_8/HW_8.sln b/HW_8/HW_8.sln deleted file mode 100644 index 72a35d7..0000000 --- a/HW_8/HW_8.sln +++ /dev/null @@ -1,25 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 25.0.1706.10 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "HW_8", "HW_8\HW_8.fsproj", "{48D9A1DC-EBF2-4F90-9ACE-B494AB3B6B43}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {48D9A1DC-EBF2-4F90-9ACE-B494AB3B6B43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {48D9A1DC-EBF2-4F90-9ACE-B494AB3B6B43}.Debug|Any CPU.Build.0 = Debug|Any CPU - {48D9A1DC-EBF2-4F90-9ACE-B494AB3B6B43}.Release|Any CPU.ActiveCfg = Release|Any CPU - {48D9A1DC-EBF2-4F90-9ACE-B494AB3B6B43}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {255CB2D0-EEC2-4344-B412-20DC11F6D1EC} - EndGlobalSection -EndGlobal diff --git a/HW_8/HW_8/HW_8.fsproj b/HW_8/HW_8/HW_8.fsproj deleted file mode 100644 index 728a968..0000000 --- a/HW_8/HW_8/HW_8.fsproj +++ /dev/null @@ -1,12 +0,0 @@ - - - - net7.0 - true - - - - - - - diff --git a/HW_8/HW_8/Library.fs b/HW_8/HW_8/Library.fs deleted file mode 100644 index 9383fe8..0000000 --- a/HW_8/HW_8/Library.fs +++ /dev/null @@ -1,6 +0,0 @@ -namespace HW_8 - -module Say = - let hello name = - printfn "Hello %s" name -