From bbc013dc5a9787e47af993c6dd798fbe2aca7fee Mon Sep 17 00:00:00 2001 From: omaus Date: Wed, 21 Feb 2024 18:27:13 +0100 Subject: [PATCH 01/11] Add ErrorMessage for IParam collections --- src/ARCExpect/ErrorMessage.fs | 39 +++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/ARCExpect/ErrorMessage.fs b/src/ARCExpect/ErrorMessage.fs index 504200c..35f693b 100644 --- a/src/ARCExpect/ErrorMessage.fs +++ b/src/ARCExpect/ErrorMessage.fs @@ -85,6 +85,45 @@ type ErrorMessage = str.AppendFormat(" > line '{0}'", line) |> ignore | None -> () + match Param.tryGetValueOfCvParamAttr "Position" iParam with + | Some position -> + str.AppendFormat(" > position '{0}'", position) |> ignore + | None -> () + str.ToString() + + + static member ofIParamCollection error iParamCollection = + + let iParam = Seq.head iParamCollection + + let str = new StringBuilder() + str.AppendFormat("['{0}', ..] {1}\n", Param.getCvName iParam, error) |> ignore + + match Param.tryGetValueOfCvParamAttr "FilePath" iParam with + | Some path -> + str.AppendFormat(" > filePath '{0}'\n", path) |> ignore + | None -> () + + match Param.tryGetValueOfCvParamAttr "Worksheet" iParam with + | Some sheet -> + str.AppendFormat(" > sheet '{0}'", sheet) |> ignore + | None -> () + + match Param.tryGetValueOfCvParamAttr "Row" iParam with + | Some row -> + str.AppendFormat(" > row '{0}'", row) |> ignore + | None -> () + + match Param.tryGetValueOfCvParamAttr "Column" iParam with + | Some column -> + str.AppendFormat(" > column '{0}'", column) |> ignore + | None -> () + + match Param.tryGetValueOfCvParamAttr "Line" iParam with + | Some line -> + str.AppendFormat(" > line '{0}'", line) |> ignore + | None -> () + match Param.tryGetValueOfCvParamAttr "Position" iParam with | Some position -> str.AppendFormat(" > position '{0}'", position) |> ignore From 1250e91a0f51d832d1fbf681057e9c21bf1f9d61 Mon Sep 17 00:00:00 2001 From: omaus Date: Wed, 21 Feb 2024 18:27:57 +0100 Subject: [PATCH 02/11] Add `forAll` function to validate IParam collections Closes #72. --- src/ARCExpect/ValidationFunctions.fs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/ARCExpect/ValidationFunctions.fs b/src/ARCExpect/ValidationFunctions.fs index 641702e..88b27a4 100644 --- a/src/ARCExpect/ValidationFunctions.fs +++ b/src/ARCExpect/ValidationFunctions.fs @@ -134,7 +134,7 @@ module Validate = |> Expecto.Tests.failtestNoStackf "%s" /// - /// Validates if the given Param is contained in the given collection át least once. + /// Validates if the given Param is contained in the given collection at least once. /// /// the param expected to occur at least once in the given collection /// The param collection to validate @@ -152,6 +152,18 @@ module Validate = |> ErrorMessage.ofIParam $"does not exist" |> Expecto.Tests.failtestNoStackf "%s" + /// + /// Validates if all elements in the given IParam collection satisfy the projection function. + /// + /// A function that evaluates to true if the element satisfies the requirements. + /// The IParam collection to validate. + static member forAll (projection : #IParam -> bool) (paramCollection : #seq<#IParam>) = + match Seq.forall projection paramCollection with + | true -> () + | false -> + ErrorMessage.ofIParamCollection $"does not exist" paramCollection + |> Expecto.Tests.failtestNoStackf "%s" + /// /// Validates wether the given Param's value is an email that matches a pre-defined regex pattern ("^[^@\s]+@[^@\s]+\.[^@\s]+$") From bd4d2de49ef3f09fa68c475d47258ab05590e028 Mon Sep 17 00:00:00 2001 From: omaus Date: Wed, 21 Feb 2024 19:01:43 +0100 Subject: [PATCH 03/11] Add unit test for ErrorMessage (WIP) --- tests/ARCExpect.Tests/ARCExpect.Tests.fsproj | 1 + tests/ARCExpect.Tests/ErrorMessageTests.fs | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 tests/ARCExpect.Tests/ErrorMessageTests.fs diff --git a/tests/ARCExpect.Tests/ARCExpect.Tests.fsproj b/tests/ARCExpect.Tests/ARCExpect.Tests.fsproj index 61d6203..f5fefe8 100644 --- a/tests/ARCExpect.Tests/ARCExpect.Tests.fsproj +++ b/tests/ARCExpect.Tests/ARCExpect.Tests.fsproj @@ -11,6 +11,7 @@ + diff --git a/tests/ARCExpect.Tests/ErrorMessageTests.fs b/tests/ARCExpect.Tests/ErrorMessageTests.fs new file mode 100644 index 0000000..8733361 --- /dev/null +++ b/tests/ARCExpect.Tests/ErrorMessageTests.fs @@ -0,0 +1,19 @@ +module ErrorMessageTests + + +open Expecto +open ARCExpect +open ControlledVocabulary + + +let dummyIParam = CvParam("test:0", "testTerm", "test", ParamValue.Value "no val") +dummyIParam.AddAttribute(CvParam()) + + +[] +let ``ErrorMessage tests`` = + testList "ErrorMessage" [ + testList "ofIParamCollection" [ + testCase "resolves correctly" + ] + ] \ No newline at end of file From 722f808292db3ba5cf423534f6238c948c1ab21e Mon Sep 17 00:00:00 2001 From: omaus Date: Thu, 22 Feb 2024 18:40:43 +0100 Subject: [PATCH 04/11] Add unit test for new ErrorMessage function --- tests/ARCExpect.Tests/ErrorMessageTests.fs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/ARCExpect.Tests/ErrorMessageTests.fs b/tests/ARCExpect.Tests/ErrorMessageTests.fs index 8733361..0b61553 100644 --- a/tests/ARCExpect.Tests/ErrorMessageTests.fs +++ b/tests/ARCExpect.Tests/ErrorMessageTests.fs @@ -7,13 +7,15 @@ open ControlledVocabulary let dummyIParam = CvParam("test:0", "testTerm", "test", ParamValue.Value "no val") -dummyIParam.AddAttribute(CvParam()) +let dummyIParamColl = List.init 3 (fun _ -> dummyIParam) [] let ``ErrorMessage tests`` = testList "ErrorMessage" [ testList "ofIParamCollection" [ - testCase "resolves correctly" + testCase "resolves correctly" <| fun _ -> + let eMsg = ErrorMessage.ofIParamCollection "does not satisfy" dummyIParamColl + Expect.equal eMsg "['testTerm', ..] does not satisfy\n" "resolved incorrectly" ] ] \ No newline at end of file From ef46838c3d10823d969ef5eed878e1a11d8fcc33 Mon Sep 17 00:00:00 2001 From: omaus Date: Thu, 7 Mar 2024 15:36:58 +0100 Subject: [PATCH 05/11] Rename function to better match naming design See: https://nfdi4plants.github.io/arc-validate/ARCExpect/design.html --- src/ARCExpect/ValidationFunctions.fs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ARCExpect/ValidationFunctions.fs b/src/ARCExpect/ValidationFunctions.fs index 88b27a4..4268cd1 100644 --- a/src/ARCExpect/ValidationFunctions.fs +++ b/src/ARCExpect/ValidationFunctions.fs @@ -157,8 +157,8 @@ module Validate = /// /// A function that evaluates to true if the element satisfies the requirements. /// The IParam collection to validate. - static member forAll (projection : #IParam -> bool) (paramCollection : #seq<#IParam>) = - match Seq.forall projection paramCollection with + static member ParamsSatisfyPredicate (predicate : #IParam -> bool) (paramCollection : #seq<#IParam>) = + match Seq.forall predicate paramCollection with | true -> () | false -> ErrorMessage.ofIParamCollection $"does not exist" paramCollection From 51030b3815bc79a6f1172f360449e6f385353661 Mon Sep 17 00:00:00 2001 From: omaus Date: Thu, 7 Mar 2024 15:39:26 +0100 Subject: [PATCH 06/11] Update function to call first predicate failing param --- src/ARCExpect/ValidationFunctions.fs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/ARCExpect/ValidationFunctions.fs b/src/ARCExpect/ValidationFunctions.fs index 4268cd1..31387da 100644 --- a/src/ARCExpect/ValidationFunctions.fs +++ b/src/ARCExpect/ValidationFunctions.fs @@ -158,11 +158,16 @@ module Validate = /// A function that evaluates to true if the element satisfies the requirements. /// The IParam collection to validate. static member ParamsSatisfyPredicate (predicate : #IParam -> bool) (paramCollection : #seq<#IParam>) = - match Seq.forall predicate paramCollection with - | true -> () - | false -> - ErrorMessage.ofIParamCollection $"does not exist" paramCollection - |> Expecto.Tests.failtestNoStackf "%s" + use en = paramCollection.GetEnumerator() + let rec loop () = + match en.MoveNext() with + | true -> + if predicate en.Current |> not then + ErrorMessage.ofIParam $"does not satisfy predicate" en.Current + |> Expecto.Tests.failtestNoStackf "%s" + else loop () + | false -> () + loop () /// From b008d98dd8c9ef48ebb52771c4d6e44049e9c638 Mon Sep 17 00:00:00 2001 From: omaus Date: Thu, 7 Mar 2024 15:58:39 +0100 Subject: [PATCH 07/11] Rename function according to naming design See: https://nfdi4plants.github.io/arc-validate/ARCExpect/design.html --- src/ARCExpect/ValidationFunctions.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ARCExpect/ValidationFunctions.fs b/src/ARCExpect/ValidationFunctions.fs index 31387da..41ec959 100644 --- a/src/ARCExpect/ValidationFunctions.fs +++ b/src/ARCExpect/ValidationFunctions.fs @@ -157,7 +157,7 @@ module Validate = /// /// A function that evaluates to true if the element satisfies the requirements. /// The IParam collection to validate. - static member ParamsSatisfyPredicate (predicate : #IParam -> bool) (paramCollection : #seq<#IParam>) = + static member AllItemsSatisfyPredicate (predicate : #IParam -> bool) (paramCollection : #seq<#IParam>) = use en = paramCollection.GetEnumerator() let rec loop () = match en.MoveNext() with From bc3d4aaafa35c2bac31a9115dd25c11474f4da76 Mon Sep 17 00:00:00 2001 From: omaus Date: Thu, 7 Mar 2024 16:00:30 +0100 Subject: [PATCH 08/11] Update XML tags according to renaming --- src/ARCExpect/ValidationFunctions.fs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ARCExpect/ValidationFunctions.fs b/src/ARCExpect/ValidationFunctions.fs index 41ec959..b0e75cd 100644 --- a/src/ARCExpect/ValidationFunctions.fs +++ b/src/ARCExpect/ValidationFunctions.fs @@ -153,9 +153,9 @@ module Validate = |> Expecto.Tests.failtestNoStackf "%s" /// - /// Validates if all elements in the given IParam collection satisfy the projection function. + /// Validates if all elements in the given IParam collection satisfy the predicate function. /// - /// A function that evaluates to true if the element satisfies the requirements. + /// A function that evaluates to true if the element satisfies the requirements. /// The IParam collection to validate. static member AllItemsSatisfyPredicate (predicate : #IParam -> bool) (paramCollection : #seq<#IParam>) = use en = paramCollection.GetEnumerator() From 528155d1210386d7020c89194264f9750514d132 Mon Sep 17 00:00:00 2001 From: omaus Date: Fri, 8 Mar 2024 17:57:03 +0100 Subject: [PATCH 09/11] Let function failTest all unsatisfying items --- src/ARCExpect/ValidationFunctions.fs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ARCExpect/ValidationFunctions.fs b/src/ARCExpect/ValidationFunctions.fs index b0e75cd..aebf7db 100644 --- a/src/ARCExpect/ValidationFunctions.fs +++ b/src/ARCExpect/ValidationFunctions.fs @@ -165,6 +165,7 @@ module Validate = if predicate en.Current |> not then ErrorMessage.ofIParam $"does not satisfy predicate" en.Current |> Expecto.Tests.failtestNoStackf "%s" + loop () else loop () | false -> () loop () From 573dd083da73da64a0d7f6f088ee705cd54ada54 Mon Sep 17 00:00:00 2001 From: omaus Date: Mon, 11 Mar 2024 17:22:27 +0100 Subject: [PATCH 10/11] Update function to display all failing items at once --- arc-validate.sln | 5 +++- .../pride_prototype_v0.1.0.fsx | 29 +++++++++++++++++-- src/ARCExpect/ValidationFunctions.fs | 18 +++++++----- 3 files changed, 41 insertions(+), 11 deletions(-) diff --git a/arc-validate.sln b/arc-validate.sln index c7e06f6..578d24f 100644 --- a/arc-validate.sln +++ b/arc-validate.sln @@ -61,6 +61,9 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "demo_notebooks", "demo_notebooks", "{A83F65C9-925E-437C-A457-EF8B9C6B154D}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "qcPackage_prototypes", "qcPackage_prototypes", "{9B3B6E39-DB2F-4A91-944B-EFAAD961FCE7}" + ProjectSection(SolutionItems) = preProject + playgrounds\qcPackage_prototypes\pride_prototype_v0.1.0.fsx = playgrounds\qcPackage_prototypes\pride_prototype_v0.1.0.fsx + EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{DB01DF70-3713-4445-AC79-A09ECE093294}" EndProject @@ -68,7 +71,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "content", "content", "{588E EndProject Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharpConsole", "tests\FSharpConsole\FSharpConsole.fsproj", "{DE9F79F6-ABA2-4940-AEB6-D969AE752E6F}" EndProject -Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Common", "tests\Common\Common.fsproj", "{C41FAD1A-6E44-4C11-B915-CD928E0ED72B}" +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Common", "tests\Common\Common.fsproj", "{C41FAD1A-6E44-4C11-B915-CD928E0ED72B}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "arc-validate", "arc-validate", "{E6A037FA-C367-4C2A-9B87-2A04CA25D3C9}" EndProject diff --git a/playgrounds/qcPackage_prototypes/pride_prototype_v0.1.0.fsx b/playgrounds/qcPackage_prototypes/pride_prototype_v0.1.0.fsx index c5b1475..d111b87 100644 --- a/playgrounds/qcPackage_prototypes/pride_prototype_v0.1.0.fsx +++ b/playgrounds/qcPackage_prototypes/pride_prototype_v0.1.0.fsx @@ -50,9 +50,6 @@ let invFileTokens = |> Seq.concat |> Seq.map snd -Investigation.parseMetadataSheetsFromTokens() absoluteFilePaths |> List.concat |> Seq.iter (Param.getCvName >> printfn "%s") -Investigation.parseMetadataSheetsFromTokens() absoluteFilePaths |> List.concat |> Seq.iter (Param.getTerm >> printfn "%A") - let invFileTokensNoMdSecKeys = invFileTokens |> Seq.filter (Param.getValue >> (<>) Terms.StructuralTerms.metadataSectionKey.Name) @@ -78,6 +75,32 @@ let commis = |> Seq.filter (Param.getTerm >> (=) Terms.StructuralTerms.userComment) + +// Helper functions: + +type ParamCollection = + + static member AllItemsSatisfyPredicate (predicate : #IParam -> bool) (paramCollection : #seq<#IParam>) = + use en = paramCollection.GetEnumerator() + let rec loop failString = + match en.MoveNext() with + | true -> + if predicate en.Current |> not then + let em = ErrorMessage.ofIParam $"does not satisfy predicate" en.Current + loop $"{failString}\n{em}" + else loop failString + | false -> failString + let failString = loop "" + if String.isNullOrEmpty failString |> not then + Expecto.Tests.failtestNoStackf "%s" failString + + +let testl = Seq.take 5 invFileTokens |> List.ofSeq + +ParamCollection.AllItemsSatisfyPredicate (fun p -> p.Name = "Term Source Name") testl + + + // Validation Cases: let cases = diff --git a/src/ARCExpect/ValidationFunctions.fs b/src/ARCExpect/ValidationFunctions.fs index aebf7db..61f7e02 100644 --- a/src/ARCExpect/ValidationFunctions.fs +++ b/src/ARCExpect/ValidationFunctions.fs @@ -3,6 +3,9 @@ open ControlledVocabulary open ARCExpect open ARCTokenization.StructuralOntology +open FSharpAux + +FSharpx.Collections.Array.catOptions /// /// Top level API for performing validation. @@ -159,16 +162,17 @@ module Validate = /// The IParam collection to validate. static member AllItemsSatisfyPredicate (predicate : #IParam -> bool) (paramCollection : #seq<#IParam>) = use en = paramCollection.GetEnumerator() - let rec loop () = + let rec loop failString = match en.MoveNext() with | true -> if predicate en.Current |> not then - ErrorMessage.ofIParam $"does not satisfy predicate" en.Current - |> Expecto.Tests.failtestNoStackf "%s" - loop () - else loop () - | false -> () - loop () + let em = ErrorMessage.ofIParam $"does not satisfy predicate" en.Current + loop $"{failString}\n{em}" + else loop failString + | false -> failString + let failString = loop "" + if String.isNullOrEmpty failString |> not then + Expecto.Tests.failtestNoStackf "%s" failString /// From 9d464288e89dd6470f3f353609dacf00a6f75f73 Mon Sep 17 00:00:00 2001 From: omaus Date: Mon, 11 Mar 2024 17:26:47 +0100 Subject: [PATCH 11/11] Delete missed line --- src/ARCExpect/ValidationFunctions.fs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ARCExpect/ValidationFunctions.fs b/src/ARCExpect/ValidationFunctions.fs index 61f7e02..bd6efe9 100644 --- a/src/ARCExpect/ValidationFunctions.fs +++ b/src/ARCExpect/ValidationFunctions.fs @@ -5,7 +5,6 @@ open ARCExpect open ARCTokenization.StructuralOntology open FSharpAux -FSharpx.Collections.Array.catOptions /// /// Top level API for performing validation.