diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 9fdbb19..b82a0d3 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -43,18 +43,6 @@ jobs: python-version: '3.12' - name: Setup Virtual Environment run: python -m venv .venv - - name: Setup Poetry Windows - if: matrix.os == 'windows-latest' - run: | - .\.venv\Scripts\python.exe -m pip install -U pip setuptools - .\.venv\Scripts\python.exe -m pip install poetry - .\.venv\Scripts\python.exe -m poetry install --no-root - - name: Setup Poetry Unix - if: matrix.os == 'ubuntu-latest' - run: | - ./.venv/bin/python -m pip install -U pip setuptools - ./.venv/bin/python -m pip install poetry - ./.venv/bin/python -m poetry install --no-root # BUILD - name: make script executable diff --git a/README.md b/README.md index 90c70f1..cbdf19e 100644 --- a/README.md +++ b/README.md @@ -103,10 +103,4 @@ On windows you can use the `setup.cmd` to run the following steps automatically! `py -m venv .venv` -4. Install [Poetry](https://python-poetry.org/) and dependencies - - 1. `.\.venv\Scripts\python.exe -m pip install -U pip setuptools` - 2. `.\.venv\Scripts\python.exe -m pip install poetry` - 3. `.\.venv\Scripts\python.exe -m poetry install --no-root` - Verify correct setup with `./build.cmd runtests` ✨ \ No newline at end of file diff --git a/poetry.lock b/poetry.lock deleted file mode 100644 index 5e4e520..0000000 --- a/poetry.lock +++ /dev/null @@ -1,174 +0,0 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. - -[[package]] -name = "certifi" -version = "2024.7.4" -description = "Python package for providing Mozilla's CA Bundle." -optional = false -python-versions = ">=3.6" -files = [ - {file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"}, - {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"}, -] - -[[package]] -name = "charset-normalizer" -version = "2.1.1" -description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -optional = false -python-versions = ">=3.6.0" -files = [ - {file = "charset-normalizer-2.1.1.tar.gz", hash = "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845"}, - {file = "charset_normalizer-2.1.1-py3-none-any.whl", hash = "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"}, -] - -[package.extras] -unicode-backport = ["unicodedata2"] - -[[package]] -name = "colorama" -version = "0.4.6" -description = "Cross-platform colored terminal text." -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -files = [ - {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, - {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, -] - -[[package]] -name = "exceptiongroup" -version = "1.2.2" -description = "Backport of PEP 654 (exception groups)" -optional = false -python-versions = ">=3.7" -files = [ - {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, - {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, -] - -[package.extras] -test = ["pytest (>=6)"] - -[[package]] -name = "idna" -version = "3.7" -description = "Internationalized Domain Names in Applications (IDNA)" -optional = false -python-versions = ">=3.5" -files = [ - {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, - {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, -] - -[[package]] -name = "iniconfig" -version = "2.0.0" -description = "brain-dead simple config-ini parsing" -optional = false -python-versions = ">=3.7" -files = [ - {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, - {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, -] - -[[package]] -name = "packaging" -version = "24.1" -description = "Core utilities for Python packages" -optional = false -python-versions = ">=3.8" -files = [ - {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, - {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, -] - -[[package]] -name = "pluggy" -version = "1.5.0" -description = "plugin and hook calling mechanisms for python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, - {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, -] - -[package.extras] -dev = ["pre-commit", "tox"] -testing = ["pytest", "pytest-benchmark"] - -[[package]] -name = "pytest" -version = "8.3.2" -description = "pytest: simple powerful testing with Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pytest-8.3.2-py3-none-any.whl", hash = "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5"}, - {file = "pytest-8.3.2.tar.gz", hash = "sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "sys_platform == \"win32\""} -exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} -iniconfig = "*" -packaging = "*" -pluggy = ">=1.5,<2" -tomli = {version = ">=1", markers = "python_version < \"3.11\""} - -[package.extras] -dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] - -[[package]] -name = "requests" -version = "2.28.1" -description = "Python HTTP for Humans." -optional = false -python-versions = ">=3.7, <4" -files = [ - {file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"}, - {file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"}, -] - -[package.dependencies] -certifi = ">=2017.4.17" -charset-normalizer = ">=2,<3" -idna = ">=2.5,<4" -urllib3 = ">=1.21.1,<1.27" - -[package.extras] -socks = ["PySocks (>=1.5.6,!=1.5.7)"] -use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] - -[[package]] -name = "tomli" -version = "2.0.1" -description = "A lil' TOML parser" -optional = false -python-versions = ">=3.7" -files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, -] - -[[package]] -name = "urllib3" -version = "1.26.19" -description = "HTTP library with thread-safe connection pooling, file post, and more." -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" -files = [ - {file = "urllib3-1.26.19-py2.py3-none-any.whl", hash = "sha256:37a0344459b199fce0e80b0d3569837ec6b6937435c5244e7fd73fa6006830f3"}, - {file = "urllib3-1.26.19.tar.gz", hash = "sha256:3e3d753a8618b86d7de333b4223005f68720bcd6a7d2bcb9fbd2229ec7c1e429"}, -] - -[package.extras] -brotli = ["brotli (==1.0.9)", "brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] -secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] -socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] - -[metadata] -lock-version = "2.0" -python-versions = "^3.10" -content-hash = "b71d5769d70eac536444eb6d8a3f12e57d59113029b8de56c9bf24e9a8598dc8" diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index 477645a..0000000 --- a/pyproject.toml +++ /dev/null @@ -1,19 +0,0 @@ -[tool.poetry] -name = "DynamicObj" -version = "3.0.0" -description = "Fable compatible library supporting Dynamic Objects including inheritance in functional style." -authors = ["Kevin Schneider", "WhiteBlackGoose", "Heinrich Lukas Weil", "Timo Muehlhaus", "Kevin Frey", "David Zimmer"] -maintainers = ["Heinrich Lukas Weil", "Timo Muehlhaus", "Kevin Schneider"] -readme = "README.md" -repository = "https://github.com/CSBiology/DynamicObj" -keywords = ["Dynamic Object", "Fable", "FSharp", "Javascript", "Python"] - -[tool.poetry.dependencies] -python = "^3.10" - -[tool.poetry.group.dev.dependencies] -pytest = "^8.1.1" - -[build-system] -requires = ["poetry-core"] -build-backend = "poetry.core.masonry.api" \ No newline at end of file diff --git a/src/DynamicObj/DynamicObj.fs b/src/DynamicObj/DynamicObj.fs index 8f6ac2f..ff77029 100644 --- a/src/DynamicObj/DynamicObj.fs +++ b/src/DynamicObj/DynamicObj.fs @@ -21,11 +21,8 @@ type DynamicObj() = /// Gets property value member this.TryGetValue name = // first check the Properties collection for member - match properties.TryGetValue name with - | true,value -> Some value - // Next check for Public properties via Reflection - | _ -> ReflectionUtils.tryGetPropertyValue this name - + this.TryGetPropertyInfo(name) + |> Option.map (fun pi -> pi.GetValue(this)) member this.GetValue (name) = this.TryGetValue(name).Value @@ -39,12 +36,43 @@ type DynamicObj() = | :? 'a -> o :?> 'a |> Some | _ -> None + + member this.TryGetStaticPropertyInfo name : PropertyHelper option = + ReflectionUtils.tryGetStaticPropertyInfo this name + + member this.TryGetDynamicPropertyInfo name : PropertyHelper option = + #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT + FableJS.tryGetDynamicPropertyHelper this name + #endif + #if FABLE_COMPILER_PYTHON + FablePy.tryGetDynamicPropertyHelper this name + #endif + #if !FABLE_COMPILER + match properties.TryGetValue name with + | true,_ -> + Some { + Name = name + IsStatic = false + IsDynamic = true + IsMutable = true + IsImmutable = false + GetValue = fun o -> properties.[name] + SetValue = fun o v -> properties.[name] <- v + RemoveValue = fun o -> properties.Remove(name) |> ignore + } + | _ -> None + #endif + member this.TryGetPropertyInfo name : PropertyHelper option = + match this.TryGetStaticPropertyInfo name with + | Some pi -> Some pi + | None -> this.TryGetDynamicPropertyInfo name + /// Sets property value, creating a new property if none exists member this.SetValue (name,value) = // private // first check to see if there's a native property to set - match ReflectionUtils.tryGetPropertyInfo this name with + match this.TryGetStaticPropertyInfo name with | Some pi -> if pi.IsMutable then pi.SetValue this value @@ -65,11 +93,10 @@ type DynamicObj() = #endif member this.Remove name = - match ReflectionUtils.removeProperty this name with - | true -> true - // Maybe in map - | false -> properties.Remove(name) - + match this.TryGetPropertyInfo name with + | Some pi when pi.IsMutable -> pi.RemoveValue this + | Some _ -> failwith $"Cannot remove value for static, immutable property \"{name}\"" + | None -> () member this.GetPropertyHelpers (includeInstanceProperties) = #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT @@ -106,36 +133,30 @@ type DynamicObj() = /// Returns both instance and dynamic properties when passed true, only dynamic properties otherwise. /// Properties are returned as a key value pair of the member names and the boxed values member this.GetProperties includeInstanceProperties : seq> = - #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT - FableJS.getPropertyHelpers this - |> Seq.choose (fun pd -> - if includeInstanceProperties || pd.IsDynamic then - new KeyValuePair(pd.Name, pd.GetValue this) - |> Some + this.GetPropertyHelpers(includeInstanceProperties) + |> Seq.choose (fun kv -> + if kv.Name <> "properties" then + Some (KeyValuePair(kv.Name, kv.GetValue this)) else - None + None ) - #endif - #if FABLE_COMPILER_PYTHON - FablePy.getPropertyHelpers this - |> Seq.choose (fun pd -> - if includeInstanceProperties || pd.IsDynamic then - new KeyValuePair(pd.Name, pd.GetValue this) - |> Some - else - None + + /// Copies all dynamic members of the DynamicObj to the target DynamicObj. + member this.CopyDynamicPropertiesTo(target:#DynamicObj, ?overWrite) = + let overWrite = Option.defaultValue false overWrite + this.GetProperties(false) + |> Seq.iter (fun kv -> + match target.TryGetPropertyInfo kv.Key with + | Some pi when overWrite -> pi.SetValue target kv.Value + | Some _ -> failwith $"Property \"{kv.Key}\" already exists on target object and overWrite was not set to true." + | None -> target.SetValue(kv.Key,kv.Value) ) - #endif - #if !FABLE_COMPILER - seq [ - if includeInstanceProperties then - for prop in ReflectionUtils.getStaticProperties (this) -> - new KeyValuePair(prop.Name, prop.GetValue(this)) - for key in properties.Keys -> - new KeyValuePair(key, properties.[key]); - ] - #endif - |> Seq.filter (fun kv -> kv.Key.ToLower() <> "properties") + + /// Returns a new DynamicObj with only the dynamic properties of the original DynamicObj (sans instance properties). + member this.CopyDynamicProperties() = + let target = DynamicObj() + this.CopyDynamicPropertiesTo(target) + target member this.GetPropertyNames(includeInstanceProperties) = this.GetProperties(includeInstanceProperties) diff --git a/src/DynamicObj/FableJS.fs b/src/DynamicObj/FableJS.fs index b8a5e3e..e66b0ef 100644 --- a/src/DynamicObj/FableJS.fs +++ b/src/DynamicObj/FableJS.fs @@ -85,58 +85,68 @@ module FableJS = getPropertyValue o propName [] - let getPropertyDescriptor (o:obj) (propName:string) = + let tryGetPropertyDescriptor (o:obj) (propName:string) : obj option = jsNative - let getStaticPropertyDescriptor (o:obj) (propName:string) = - getPropertyDescriptor (getPrototype o) propName - + let tryGetStaticPropertyDescriptor (o:obj) (propName:string) : obj option= + tryGetPropertyDescriptor (getPrototype o) propName + + let tryStaticPropertyHelperFromDescriptor (pd:obj) (name:string) : PropertyHelper option = + let isWritable = PropertyDescriptor.isWritable pd + if PropertyDescriptor.isFunction pd then + None + else + { + Name = name + IsStatic = true + IsDynamic = false + IsMutable = isWritable + IsImmutable = not isWritable + GetValue = createGetter name + SetValue = createSetter name + RemoveValue = createRemover name true + } + |> Some + + let tryGetStaticPropertyHelper (o:obj) (propName:string) : PropertyHelper option = + tryGetStaticPropertyDescriptor o propName + |> Option.bind (fun pd -> tryStaticPropertyHelperFromDescriptor pd propName) + let getStaticPropertyHelpers (o:obj) : PropertyHelper [] = getStaticPropertyNames o - |> Array.choose (fun n -> - let pd = getStaticPropertyDescriptor o n - if PropertyDescriptor.isFunction pd then - None - else - let isWritable = PropertyDescriptor.isWritable pd - { - Name = n - IsStatic = true - IsDynamic = false - IsMutable = isWritable - IsImmutable = not isWritable - GetValue = createGetter n - SetValue = createSetter n - RemoveValue = createRemover n true - } - |> Some - ) + |> Array.choose (tryGetStaticPropertyHelper o) + + let tryGetDynamicPropertyDescriptor (o:obj) (propName:string) : obj option = + tryGetPropertyDescriptor o propName let transpiledPropertyRegex = "^[a-zA-Z]+@[0-9]+$" let isTranspiledPropertyHelper (propertyName : string) = System.Text.RegularExpressions.Regex.IsMatch(propertyName, transpiledPropertyRegex) + let tryDynamicPropertyHelperFromDescriptor (pd:obj) (name:string) : PropertyHelper option = + if PropertyDescriptor.isFunction pd || isTranspiledPropertyHelper name then + None + else + { + Name = name + IsStatic = false + IsDynamic = true + IsMutable = true + IsImmutable = false + GetValue = createGetter name + SetValue = createSetter name + RemoveValue = createRemover name false + } + |> Some + + let tryGetDynamicPropertyHelper (o:obj) (propName:string) : PropertyHelper option = + tryGetDynamicPropertyDescriptor o propName + |> Option.bind (fun pd -> tryDynamicPropertyHelperFromDescriptor pd propName) + let getDynamicPropertyHelpers (o:obj) : PropertyHelper [] = getOwnPropertyNames o - |> Array.choose (fun n -> - let pd = getPropertyDescriptor o n - if PropertyDescriptor.isFunction pd || isTranspiledPropertyHelper n then - None - else - let isWritable = PropertyDescriptor.isWritable pd - { - Name = n - IsStatic = false - IsDynamic = true - IsMutable = isWritable - IsImmutable = not isWritable - GetValue = createGetter n - SetValue = createSetter n - RemoveValue = createRemover n false - } - |> Some - ) + |> Array.choose (tryGetDynamicPropertyHelper o) let getPropertyHelpers (o:obj) = getDynamicPropertyHelpers o diff --git a/src/DynamicObj/FablePy.fs b/src/DynamicObj/FablePy.fs index 0e43cca..1c84f8c 100644 --- a/src/DynamicObj/FablePy.fs +++ b/src/DynamicObj/FablePy.fs @@ -115,7 +115,7 @@ module FablePy = - [] + [] let getMemberObject (o:obj) (propName:string) = nativeOnly diff --git a/src/DynamicObj/ReflectionUtils.fs b/src/DynamicObj/ReflectionUtils.fs index fdddbaa..b709947 100644 --- a/src/DynamicObj/ReflectionUtils.fs +++ b/src/DynamicObj/ReflectionUtils.fs @@ -24,20 +24,20 @@ module ReflectionUtils = #endif /// Try to get the PropertyInfo by name using reflection - let tryGetPropertyInfo (o:obj) (propName:string) = + let tryGetStaticPropertyInfo (o:obj) (propName:string) = #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT - FableJS.getPropertyHelpers o + FableJS.tryGetStaticPropertyHelper o propName #endif #if FABLE_COMPILER_PYTHON - FablePy.getPropertyHelpers o + FablePy.tryGetStaticPropertyHelper o propName #endif #if !FABLE_COMPILER - getStaticProperties (o) + getStaticProperties (o) + |> Array.tryFind (fun n -> n.Name = propName) #endif - |> Array.tryFind (fun n -> n.Name = propName) let trySetPropertyValue (o:obj) (propName:string) (value:obj) = - match tryGetPropertyInfo o propName with + match tryGetStaticPropertyInfo o propName with | Some property when property.IsMutable -> property.SetValue o value true @@ -45,7 +45,7 @@ module ReflectionUtils = let tryGetPropertyValue (o:obj) (propName:string) = try - match tryGetPropertyInfo o propName with + match tryGetStaticPropertyInfo o propName with | Some v -> Some (v.GetValue(o)) | None -> None with @@ -65,7 +65,7 @@ module ReflectionUtils = let removeProperty (o:obj) (propName:string) = - match tryGetPropertyInfo o propName with + match tryGetStaticPropertyInfo o propName with | Some property when property.IsMutable -> property.RemoveValue(o) true diff --git a/tests/DynamicObject.Tests/DynamicObj.fs b/tests/DynamicObject.Tests/DynamicObj.fs index 7c180ab..c94cd19 100644 --- a/tests/DynamicObject.Tests/DynamicObj.fs +++ b/tests/DynamicObject.Tests/DynamicObj.fs @@ -269,9 +269,44 @@ let tests_print = testList "Print" [ Expect.isTrue print "Print failed for issue 14" ] +let tests_copyDynamicProperties = testList "CopyDynamicProperties" [ + testCase "NewObject" <| fun _ -> + let a = DynamicObj() + a.SetValue("a", 1) + a.SetValue("b", 2) + let b = a.CopyDynamicProperties() + Expect.equal a b "Values should be equal" + testCase "ExistingObject" <| fun _ -> + let a = DynamicObj() + a.SetValue("a", 1) + a.SetValue("b", 2) + let b = DynamicObj() + b.SetValue("c", 3) + a.CopyDynamicPropertiesTo(b) + Expect.equal (b.GetValue("a")) 1 "Value a should be copied" + Expect.equal (b.GetValue("b")) 2 "Value b should be copied" + Expect.equal (b.GetValue("c")) 3 "Value c should be unaffected" + testCase "NoOverwrite throws" <| fun _ -> + let a = DynamicObj() + a.SetValue("a", 1) + let b = DynamicObj() + b.SetValue("a", 3) + let f = fun () -> a.CopyDynamicPropertiesTo(b) + Expect.throws f "Should throw because property exists" + testCase "Overwrite" <| fun _ -> + let a = DynamicObj() + a.SetValue("a", 1) + let b = DynamicObj() + b.SetValue("a", 3) + Expect.notEqual a b "Values should not be equal before copying" + a.CopyDynamicPropertiesTo(b, true) + Expect.equal a b "Values should be equal" +] + let main = testList "DynamicObj" [ tests_set tests_remove tests_formatString tests_combine + tests_copyDynamicProperties ] \ No newline at end of file diff --git a/tests/DynamicObject.Tests/ReflectionUtils.fs b/tests/DynamicObject.Tests/ReflectionUtils.fs index 6667721..ef4644e 100644 --- a/tests/DynamicObject.Tests/ReflectionUtils.fs +++ b/tests/DynamicObject.Tests/ReflectionUtils.fs @@ -39,7 +39,7 @@ let tests_PropertyHelper = testList "PropertyHelper" [ testCase "TryGetPropertyInfo" <| fun _ -> let p = TestObject("1", "test") - let idOption = ReflectionUtils.tryGetPropertyInfo p "Id" + let idOption = ReflectionUtils.tryGetStaticPropertyInfo p "Id" let id = Expect.wantSome idOption "Should have immutable property" Expect.equal id.Name "Id" "Should have correct property" Expect.equal id.IsStatic true "Id should be static" @@ -47,7 +47,7 @@ let tests_PropertyHelper = testList "PropertyHelper" [ Expect.equal id.IsMutable false "Id should not be mutable" Expect.equal id.IsImmutable true "Id should be immutable" - let nameOption = ReflectionUtils.tryGetPropertyInfo p "Name" + let nameOption = ReflectionUtils.tryGetStaticPropertyInfo p "Name" let name = Expect.wantSome nameOption "Should have mutable property" Expect.equal name.Name "Name" "Should have correct property" Expect.equal name.IsStatic true "Name should be static" @@ -55,7 +55,7 @@ let tests_PropertyHelper = testList "PropertyHelper" [ Expect.equal name.IsMutable true "Name should be mutable" Expect.equal name.IsImmutable false "Name should not be immutable" - let nonExistingOption = ReflectionUtils.tryGetPropertyInfo p "NonExisting" + let nonExistingOption = ReflectionUtils.tryGetStaticPropertyInfo p "NonExisting" Expect.isNone nonExistingOption "Should not have property" ]