diff --git a/.gitignore b/.gitignore index c7ad1b0e..27151ea4 100644 --- a/.gitignore +++ b/.gitignore @@ -158,6 +158,9 @@ $RECYCLE.BIN/ # Exclude F# project specific directories and files # =================================================== +.idea/ +.vs/ + # NuGet Packages Directory packages/ @@ -179,3 +182,6 @@ paket-files build_PRIVATE.cmd .fake/build.fsx_* docs/tools/.fake/generate.fsx_* +/.idea +/.paket/paket.exe +/.paket/Paket.Restore.targets diff --git a/.paket/paket.bootstrapper.exe b/.paket/paket.bootstrapper.exe new file mode 100755 index 00000000..7d59edd8 Binary files /dev/null and b/.paket/paket.bootstrapper.exe differ diff --git a/.paket/paket.exe b/.paket/paket.exe old mode 100644 new mode 100755 index b98e000b..dd104efa Binary files a/.paket/paket.exe and b/.paket/paket.exe differ diff --git a/.travis.yml b/.travis.yml index 9b785a16..80244f11 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,8 @@ language: csharp +dist: trusty +sudo: true -sudo: false # use the new container-based Travis infrastructure +dotnet: 2.1.101 script: - ./build.sh \ No newline at end of file diff --git a/build.fsx b/build.fsx index fe00a73c..f0a561e9 100644 --- a/build.fsx +++ b/build.fsx @@ -44,7 +44,7 @@ let tags = "appsettings, YAML, F#, ResX, Ini, config" let solutionFile = "FSharp.Configuration" // Pattern specifying assemblies to be tested using NUnit -let testAssemblies = "tests/**/bin/Release/*Tests*.exe" +let testAssemblies = "tests/**/bin/Release/net461/*Tests*.exe" // Git configuration (used for publishing documentation in gh-pages branch) // The profile where the project is posted @@ -108,14 +108,32 @@ Target "CleanDocs" (fun _ -> // -------------------------------------------------------------------------------------- // Build library & test project +let mutable dotnetExePath = "dotnet" +let dotnetcliVersion = "2.1.101" + +Target "InstallDotNetCore" (fun _ -> + dotnetExePath <- DotNetCli.InstallDotNetSDK dotnetcliVersion + Environment.SetEnvironmentVariable("DOTNET_EXE_PATH", dotnetExePath) +) + Target "Build" (fun _ -> - !! (solutionFile + ".sln") - |> MSBuildRelease "" "Rebuild" - |> ignore + DotNetCli.Build (fun c -> + { c with + Project = "FSharp.Configuration.sln" + Configuration = "Release" + ToolPath = dotnetExePath }) + + CopyDir "bin/lib/net45" + "src/FSharp.Configuration/bin/Release/net45/" + (fun _ -> true) +) - !! (solutionFile + ".Tests.sln") - |> MSBuildRelease "" "Rebuild" - |> ignore +Target "BuildTests" (fun _ -> + DotNetCli.Build (fun c -> + { c with + Project = "FSharp.Configuration.Tests.sln" + Configuration = "Release" + ToolPath = dotnetExePath }) ) // -------------------------------------------------------------------------------------- @@ -139,7 +157,7 @@ Target "NuGet" (fun _ -> CleanDir nugetDocsDir CleanDir nugetlibDir - CopyDir nugetlibDir "bin" (fun file -> file.Contains "FSharp.Core." |> not) + CopyDir nugetlibDir "bin/lib/net45" (fun file -> file.Contains "FSharp.Core." |> not) CopyDir nugetDocsDir "./docs/output" allFiles NuGet (fun p -> @@ -263,7 +281,9 @@ Target "All" DoNothing "Clean" ==> "AssemblyInfo" + ==> "InstallDotNetCore" ==> "Build" + ==> "BuildTests" ==> "RunTests" =?> ("GenerateReferenceDocs",isLocalBuild && not isMono) =?> ("GenerateDocs",isLocalBuild && not isMono) diff --git a/fsc.props b/fsc.props new file mode 100644 index 00000000..9a15225d --- /dev/null +++ b/fsc.props @@ -0,0 +1,21 @@ + + + + + true + true + true + + + C:\Program Files (x86)\Microsoft SDKs\F#\10.1\Framework\v4.0 + fsc.exe + + + /Library/Frameworks/Mono.framework/Versions/Current/Commands + fsharpc + + + /usr/bin + fsharpc + + \ No newline at end of file diff --git a/netfx.props b/netfx.props new file mode 100644 index 00000000..91361f30 --- /dev/null +++ b/netfx.props @@ -0,0 +1,34 @@ + + + + + + + true + + + /Library/Frameworks/Mono.framework/Versions/Current/lib/mono + /usr/lib/mono + /usr/local/lib/mono + + + $(BaseFrameworkPathOverrideForMono)/4.5-api + $(BaseFrameworkPathOverrideForMono)/4.5.1-api + $(BaseFrameworkPathOverrideForMono)/4.5.2-api + $(BaseFrameworkPathOverrideForMono)/4.6-api + $(BaseFrameworkPathOverrideForMono)/4.6.1-api + $(BaseFrameworkPathOverrideForMono)/4.6.2-api + $(BaseFrameworkPathOverrideForMono)/4.7-api + $(BaseFrameworkPathOverrideForMono)/4.7.1-api + true + + + $(FrameworkPathOverride)/Facades;$(AssemblySearchPaths) + + + + + + + + \ No newline at end of file diff --git a/paket.dependencies b/paket.dependencies index 2a1f7c0e..2364431f 100644 --- a/paket.dependencies +++ b/paket.dependencies @@ -1,28 +1,29 @@ -source http://nuget.org/api/v2 -framework: >= net45 - -nuget SharpYaml -nuget FSharp.Core ~> 4.0.0 - -github fsprojects/FSharp.TypeProviders.SDK src/ProvidedTypes.fs -github fsprojects/FSharp.TypeProviders.SDK src/ProvidedTypes.fsi -github fsprojects/FSharp.TypeProviders.SDK src/ProvidedTypesTesting.fs group Build - framework: net45 + frameworks: netstandard2.0 source https://nuget.org/api/v2 - nuget FAKE + nuget FAKE ~> 4 nuget FSharp.Formatting nuget Octokit nuget NuGet.CommandLine nuget SourceLink.Fake + nuget FSharp.Core + nuget SharpYaml + nuget NetStandard.Library.NetFramework + nuget System.Runtime.Caching github fsharp/FAKE modules/Octokit/Octokit.fsx + github fsprojects/FSharp.TypeProviders.SDK src/ProvidedTypes.fsi + github fsprojects/FSharp.TypeProviders.SDK src/ProvidedTypes.fs + github fsprojects/FSharp.TypeProviders.SDK src/ProvidedTypesTesting.fs group Test - framework: net461 + frameworks: net461 source https://nuget.org/api/v2 nuget FSharp.Core redirects: force - nuget Expecto \ No newline at end of file + nuget Expecto + nuget SharpYaml + + github fsprojects/FSharp.TypeProviders.SDK fsc.props diff --git a/paket.lock b/paket.lock index 72f37b15..11a8596f 100644 --- a/paket.lock +++ b/paket.lock @@ -1,31 +1,38 @@ -RESTRICTION: >= net45 -NUGET - remote: http://www.nuget.org/api/v2 - FSharp.Core (4.0.0.1) - SharpYaml (1.6.2) -GITHUB - remote: fsprojects/FSharp.TypeProviders.SDK - src/ProvidedTypes.fs (f0c4a6300db313eb2616c4f792cd6ae68c255e56) - src/ProvidedTypes.fsi (f0c4a6300db313eb2616c4f792cd6ae68c255e56) - src/ProvidedTypesTesting.fs (f0c4a6300db313eb2616c4f792cd6ae68c255e56) + + GROUP Build -RESTRICTION: == net45 +RESTRICTION: == netstandard2.0 NUGET remote: https://www.nuget.org/api/v2 FAKE (4.64.12) FSharp.Compiler.Service (2.0.0.6) + FSharp.Core (4.3.4) FSharp.Formatting (2.14.4) FSharp.Compiler.Service (2.0.0.6) FSharpVSPowerTools.Core (>= 2.3 < 2.4) FSharpVSPowerTools.Core (2.3) FSharp.Compiler.Service (>= 2.0.0.3) + Microsoft.NETCore.Platforms (2.0.2) + NETStandard.Library (2.0.2) + Microsoft.NETCore.Platforms (>= 1.1) + NETStandard.Library.NETFramework (2.0.0-preview2-25405-01) NuGet.CommandLine (4.6.2) Octokit (0.29) + NETStandard.Library (>= 1.6) + SharpYaml (1.6.3) + NETStandard.Library (>= 1.6.1) + System.Reflection.TypeExtensions (>= 4.3) SourceLink.Fake (1.1) + System.Reflection.TypeExtensions (4.4) + System.Runtime.Caching (4.5.0-preview2-26406-04) GITHUB remote: fsharp/FAKE - modules/Octokit/Octokit.fsx (800579e69ce35b77345ee21923ddf117168067cd) + modules/Octokit/Octokit.fsx (b3961e973484a8dc61ee94af13fc6898d0bee705) Octokit (>= 0.20) + remote: fsprojects/FSharp.TypeProviders.SDK + src/ProvidedTypes.fs (f0c4a6300db313eb2616c4f792cd6ae68c255e56) + src/ProvidedTypes.fsi (f0c4a6300db313eb2616c4f792cd6ae68c255e56) + src/ProvidedTypesTesting.fs (f0c4a6300db313eb2616c4f792cd6ae68c255e56) GROUP Test RESTRICTION: == net461 NUGET @@ -35,5 +42,25 @@ NUGET Expecto (7.0.1) Argu (>= 5.1) Mono.Cecil (>= 0.10) - FSharp.Core (4.3.4) - redirects: force + FAKE (4.64.12) + FSharp.Core (4.2.3) + Microsoft.NETCore.App (2.0.7) + Microsoft.NETCore.Platforms (2.0.2) Mono.Cecil (0.10) + NETStandard.Library (2.0.2) + Microsoft.NETCore.Platforms (>= 1.1) + NETStandard.Library.NETFramework (2.0.0-preview2-25405-01) + Microsoft.NETCore.Platforms (>= 2.0.0-preview2-25405-01) + NETStandard.Library (>= 2.0.0-preview2-25401-01) + NuGet.CommandLine (4.6.2) + SharpYaml (1.6.3) + xunit.runner.console (2.3.1) +GITHUB + remote: fsprojects/FSharp.TypeProviders.SDK + fsc.props (f0c4a6300db313eb2616c4f792cd6ae68c255e56) + FAKE + FSharp.Core (>= 4.2.3 < 4.3) + Microsoft.NETCore.App + NetStandard.Library.NetFramework + Nuget.CommandLine + xunit.runner.console \ No newline at end of file diff --git a/src/FSharp.Configuration/AppSettingsProvider.fs b/src/FSharp.Configuration/AppSettingsProvider.fs index e5296743..e12edf92 100644 --- a/src/FSharp.Configuration/AppSettingsProvider.fs +++ b/src/FSharp.Configuration/AppSettingsProvider.fs @@ -1,167 +1,167 @@ module FSharp.Configuration.AppSettingsTypeProvider -#nowarn "57" - -open FSharp.Configuration.Helper -open ProviderImplementation.ProvidedTypes -open System -open System.Configuration -open System.Collections.Generic -open System.Globalization -open System.Web.Hosting -open System.Runtime.Caching - -let mutable private exePath = Map.empty -let setExeFilePath key filePath = exePath <- exePath.Add(key, filePath) - -let getConfig file = - let path = exePath - if path.ContainsKey(file) && System.IO.File.Exists(path.[file]) then - ConfigurationManager.OpenExeConfiguration path.[file] - else - if HostingEnvironment.IsHosted then - Web.Configuration.WebConfigurationManager.OpenWebConfiguration "~" - else ConfigurationManager.OpenExeConfiguration ConfigurationUserLevel.None - -let getConfigValue(file,key) = - let conf = getConfig file - match conf.AppSettings.Settings.[key] with - | null -> raise <| KeyNotFoundException (sprintf "Cannot find name %s in section of config file. (%s)" key conf.FilePath) - | settings -> settings.Value - -let setConfigValue(file, key, value) = - let config = getConfig file - config.AppSettings.Settings.[key].Value <- value - config.Save() - -let getConnectionString(file, key: string) = - match getConfig(file).ConnectionStrings.ConnectionStrings.[key] with - | null -> raise <| KeyNotFoundException (sprintf "Cannot find name %s in section of config file." key) - | section -> section.ConnectionString - -let setConnectionString(file, key: string, value) = - let config = getConfig file - config.ConnectionStrings.ConnectionStrings.[key].ConnectionString <- value - config.Save() - -let internal typedAppSettings (context: Context) = - let appSettings = erasedType thisAssembly rootNamespace "AppSettings" None - let cache = new MemoryCache("AppSettingProvider") - context.AddDisposable cache - - appSettings.DefineStaticParameters( - parameters = [ProvidedStaticParameter("configFileName", typeof)], - instantiationFunction = (fun typeName parameterValues -> - let value = lazy ( - let typedConnectionStrings (config: Configuration, filePath, configFileName) = - let typeDef = ProvidedTypeDefinition ("ConnectionStrings", Some typeof, hideObjectMethods = true) - typeDef.AddXmlDoc (sprintf "Represents the available connection strings from %s" configFileName) - let niceName = createNiceNameProvider() - let connectionStrings = config.ConnectionStrings.ConnectionStrings - for connectionString in connectionStrings do - let key = connectionString.Name - let name = niceName key - let prop = - ProvidedProperty( - name, - typeof, - getterCode = (fun _ -> <@@ getConnectionString(filePath, key) @@>), - setterCode = (fun args -> <@@ setConnectionString(filePath, key, %%args.[0]) @@>), - isStatic = true) - - prop.AddXmlDoc (sprintf "Returns the connection string from %s with name %s" configFileName name) - prop.AddDefinitionLocation(1,1,filePath) - typeDef.AddMember prop - typeDef - - match parameterValues with - | [| :? string as configFileName |] -> - let typeDef = erasedType thisAssembly rootNamespace typeName None - let niceName = createNiceNameProvider() - try - let filePath = findConfigFile context.ResolutionFolder configFileName - let fileMap = ExeConfigurationFileMap(ExeConfigFilename=filePath) - let config = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None) - let appSettings = config.AppSettings.Settings - - for key in appSettings.AllKeys do - let name = niceName key - let prop = - match (appSettings.Item key).Value with - | ValueParser.Uri _ -> - ProvidedProperty(name, typeof, - isStatic = true, - getterCode = (fun _ -> <@@ Uri (getConfigValue(filePath, key)) @@>), - setterCode = fun args -> <@@ setConfigValue(filePath, key, string (%%args.[0]: Uri)) @@>) - | ValueParser.Int _ -> - ProvidedProperty(name, typeof, - isStatic = true, - getterCode = (fun _ -> <@@ Int32.Parse (getConfigValue(filePath, key)) @@>), - setterCode = fun args -> <@@ setConfigValue(filePath, key, string (%%args.[0]: Int32)) @@>) - | ValueParser.Bool _ -> - ProvidedProperty(name, typeof, - isStatic = true, - getterCode = (fun _ -> <@@ Boolean.Parse (getConfigValue(filePath, key)) @@>), - setterCode = fun args -> <@@ setConfigValue(filePath, key, string (%%args.[0]: Boolean)) @@>) - | ValueParser.Float _ -> - ProvidedProperty(name, typeof, - isStatic = true, - getterCode = (fun _ -> <@@ Double.Parse (getConfigValue(filePath, key), NumberStyles.Any, CultureInfo.InvariantCulture) @@>), - setterCode = fun args -> <@@ setConfigValue(filePath, key, string (%%args.[0]: float)) @@>) - | ValueParser.TimeSpan _ -> - ProvidedProperty(name, typeof, - isStatic = true, - getterCode = (fun _ -> <@@ TimeSpan.Parse(getConfigValue(filePath, key), CultureInfo.InvariantCulture) @@>), - setterCode = fun args -> <@@ setConfigValue(filePath, key, string (%%args.[0]: TimeSpan)) @@>) - | ValueParser.DateTime _ -> - ProvidedProperty(name, typeof, - isStatic = true, - getterCode = (fun _ -> <@@ DateTime.Parse(getConfigValue(filePath, key), CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal) @@>), - setterCode = fun args -> <@@ setConfigValue(filePath, key, (%%args.[0]: DateTime).ToString("o")) @@>) - | ValueParser.Guid _ -> - ProvidedProperty(name, typeof, - isStatic = true, - getterCode = (fun _ -> <@@ Guid.Parse(getConfigValue(filePath, key)) @@>), - setterCode = fun args -> <@@ setConfigValue(filePath, key, (%%args.[0]: Guid).ToString("B")) @@>) - | _ -> - ProvidedProperty(name, typeof, - isStatic = true, - getterCode = (fun _ -> <@@ getConfigValue(filePath, key) @@>), - setterCode = fun args -> <@@ setConfigValue(filePath, key, %%args.[0]) @@>) - - prop.AddXmlDoc (sprintf "Returns the value from %s with key %s" configFileName key) - prop.AddDefinitionLocation(1, 1, filePath) - - typeDef.AddMember prop - - let executeSelector = - ProvidedMethod( - niceName "SelectExecutableFile", - [ ProvidedParameter ("pathOfExe", typeof) ], - typeof, - isStatic = true, - invokeCode = fun args -> <@@ setExeFilePath filePath %%args.[0] @@>) - - executeSelector.AddXmlDoc "Property to change the executable file that is read for configurations. This idea is that you can manage other executables also (e.g. from script)." - typeDef.AddMember executeSelector - - - let configFileNameProp = - ProvidedProperty( - niceName "ConfigFileName", - typeof, - isStatic = true, - getterCode = fun _ -> <@@ filePath @@>) - - configFileNameProp.AddXmlDoc "Returns the Filename" - typeDef.AddMember configFileNameProp - - let connectionStringTypeDefinition = typedConnectionStrings (config, filePath, configFileName) - typeDef.AddMember connectionStringTypeDefinition - - context.WatchFile filePath - typeDef - with _ -> typeDef - | x -> failwithf "unexpected parameter values %A" x) - cache.GetOrAdd (typeName, value))) - appSettings \ No newline at end of file +//#nowarn "57" +// +//open FSharp.Configuration.Helper +//open ProviderImplementation.ProvidedTypes +//open System +//open System.Configuration +//open System.Collections.Generic +//open System.Globalization +//open System.Web.Hosting +//open System.Runtime.Caching +// +//let mutable private exePath = Map.empty +//let setExeFilePath key filePath = exePath <- exePath.Add(key, filePath) +// +//let getConfig file = +// let path = exePath +// if path.ContainsKey(file) && System.IO.File.Exists(path.[file]) then +// ConfigurationManager.OpenExeConfiguration path.[file] +// else +// if HostingEnvironment.IsHosted then +// Web.Configuration.WebConfigurationManager.OpenWebConfiguration "~" +// else ConfigurationManager.OpenExeConfiguration ConfigurationUserLevel.None +// +//let getConfigValue(file,key) = +// let conf = getConfig file +// match conf.AppSettings.Settings.[key] with +// | null -> raise <| KeyNotFoundException (sprintf "Cannot find name %s in section of config file. (%s)" key conf.FilePath) +// | settings -> settings.Value +// +//let setConfigValue(file, key, value) = +// let config = getConfig file +// config.AppSettings.Settings.[key].Value <- value +// config.Save() +// +//let getConnectionString(file, key: string) = +// match getConfig(file).ConnectionStrings.ConnectionStrings.[key] with +// | null -> raise <| KeyNotFoundException (sprintf "Cannot find name %s in section of config file." key) +// | section -> section.ConnectionString +// +//let setConnectionString(file, key: string, value) = +// let config = getConfig file +// config.ConnectionStrings.ConnectionStrings.[key].ConnectionString <- value +// config.Save() +// +//let internal typedAppSettings (context: Context) = +// let appSettings = erasedType thisAssembly rootNamespace "AppSettings" None +// let cache = new MemoryCache("AppSettingProvider") +// context.AddDisposable cache +// +// appSettings.DefineStaticParameters( +// parameters = [ProvidedStaticParameter("configFileName", typeof)], +// instantiationFunction = (fun typeName parameterValues -> +// let value = lazy ( +// let typedConnectionStrings (config: Configuration, filePath, configFileName) = +// let typeDef = ProvidedTypeDefinition ("ConnectionStrings", Some typeof, hideObjectMethods = true) +// typeDef.AddXmlDoc (sprintf "Represents the available connection strings from %s" configFileName) +// let niceName = createNiceNameProvider() +// let connectionStrings = config.ConnectionStrings.ConnectionStrings +// for connectionString in connectionStrings do +// let key = connectionString.Name +// let name = niceName key +// let prop = +// ProvidedProperty( +// name, +// typeof, +// getterCode = (fun _ -> <@@ getConnectionString(filePath, key) @@>), +// setterCode = (fun args -> <@@ setConnectionString(filePath, key, %%args.[0]) @@>), +// isStatic = true) +// +// prop.AddXmlDoc (sprintf "Returns the connection string from %s with name %s" configFileName name) +// prop.AddDefinitionLocation(1,1,filePath) +// typeDef.AddMember prop +// typeDef +// +// match parameterValues with +// | [| :? string as configFileName |] -> +// let typeDef = erasedType thisAssembly rootNamespace typeName None +// let niceName = createNiceNameProvider() +// try +// let filePath = findConfigFile context.ResolutionFolder configFileName +// let fileMap = ExeConfigurationFileMap(ExeConfigFilename=filePath) +// let config = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None) +// let appSettings = config.AppSettings.Settings +// +// for key in appSettings.AllKeys do +// let name = niceName key +// let prop = +// match (appSettings.Item key).Value with +// | ValueParser.Uri _ -> +// ProvidedProperty(name, typeof, +// isStatic = true, +// getterCode = (fun _ -> <@@ Uri (getConfigValue(filePath, key)) @@>), +// setterCode = fun args -> <@@ setConfigValue(filePath, key, string (%%args.[0]: Uri)) @@>) +// | ValueParser.Int _ -> +// ProvidedProperty(name, typeof, +// isStatic = true, +// getterCode = (fun _ -> <@@ Int32.Parse (getConfigValue(filePath, key)) @@>), +// setterCode = fun args -> <@@ setConfigValue(filePath, key, string (%%args.[0]: Int32)) @@>) +// | ValueParser.Bool _ -> +// ProvidedProperty(name, typeof, +// isStatic = true, +// getterCode = (fun _ -> <@@ Boolean.Parse (getConfigValue(filePath, key)) @@>), +// setterCode = fun args -> <@@ setConfigValue(filePath, key, string (%%args.[0]: Boolean)) @@>) +// | ValueParser.Float _ -> +// ProvidedProperty(name, typeof, +// isStatic = true, +// getterCode = (fun _ -> <@@ Double.Parse (getConfigValue(filePath, key), NumberStyles.Any, CultureInfo.InvariantCulture) @@>), +// setterCode = fun args -> <@@ setConfigValue(filePath, key, string (%%args.[0]: float)) @@>) +// | ValueParser.TimeSpan _ -> +// ProvidedProperty(name, typeof, +// isStatic = true, +// getterCode = (fun _ -> <@@ TimeSpan.Parse(getConfigValue(filePath, key), CultureInfo.InvariantCulture) @@>), +// setterCode = fun args -> <@@ setConfigValue(filePath, key, string (%%args.[0]: TimeSpan)) @@>) +// | ValueParser.DateTime _ -> +// ProvidedProperty(name, typeof, +// isStatic = true, +// getterCode = (fun _ -> <@@ DateTime.Parse(getConfigValue(filePath, key), CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal) @@>), +// setterCode = fun args -> <@@ setConfigValue(filePath, key, (%%args.[0]: DateTime).ToString("o")) @@>) +// | ValueParser.Guid _ -> +// ProvidedProperty(name, typeof, +// isStatic = true, +// getterCode = (fun _ -> <@@ Guid.Parse(getConfigValue(filePath, key)) @@>), +// setterCode = fun args -> <@@ setConfigValue(filePath, key, (%%args.[0]: Guid).ToString("B")) @@>) +// | _ -> +// ProvidedProperty(name, typeof, +// isStatic = true, +// getterCode = (fun _ -> <@@ getConfigValue(filePath, key) @@>), +// setterCode = fun args -> <@@ setConfigValue(filePath, key, %%args.[0]) @@>) +// +// prop.AddXmlDoc (sprintf "Returns the value from %s with key %s" configFileName key) +// prop.AddDefinitionLocation(1, 1, filePath) +// +// typeDef.AddMember prop +// +// let executeSelector = +// ProvidedMethod( +// niceName "SelectExecutableFile", +// [ ProvidedParameter ("pathOfExe", typeof) ], +// typeof, +// isStatic = true, +// invokeCode = fun args -> <@@ setExeFilePath filePath %%args.[0] @@>) +// +// executeSelector.AddXmlDoc "Property to change the executable file that is read for configurations. This idea is that you can manage other executables also (e.g. from script)." +// typeDef.AddMember executeSelector +// +// +// let configFileNameProp = +// ProvidedProperty( +// niceName "ConfigFileName", +// typeof, +// isStatic = true, +// getterCode = fun _ -> <@@ filePath @@>) +// +// configFileNameProp.AddXmlDoc "Returns the Filename" +// typeDef.AddMember configFileNameProp +// +// let connectionStringTypeDefinition = typedConnectionStrings (config, filePath, configFileName) +// typeDef.AddMember connectionStringTypeDefinition +// +// context.WatchFile filePath +// typeDef +// with _ -> typeDef +// | x -> failwithf "unexpected parameter values %A" x) +// cache.GetOrAdd (typeName, value))) +// appSettings \ No newline at end of file diff --git a/src/FSharp.Configuration/ConfigTypeProvider.fs b/src/FSharp.Configuration/ConfigTypeProvider.fs index da91e8f9..782d5e59 100644 --- a/src/FSharp.Configuration/ConfigTypeProvider.fs +++ b/src/FSharp.Configuration/ConfigTypeProvider.fs @@ -11,10 +11,11 @@ type FSharpConfigurationProvider(cfg: TypeProviderConfig) as this = let context = new Context(this, cfg) do this.AddNamespace ( rootNamespace, - [ AppSettingsTypeProvider.typedAppSettings context - ResXProvider.typedResources context + [ //AppSettingsTypeProvider.typedAppSettings context + //ResXProvider.typedResources context YamlConfigTypeProvider.typedYamlConfig context - IniFileProvider.typedIniFile context ]) + //IniFileProvider.typedIniFile context + ]) do this.Disposing.Add (fun _ -> dispose context) end diff --git a/src/FSharp.Configuration/FSharp.Configuration.fsproj b/src/FSharp.Configuration/FSharp.Configuration.fsproj index 81112094..fee20b4b 100644 --- a/src/FSharp.Configuration/FSharp.Configuration.fsproj +++ b/src/FSharp.Configuration/FSharp.Configuration.fsproj @@ -1,69 +1,22 @@ - - - + - Debug - AnyCPU - 2.0 - 7e90d6ce-a10b-4858-a5bc-41df7250cbca - Library - FSharp.Configuration - FSharp.Configuration - v4.5 - FSharp.Configuration - - - - true - full - false - false - ..\..\bin\ - DEBUG;TRACE - 3 - - - Program - C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\devenv.exe - - - - - pdbonly - true - true - ..\..\bin - TRACE - 3 - ..\..\bin\FSharp.Configuration.XML + netstandard2.0 + - 11 + FSharp.Configuration + false - - - - $(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets - - - - - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets - - - - - - + True ProvidedTypes.fsi - + True ProvidedTypes.fs - + True ProvidedTypesTesting.fs @@ -74,16 +27,24 @@ - + - - - - - - - + + + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + - - - - - ..\..\packages\FSharp.Core\lib\net40\FSharp.Core.dll - True - True - - - - - - - - - ..\..\packages\SharpYaml\lib\net45\SharpYaml.dll - True - True - - - - + \ No newline at end of file diff --git a/src/FSharp.Configuration/IniFileProvider.fs b/src/FSharp.Configuration/IniFileProvider.fs index 333b06b5..38e96ef3 100644 --- a/src/FSharp.Configuration/IniFileProvider.fs +++ b/src/FSharp.Configuration/IniFileProvider.fs @@ -1,150 +1,152 @@ module FSharp.Configuration.IniFileProvider -open System -open System.IO - -module Parser = - open System.Text.RegularExpressions - - type Key = string - type Value = string - type Setting = { Key: Key; Value: Value } - type SectionName = string - type Section = { Name: SectionName; Settings: Setting list } - - type Stream = Stream of int * string list - - let (|Regex|_|) pattern = function - | Stream (n, line :: rest) -> - let m = Regex.Match (line, pattern) - if m.Success then - let values = [ for gr in m.Groups -> gr.Value ] - Some (values, Stream (n, rest)) - else None - | _ -> None - - let (|Comment|_|) = function - | Regex @"^\s*;.*" (_, s) -> Some s - | _ -> None - - let (|Header|_|) = function - | Regex @"\[\s*(\S+)\s*\]" ([_; name], s) -> Some (name, s) - | _ -> None - - let (|Setting|_|) = function - | Regex @"\s*(\S+)\s*=\s*([^;]*)" ([_; key; value], s) -> - Some ({ Key = key; Value = value }, s) - | _ -> None - - let (|Settings|_|) s = - let rec loop s settings = - match s with - | Setting (setting, s) -> loop s (setting :: settings) - | Comment s -> loop s settings - | _ -> (List.rev settings, s) - let settings, s = loop s [] - Some (settings, s) - - let rec (|Section|_|) = function - | Header (name, Settings (settings, s)) -> Some ({ Name = name; Settings = settings }, s) - | _ -> None - - let (|Sections|_|) s = - let rec loop s sections = - match s with - | Section (section, s) -> loop s (section :: sections) - | Comment s -> loop s sections - | _ -> (sections |> List.rev, s) - let sections, s = loop s [] - Some (sections, s) - - let streamOfLines lines = Stream (0, lines |> Seq.filter (not << String.IsNullOrWhiteSpace) |> List.ofSeq) - let streamOfFile path = File.ReadLines path |> streamOfLines - let parse path = - match streamOfFile path with - | Sections (sections, _) -> Choice1Of2 sections - | e -> Choice2Of2 e - -open ProviderImplementation.ProvidedTypes -open System.Globalization -open System.Runtime.Caching - -let getValue (iniFileName: string) (section: string) (key: string) = - match Parser.parse (Path.GetFileName iniFileName) with - | Choice1Of2 sections -> - maybe { - let! section = sections |> List.tryFind (fun s -> s.Name = section) - let! setting = section.Settings |> List.tryFind (fun s -> s.Key = key) - return setting.Value - } - | Choice2Of2 _ -> None - -let internal typedIniFile (context: Context) = - let iniFile = erasedType thisAssembly rootNamespace "IniFile" None - let cache = new MemoryCache(name = "IniFileProvider") - context.AddDisposable cache - - iniFile.DefineStaticParameters( - parameters = [ ProvidedStaticParameter ("configFileName", typeof) ], - instantiationFunction = (fun typeName parameterValues -> - let value = lazy ( - match parameterValues with - | [| :? string as iniFileName |] -> - let typeDef = erasedType thisAssembly rootNamespace typeName (Some true) - let niceName = createNiceNameProvider() - try - let filePath = findConfigFile context.ResolutionFolder iniFileName - match Parser.parse filePath with - | Choice1Of2 sections -> - for section in sections do - let sectionTy = ProvidedTypeDefinition(section.Name, Some typeof, hideObjectMethods = true) - for setting in section.Settings do - let sectionName = section.Name - let key = setting.Key - let prop = - match setting.Value with - | ValueParser.Int value -> ProvidedProperty(key, typeof, isStatic = true, getterCode = fun _ -> - <@@ - match getValue filePath sectionName key with - | Some v -> Int32.Parse v - | None -> value - @@>) - | ValueParser.Bool value -> ProvidedProperty(key, typeof, isStatic = true, getterCode = fun _ -> - <@@ - match getValue filePath sectionName key with - | Some v -> Boolean.Parse v - | None -> value - @@>) - | ValueParser.Float value -> ProvidedProperty(key, typeof, isStatic = true, getterCode = fun _ -> - <@@ - match getValue filePath sectionName key with - | Some v -> Double.Parse (v, NumberStyles.Any, CultureInfo.InvariantCulture) - | None -> value - @@>) - | value -> ProvidedProperty(key, typeof, isStatic = true, getterCode = fun _ -> - <@@ - match getValue filePath sectionName key with - | Some v -> v - | None -> value - @@>) - - prop.AddXmlDoc (sprintf "Returns the value from %s from section %s with key %s" iniFileName section.Name setting.Key) - prop.AddDefinitionLocation(1, 1, filePath) - sectionTy.AddMember prop - - typeDef.AddMember sectionTy - | Choice2Of2 e -> failwithf "%A" e - - let name = niceName "ConfigFileName" - let getValue = <@@ filePath @@> - let prop = ProvidedProperty(name, typeof, isStatic = true, getterCode = fun _ -> getValue) - - prop.AddXmlDoc "Returns the Filename" - - typeDef.AddMember prop - context.WatchFile filePath - typeDef - with _ -> typeDef - | x -> failwithf "unexpected parameter values %A" x) - cache.GetOrAdd (typeName, value))) - iniFile \ No newline at end of file +//open System +//open System.IO +// +//module Parser = +// open System.Text.RegularExpressions +// +// type Key = string +// type Value = string +// type Setting = { Key: Key; Value: Value } +// type SectionName = string +// type Section = { Name: SectionName; Settings: Setting list } +// +// type Stream = Stream of int * string list +// +// let (|Regex|_|) pattern = function +// | Stream (n, line :: rest) -> +// let m = Regex.Match (line, pattern) +// if m.Success then +// let values = [ for gr in m.Groups -> gr.Value ] +// Some (values, Stream (n, rest)) +// else None +// | _ -> None +// +// let (|Comment|_|) = function +// | Regex @"^\s*;.*" (_, s) -> Some s +// | _ -> None +// +// let (|Header|_|) = function +// | Regex @"\[\s*(\S+)\s*\]" ([_; name], s) -> Some (name, s) +// | _ -> None +// +// let (|Setting|_|) = function +// | Regex @"\s*(\S+)\s*=\s*([^;]*)" ([_; key; value], s) -> +// Some ({ Key = key; Value = value }, s) +// | _ -> None +// +// let (|Settings|_|) s = +// let rec loop s settings = +// match s with +// | Setting (setting, s) -> loop s (setting :: settings) +// | Comment s -> loop s settings +// | _ -> (List.rev settings, s) +// let settings, s = loop s [] +// Some (settings, s) +// +// let rec (|Section|_|) = function +// | Header (name, Settings (settings, s)) -> Some ({ Name = name; Settings = settings }, s) +// | _ -> None +// +// let (|Sections|_|) s = +// let rec loop s sections = +// match s with +// | Section (section, s) -> loop s (section :: sections) +// | Comment s -> loop s sections +// | _ -> (sections |> List.rev, s) +// let sections, s = loop s [] +// Some (sections, s) +// +// let streamOfLines lines = Stream (0, lines |> Seq.filter (not << String.IsNullOrWhiteSpace) |> List.ofSeq) +// let streamOfFile path = File.ReadLines path |> streamOfLines +// let parse path = +// match streamOfFile path with +// | Sections (sections, _) -> Choice1Of2 sections +// | e -> Choice2Of2 e +// +//open ProviderImplementation.ProvidedTypes +//open System.Globalization +////open System.Runtime.Caching +// +//let getValue (iniFileName: string) (section: string) (key: string) = +// match Parser.parse (Path.GetFileName iniFileName) with +// | Choice1Of2 sections -> +// maybe { +// let! section = sections |> List.tryFind (fun s -> s.Name = section) +// let! setting = section.Settings |> List.tryFind (fun s -> s.Key = key) +// return setting.Value +// } +// | Choice2Of2 _ -> None +// +//let internal typedIniFile (context: Context) = +// let iniFile = ProvidedTypeDefinition(thisAssembly, rootNamespace, "IniFile", Some typeof, true) +// //let cache = new MemoryCache(name = "IniFileProvider") +// //context.AddDisposable cache +// +// iniFile.DefineStaticParameters( +// parameters = [ ProvidedStaticParameter ("configFileName", typeof) ], +// instantiationFunction = (fun typeName parameterValues -> +// //let value = lazy ( +// match parameterValues with +// | [| :? string as iniFileName |] -> +// let typeDef = ProvidedTypeDefinition(thisAssembly, rootNamespace, typeName, Some typeof, true) +// let niceName = createNiceNameProvider() +// try +// let filePath = findConfigFile context.ResolutionFolder iniFileName +// match Parser.parse filePath with +// | Choice1Of2 sections -> +// for section in sections do +// let sectionTy = ProvidedTypeDefinition(section.Name, Some typeof, hideObjectMethods = true) +// for setting in section.Settings do +// let sectionName = section.Name +// let key = setting.Key +// let prop = +// match setting.Value with +// | ValueParser.Int value -> ProvidedProperty(key, typeof, isStatic = true, getterCode = fun _ -> +// <@@ +// match getValue filePath sectionName key with +// | Some v -> Int32.Parse v +// | None -> value +// @@>) +// | ValueParser.Bool value -> ProvidedProperty(key, typeof, isStatic = true, getterCode = fun _ -> +// <@@ +// match getValue filePath sectionName key with +// | Some v -> Boolean.Parse v +// | None -> value +// @@>) +// | ValueParser.Float value -> ProvidedProperty(key, typeof, isStatic = true, getterCode = fun _ -> +// <@@ +// match getValue filePath sectionName key with +// | Some v -> Double.Parse (v, NumberStyles.Any, CultureInfo.InvariantCulture) +// | None -> value +// @@>) +// | value -> ProvidedProperty(key, typeof, isStatic = true, getterCode = fun _ -> +// <@@ +// match getValue filePath sectionName key with +// | Some v -> v +// | None -> value +// @@>) +// +// +// prop.AddXmlDoc (sprintf "Returns the value from %s from section %s with key %s" iniFileName section.Name setting.Key) +// prop.AddDefinitionLocation(1, 1, filePath) +// sectionTy.AddMember prop +// +// typeDef.AddMember sectionTy +// | Choice2Of2 e -> failwithf "%A" e +// +// let name = niceName "ConfigFileName" +// let getValue = <@@ filePath @@> +// let prop = ProvidedProperty(name, typeof, isStatic = true, getterCode = fun _ -> getValue) +// +// +// prop.AddXmlDoc "Returns the Filename" +// typeDef.AddMember prop +// context.WatchFile filePath +// typeDef +// with _ -> typeDef +// | x -> failwithf "unexpected parameter values %A" x) +// //cache.GetOrAdd (typeName, value))) +// ) +// iniFile \ No newline at end of file diff --git a/src/FSharp.Configuration/ResXProvider.fs b/src/FSharp.Configuration/ResXProvider.fs index 31a0f246..0b6feedf 100644 --- a/src/FSharp.Configuration/ResXProvider.fs +++ b/src/FSharp.Configuration/ResXProvider.fs @@ -1,76 +1,76 @@ module FSharp.Configuration.ResXProvider -open System -open System.IO -open System.Reflection -open System.Resources -open System.ComponentModel.Design -open System.Collections -open System.Collections.Concurrent -open System.Runtime.Caching -open ProviderImplementation.ProvidedTypes -open FSharp.Configuration.Helper - -let readFile (filePath: FilePath) : ResXDataNode list = - use reader = new ResXResourceReader(filePath, UseResXDataNodes = true) - reader - |> Seq.cast - |> Seq.map (fun (x: DictionaryEntry) -> x.Value :?> ResXDataNode) - |> Seq.toList - -let resourceManCache = ConcurrentDictionary () - -let readValue resourceName assembly key = - let resourceMan = resourceManCache.GetOrAdd ((resourceName, assembly), - fun _ -> ResourceManager (resourceName, assembly)) - downcast (resourceMan.GetObject key) - -/// Converts ResX entries to provided properties -let private toProperties (filePath: FilePath) resourceName : MemberInfo list = - readFile filePath - |> List.map (fun node -> - let key = node.Name - let ty = node.GetValueTypeName Unchecked.defaultof |> Type.GetType - let resource = - ProvidedProperty( - key, - ty, - isStatic = true, - getterCode = fun _ -> <@@ readValue resourceName (Assembly.GetExecutingAssembly ()) key @@>) - if not (String.IsNullOrEmpty node.Comment) then - resource.AddXmlDoc node.Comment - resource :> MemberInfo) - -/// Creates provided type from static resource file parameter -let private createResXProvider typeName resourceName filePath = - let ty = ProvidedTypeDefinition (thisAssembly, rootNamespace, typeName, baseType = Some typeof) - ty.SetAttributes (ty.Attributes ||| TypeAttributes.Abstract ||| TypeAttributes.Sealed) - toProperties filePath resourceName - |> Seq.iter ty.AddMember - ty - -let inline private replace (oldChar:char) (newChar:char) (s:string) = s.Replace(oldChar, newChar) - -let internal typedResources (context: Context) = - let resXType = erasedType thisAssembly rootNamespace "ResXProvider" None - let cache = new MemoryCache("ResXProvider") - context.AddDisposable cache - - resXType.DefineStaticParameters( - parameters = [ ProvidedStaticParameter ("file", typeof) ], - instantiationFunction = (fun typeName parameterValues -> - let value = lazy ( - match parameterValues with - | [| :? string as resourcePath|] -> - let filePath = findConfigFile context.ResolutionFolder resourcePath - if not (File.Exists filePath) then invalidArg "file" "Resouce file not found" - let resourceName = - Path.ChangeExtension (resourcePath, null) - |> replace '\\' '.' - |> replace '/' '.' - let providedType = createResXProvider typeName resourceName filePath - context.WatchFile filePath - providedType - | _ -> failwith "unexpected parameter values") - cache.GetOrAdd (typeName, value))) - resXType \ No newline at end of file +//open System +//open System.IO +//open System.Reflection +//open System.Resources +//open System.ComponentModel.Design +//open System.Collections +//open System.Collections.Concurrent +//open System.Runtime.Caching +//open ProviderImplementation.ProvidedTypes +//open FSharp.Configuration.Helper +// +//let readFile (filePath: FilePath) : ResXDataNode list = +// use reader = new ResXResourceReader(filePath, UseResXDataNodes = true) +// reader +// |> Seq.cast +// |> Seq.map (fun (x: DictionaryEntry) -> x.Value :?> ResXDataNode) +// |> Seq.toList +// +//let resourceManCache = ConcurrentDictionary () +// +//let readValue resourceName assembly key = +// let resourceMan = resourceManCache.GetOrAdd ((resourceName, assembly), +// fun _ -> ResourceManager (resourceName, assembly)) +// downcast (resourceMan.GetObject key) +// +///// Converts ResX entries to provided properties +//let private toProperties (filePath: FilePath) resourceName : MemberInfo list = +// readFile filePath +// |> List.map (fun node -> +// let key = node.Name +// let ty = node.GetValueTypeName Unchecked.defaultof |> Type.GetType +// let resource = +// ProvidedProperty( +// key, +// ty, +// isStatic = true, +// getterCode = fun _ -> <@@ readValue resourceName (Assembly.GetExecutingAssembly ()) key @@>) +// if not (String.IsNullOrEmpty node.Comment) then +// resource.AddXmlDoc node.Comment +// resource :> MemberInfo) +// +///// Creates provided type from static resource file parameter +//let private createResXProvider typeName resourceName filePath = +// let ty = ProvidedTypeDefinition (thisAssembly, rootNamespace, typeName, baseType = Some typeof) +// ty.SetAttributes (ty.Attributes ||| TypeAttributes.Abstract ||| TypeAttributes.Sealed) +// toProperties filePath resourceName +// |> Seq.iter ty.AddMember +// ty +// +//let inline private replace (oldChar:char) (newChar:char) (s:string) = s.Replace(oldChar, newChar) +// +//let internal typedResources (context: Context) = +// let resXType = erasedType thisAssembly rootNamespace "ResXProvider" None +// let cache = new MemoryCache("ResXProvider") +// context.AddDisposable cache +// +// resXType.DefineStaticParameters( +// parameters = [ ProvidedStaticParameter ("file", typeof) ], +// instantiationFunction = (fun typeName parameterValues -> +// let value = lazy ( +// match parameterValues with +// | [| :? string as resourcePath|] -> +// let filePath = findConfigFile context.ResolutionFolder resourcePath +// if not (File.Exists filePath) then invalidArg "file" "Resource file not found" +// let resourceName = +// Path.ChangeExtension (resourcePath, null) +// |> replace '\\' '.' +// |> replace '/' '.' +// let providedType = createResXProvider typeName resourceName filePath +// context.WatchFile filePath +// providedType +// | _ -> failwith "unexpected parameter values") +// cache.GetOrAdd (typeName, value))) +// resXType \ No newline at end of file diff --git a/src/FSharp.Configuration/TypeProviders.Helper.fs b/src/FSharp.Configuration/TypeProviders.Helper.fs index 48107cb2..108b3d5f 100644 --- a/src/FSharp.Configuration/TypeProviders.Helper.fs +++ b/src/FSharp.Configuration/TypeProviders.Helper.fs @@ -198,11 +198,6 @@ let findConfigFile resolutionFolder configFileName = let path = configFileName.Split([|@"\"; "/"|], StringSplitOptions.None) Array.append [|resolutionFolder|] path |> Path.Combine -let erasedType<'T> assemblyName rootNamespace typeName (hideObjectMethods: bool option) = - match hideObjectMethods with - | None -> ProvidedTypeDefinition(assemblyName, rootNamespace, typeName, Some(typeof<'T>)) - | Some hideObjectMethods -> ProvidedTypeDefinition(assemblyName, rootNamespace, typeName, Some(typeof<'T>), hideObjectMethods = hideObjectMethods) - // Get the assembly and namespace used to house the provided types let thisAssembly = System.Reflection.Assembly.GetExecutingAssembly() let rootNamespace = "FSharp.Configuration" @@ -309,22 +304,25 @@ type Context (provider: TypeProviderForNamespaces, cfg: TypeProviderConfig) = member __.WatchFile (file: FilePath) = agent.Post (Watch file) member __.AddDisposable x = agent.Post (AddDisposable x) + member __.ErasedType<'T>(assemblyName, rootNamespace, typeName) = + ProvidedTypeDefinition(assemblyName, rootNamespace, typeName, Some(typeof<'T>)) + interface IDisposable with member __.Dispose() = agent.Post Cancel -open System.Runtime.Caching - -type MemoryCache with - member x.GetOrAdd(key: string, value: Lazy, ?expiration: TimeSpan) = - let policy = CacheItemPolicy() - policy.SlidingExpiration <- defaultArg expiration <| TimeSpan.FromHours 24. - - match x.AddOrGetExisting(key, value, policy) with - | :? Lazy as item -> - try item.Value - with _ -> - x.Remove key |> ignore - value.Value - | x -> - assert(x = null) - value.Value \ No newline at end of file +//open System.Runtime.Caching +// +//type MemoryCache with +// member x.GetOrAdd(key: string, value: Lazy, ?expiration: TimeSpan) = +// let policy = CacheItemPolicy() +// policy.SlidingExpiration <- defaultArg expiration <| TimeSpan.FromHours 24. + // +// match x.AddOrGetExisting(key, value, policy) with +// | :? Lazy as item -> +// try item.Value +// with _ -> +// x.Remove key |> ignore +// value.Value +// | x -> +// assert(x = null) +// value.Value \ No newline at end of file diff --git a/src/FSharp.Configuration/YamlConfigProvider.fs b/src/FSharp.Configuration/YamlConfigProvider.fs index d7302a37..cdc04c81 100644 --- a/src/FSharp.Configuration/YamlConfigProvider.fs +++ b/src/FSharp.Configuration/YamlConfigProvider.fs @@ -1,6 +1,7 @@ module FSharp.Configuration.YamlConfigTypeProvider #nowarn "57" +#nowarn "25" open System.Reflection open System @@ -570,5 +571,7 @@ let internal typedYamlConfig (context: Context) = context.WatchFile filePath createTy (File.ReadAllText filePath) readOnly inferTypesFromStrings | _ -> failwith "Wrong parameters") - cache.GetOrAdd (typeName, value)) + + cache.AddOrGetExisting(typeName, value, DateTimeOffset(DateTime.Now + TimeSpan.FromMinutes(1.0))) :?> ProvidedTypeDefinition + ) yamlConfig diff --git a/src/FSharp.Configuration/paket.references b/src/FSharp.Configuration/paket.references index 9eb4f66e..88ec99e5 100644 --- a/src/FSharp.Configuration/paket.references +++ b/src/FSharp.Configuration/paket.references @@ -1,5 +1,7 @@ -SharpYaml -FSharp.Core -File: ProvidedTypes.fsi . -File: ProvidedTypes.fs . -File: ProvidedTypesTesting.fs . \ No newline at end of file +group Build + SharpYaml + FSharp.Core + System.Runtime.Caching + File: ProvidedTypes.fsi . + File: ProvidedTypes.fs . + File: ProvidedTypesTesting.fs . \ No newline at end of file diff --git a/tests/FSharp.Configuration.Tests/AppSettingsProvider.Tests.fs b/tests/FSharp.Configuration.Tests/AppSettingsProvider.Tests.fs index d633f3ee..c1ccb8d2 100644 --- a/tests/FSharp.Configuration.Tests/AppSettingsProvider.Tests.fs +++ b/tests/FSharp.Configuration.Tests/AppSettingsProvider.Tests.fs @@ -1,40 +1,40 @@ module FSharp.Configuration.Tests.AppSettingsTests - -open System -open FSharp.Configuration -open Expecto - -type Settings = AppSettings<"app.config"> - -let [] tests = - testList "App Settings Provider tests" [ - testCase "Can return a string from the config file" (fun _ -> Expect.equal Settings.Test2 "Some Test Value 5" "value") - testCase "Can return an integer from the config file" (fun _ -> Expect.equal Settings.TestInt 102 "value") - testCase "Can return a double from the config file" (fun _ -> Expect.equal Settings.TestDouble 10.01 "value") - testCase "Can return a boolean from the config file" (fun _ -> Expect.isTrue Settings.TestBool "value") - testCase "Can return a TimeSpan from the config file" (fun _ -> Expect.equal Settings.TestTimeSpan (TimeSpan.Parse "2.01:02:03.444") "value") - testCase "Can return a DateTime from the config file" (fun _ -> Expect.equal (Settings.TestDateTime.ToUniversalTime()) (DateTime (2014, 2, 1, 3, 4, 5, 777)) "value") - testCase "Can return a Uri from the config file" (fun _ -> Expect.equal Settings.TestUri (Uri "http://fsharp.org") "value") - - testCase "Can return a connection string from the config file" (fun _ -> - Expect.equal Settings.ConnectionStrings.Test1 "Server=myServerAddress;Database=myDataBase;Trusted_Connection=True;" "value") - - testCase "Can return a guid from the config file" (fun _ -> Expect.equal Settings.TestGuid (Guid.Parse "{7B7EB384-FEBA-4409-B560-66FF63F1E8D0}") "value") - testCase "Can read multiple connection strings from the config file" (fun _ -> Expect.notEqual Settings.ConnectionStrings.Test1 Settings.ConnectionStrings.Test2 "value") - ] - -[] -let fakeConfig = __SOURCE_DIRECTORY__ + @"/../../packages/FAKE/tools/FAKE.Deploy.exe.config" -type FakeSettings = AppSettings - -let [] test = - testCase "Can read different configuration file" (fun _ -> - [| __SOURCE_DIRECTORY__; ".."; ".."; "packages"; "FAKE"; "tools"; "FAKE.Deploy.exe" |] - |> System.IO.Path.Combine |> System.IO.Path.GetFullPath - |> FakeSettings.SelectExecutableFile - - #if INTERACTIVE //Travis can't handle fakeConfig-directory - FakeSettings.ServerName =! "localhost" - #endif - ) - \ No newline at end of file +// +//open System +//open FSharp.Configuration +//open Expecto +// +//type Settings = AppSettings<"app.config"> +// +//let [] tests = +// testList "App Settings Provider tests" [ +// testCase "Can return a string from the config file" (fun _ -> Expect.equal Settings.Test2 "Some Test Value 5" "value") +// testCase "Can return an integer from the config file" (fun _ -> Expect.equal Settings.TestInt 102 "value") +// testCase "Can return a double from the config file" (fun _ -> Expect.equal Settings.TestDouble 10.01 "value") +// testCase "Can return a boolean from the config file" (fun _ -> Expect.isTrue Settings.TestBool "value") +// testCase "Can return a TimeSpan from the config file" (fun _ -> Expect.equal Settings.TestTimeSpan (TimeSpan.Parse "2.01:02:03.444") "value") +// testCase "Can return a DateTime from the config file" (fun _ -> Expect.equal (Settings.TestDateTime.ToUniversalTime()) (DateTime (2014, 2, 1, 3, 4, 5, 777)) "value") +// testCase "Can return a Uri from the config file" (fun _ -> Expect.equal Settings.TestUri (Uri "http://fsharp.org") "value") +// +// testCase "Can return a connection string from the config file" (fun _ -> +// Expect.equal Settings.ConnectionStrings.Test1 "Server=myServerAddress;Database=myDataBase;Trusted_Connection=True;" "value") +// +// testCase "Can return a guid from the config file" (fun _ -> Expect.equal Settings.TestGuid (Guid.Parse "{7B7EB384-FEBA-4409-B560-66FF63F1E8D0}") "value") +// testCase "Can read multiple connection strings from the config file" (fun _ -> Expect.notEqual Settings.ConnectionStrings.Test1 Settings.ConnectionStrings.Test2 "value") +// ] +// +//[] +//let fakeConfig = __SOURCE_DIRECTORY__ + @"/../../packages/FAKE/tools/FAKE.Deploy.exe.config" +//type FakeSettings = AppSettings +// +//let [] test = +// testCase "Can read different configuration file" (fun _ -> +// [| __SOURCE_DIRECTORY__; ".."; ".."; "packages"; "FAKE"; "tools"; "FAKE.Deploy.exe" |] +// |> System.IO.Path.Combine |> System.IO.Path.GetFullPath +// |> FakeSettings.SelectExecutableFile +// +// #if INTERACTIVE //Travis can't handle fakeConfig-directory +// FakeSettings.ServerName =! "localhost" +// #endif +// ) +// \ No newline at end of file diff --git a/tests/FSharp.Configuration.Tests/FSharp.Configuration.Tests.fsproj b/tests/FSharp.Configuration.Tests/FSharp.Configuration.Tests.fsproj index ad1abf55..63861d90 100644 --- a/tests/FSharp.Configuration.Tests/FSharp.Configuration.Tests.fsproj +++ b/tests/FSharp.Configuration.Tests/FSharp.Configuration.Tests.fsproj @@ -1,76 +1,50 @@  - - + + + - Debug - AnyCPU - 2.0 - e789c72a-5cfd-436b-8ef1-61aa2852a89f Exe - FSharp.Configuration.Tests - FSharp.Configuration.Tests - v4.6.1 - FSharp.Configuration.Tests - - ..\..\ - true + netcoreapp20 true - - true - full - false - false - bin\Debug\ - DEBUG;TRACE - 3 - - - Project - - - - - false - - - pdbonly - true - true - bin\Release\ - TRACE - 3 - - - - - 11 - - - - - $(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets - - - - - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets - - - - - + + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + Always - + @@ -82,83 +56,19 @@ - - ..\..\bin\FSharp.Configuration.dll + + ..\..\packages\test\Expecto\lib\netstandard2.0\Expecto.dll + + + ..\..\src\FSharp.Configuration\bin\Debug\netstandard2.0\FSharp.Configuration.dll - - + - - - - - - - ..\..\packages\test\Argu\lib\net45\Argu.dll - True - True - - - - - - - - - ..\..\packages\test\Expecto\lib\net461\Expecto.dll - True - True - - - - - - - - - ..\..\packages\test\FSharp.Core\lib\net45\FSharp.Core.dll - True - True - - - - - - - - - ..\..\packages\test\Mono.Cecil\lib\net40\Mono.Cecil.dll - True - True - - - ..\..\packages\test\Mono.Cecil\lib\net40\Mono.Cecil.Mdb.dll - True - True - - - ..\..\packages\test\Mono.Cecil\lib\net40\Mono.Cecil.Pdb.dll - True - True - - - ..\..\packages\test\Mono.Cecil\lib\net40\Mono.Cecil.Rocks.dll - True - True - - - - + \ No newline at end of file diff --git a/tests/FSharp.Configuration.Tests/IniFileProvider.Tests.fs b/tests/FSharp.Configuration.Tests/IniFileProvider.Tests.fs index d7a99703..10113a12 100644 --- a/tests/FSharp.Configuration.Tests/IniFileProvider.Tests.fs +++ b/tests/FSharp.Configuration.Tests/IniFileProvider.Tests.fs @@ -1,22 +1,22 @@ module FSharp.Configuration.Tests.IniFile -open FSharp.Configuration -open Expecto - -type IniFileType = IniFile<"Sample.ini"> - -let [] tests = - testList "Ini File Provider tests" [ - testCase "Can return a string from the config file" (fun _ -> - Expect.equal IniFileType.Section1.key2 "stringValue" "value") - - testCase "Can return an integer from the config file" (fun _ -> - Expect.equal IniFileType.Section1.key1 2 "value") - - testCase "Can return a double from the config file" (fun _ -> - Expect.equal IniFileType.Section2.key3 1.23 "value") - - testCase "Can return a boolean from the config file" (fun _ -> - Expect.isTrue IniFileType.Section2.key5 "key5" - Expect.isFalse IniFileType.Section2.key6 "key6") - ] \ No newline at end of file +//open FSharp.Configuration +//open Expecto +// +//type IniFileType = IniFile<"Sample.ini"> +// +//let [] tests = +// testList "Ini File Provider tests" [ +// testCase "Can return a string from the config file" (fun _ -> +// Expect.equal IniFileType.Section1.key2 "stringValue" "value") +// +// testCase "Can return an integer from the config file" (fun _ -> +// Expect.equal IniFileType.Section1.key1 2 "value") +// +// testCase "Can return a double from the config file" (fun _ -> +// Expect.equal IniFileType.Section2.key3 1.23 "value") +// +// testCase "Can return a boolean from the config file" (fun _ -> +// Expect.isTrue IniFileType.Section2.key5 "key5" +// Expect.isFalse IniFileType.Section2.key6 "key6") +// ] \ No newline at end of file diff --git a/tests/FSharp.Configuration.Tests/ResXProvider.Tests.fs b/tests/FSharp.Configuration.Tests/ResXProvider.Tests.fs index e0a08f56..30a61a46 100644 --- a/tests/FSharp.Configuration.Tests/ResXProvider.Tests.fs +++ b/tests/FSharp.Configuration.Tests/ResXProvider.Tests.fs @@ -1,18 +1,22 @@ module FSharp.Configuration.Tests.ResXTests -open FSharp.Configuration -open Expecto - -type Resource1 = ResXProvider<"Resource1.resx"> - -let [] tests = - testList "ResX Provider tests" [ - testCase "Can return a string from the resource file" (fun _ -> Expect.equal Resource1.Greetings "Hello World!" "value") - - testCase "Can return an image from the resource file" (fun _ -> - Expect.isNotNull Resource1.Flowers "Flowers" - Expect.equal typeof (Resource1.Flowers.GetType()) "value") - - testCase "Can return an int from the resource file" (fun _ -> Expect.equal Resource1.Answer 42 "value") - testCase "Can return a text file from the resource file" (fun _ -> Expect.equal Resource1.TextFile "Text" "value") - ] \ No newline at end of file +//open FSharp.Configuration +//open Expecto +// +//type Resource1 = ResXProvider<"Resource1.resx"> +// +//let [] tests = +// // https://github.com/Microsoft/msbuild/issues/2221 +// ptestList "ResX Provider tests" [ +// testCase "Can return a string from the resource file" (fun _ -> +// Expect.equal Resource1.Greetings "Hello World!" "value") +// +// testCase "Can return an image from the resource file" (fun _ -> +// Expect.isNotNull Resource1.Flowers "Flowers" +// Expect.equal typeof (Resource1.Flowers.GetType()) "value") +// +// testCase "Can return an int from the resource file" (fun _ -> +// Expect.equal Resource1.Answer 42 "value") +// testCase "Can return a text file from the resource file" (fun _ -> +// Expect.equal Resource1.TextFile "Text" "value") +// ] diff --git a/tests/FSharp.Configuration.Tests/YamlProvider.Tests.fs b/tests/FSharp.Configuration.Tests/YamlProvider.Tests.fs index 73334902..4a10a330 100644 --- a/tests/FSharp.Configuration.Tests/YamlProvider.Tests.fs +++ b/tests/FSharp.Configuration.Tests/YamlProvider.Tests.fs @@ -1,370 +1,370 @@ module FSharp.Configuration.Tests.YamlTests - -open FSharp.Configuration -open System -open System.IO -open Expecto - -type Settings = YamlConfig<"Settings.yaml"> - -let private assertFilesAreEqual expected actual = - let read file = (File.ReadAllText file).Replace("\r\n", "\n") - Expect.equal (read expected) (read actual) "files" - -type private Listener(event: IEvent) = - let events = ref 0 - do event.Add (fun _ -> incr events) - member __.Events = !events - -let [] tests = - testList "Yaml Config Provider tests" [ - testCase "Can return a string from the settings file" (fun _ -> - let settings = Settings() - Expect.equal settings.DB.ConnectionString "Data Source=server1;Initial Catalog=Database1;Integrated Security=SSPI;" "value") - - testCase "Can return an int from the settings file" (fun _ -> - let settings = Settings() - Expect.equal settings.DB.NumberOfDeadlockRepeats 5 "value") - - testCase "Can return an int64 from the settings file" (fun _ -> - let settings = Settings() - Expect.equal settings.DB.Id 21474836470L "value") - - testCase "Can return an double from the settings file" (fun _ -> - let settings = Settings() - Expect.equal settings.JustStuff.SomeDoubleValue 0.5 "value") - - testCase "Can return a TimeSpan from the settings file" (fun _ -> - let settings = Settings() - Expect.equal settings.DB.DefaultTimeout (TimeSpan.FromMinutes 5.0) "value") - - testCase "Can return a guid from the settings file" (fun _ -> - let settings = Settings() - Expect.equal settings.JustStuff.SomeGuid (Guid.Parse "{7B7EB384-FEBA-4409-B560-66FF63F1E8D0}") "value") - - testCase "Can return a different guid from the settings file" (fun _ -> - let settings = Settings() - Expect.equal settings.JustStuff.DifferentGuid (Guid.Parse "9d165087-9b74-4313-ab90-89be897d3d93") "value") - - testCase "Can return a list from the settings file" (fun _ -> - let settings = Settings() - Expect.equal settings.Mail.ErrorNotificationRecipients.Count 2 "value" - Expect.equal settings.Mail.ErrorNotificationRecipients.[0] "user1@sample.com" "value" - Expect.equal settings.Mail.ErrorNotificationRecipients.[1] "user2@sample.com" "value") - - testCase "Can write to a string in the settings file" (fun _ -> - let settings = Settings() - settings.DB.ConnectionString <- "Data Source=server2" - Expect.equal settings.DB.ConnectionString "Data Source=server2" "value") - - testCase "Can write to an int in the settings file" (fun _ -> - let settings = Settings() - settings.DB.NumberOfDeadlockRepeats <- 6 - Expect.equal settings.DB.NumberOfDeadlockRepeats 6 "value") - - testCase "Can write to an double in the settings file" (fun _ -> - let settings = Settings() - settings.JustStuff.SomeDoubleValue <- 0.5 - Expect.equal settings.JustStuff.SomeDoubleValue 0.5 "value") - - testCase "Can write to a guid in the settings file" (fun _ -> - let settings = Settings() - let guid = Guid.NewGuid() - settings.JustStuff.SomeGuid <- guid - Expect.equal settings.JustStuff.SomeGuid guid "value") - - testCase "Can save a settings file to a specified location" (fun _ -> - let settings = Settings() - settings.DB.NumberOfDeadlockRepeats <- 11 - settings.DB.DefaultTimeout <- System.TimeSpan.FromMinutes 6. - settings.JustStuff.SomeDoubleValue <- 0.5 - settings.Save "SettingsModifed.yaml" - assertFilesAreEqual "SettingsModifed.yaml" "Settings2.yaml") - - testCase "Can save settings to the file it was loaded from last time" (fun _ -> - let settings = Settings() - let tempFile = Path.GetTempFileName() - try - File.Copy ("Settings.yaml", tempFile, overwrite=true) - settings.Load tempFile - settings.DB.NumberOfDeadlockRepeats <- 11 - settings.DB.DefaultTimeout <- System.TimeSpan.FromMinutes 6. - settings.Save() - assertFilesAreEqual tempFile "Settings2.yaml" - finally File.Delete tempFile) - - testCase "Throws exception during saving if it was not loaded from a file and location is not specified" (fun _ -> - let settings = Settings() - Expect.throwsT (fun() -> settings.Save()) "throws") - - testCase "Can loads full settings" (fun _ -> - let settings = Settings() - settings.LoadText """ - Mail: - Smtp: - Host: smtp.sample.com* - Port: 4430 - User: user1* - Password: pass1* - Pop3: - Host: pop3.sample.com* - Port: 3310 - User: user2* - Password: pass2* - CheckPeriod: 00:02:00 - ErrorNotificationRecipients: - - user1@sample.com* - - user2@sample.com* - - user3@sample.com - DB: - ConnectionString: Data Source=server1;Initial Catalog=Database1;Integrated Security=SSPI;* - NumberOfDeadlockRepeats: 50 - DefaultTimeout: 00:06:00 - """ - Expect.equal settings.Mail.Smtp.Host "smtp.sample.com*" "value" - Expect.equal settings.Mail.Smtp.Port 4430 "value" - Expect.equal settings.Mail.Smtp.User "user1*" "value" - Expect.equal settings.Mail.Smtp.Password "pass1*" "value" - - Expect.equal settings.Mail.Pop3.Host "pop3.sample.com*" "value" - Expect.equal settings.Mail.Pop3.Port 3310 "value" - Expect.equal settings.Mail.Pop3.User "user2*" "value" - Expect.equal settings.Mail.Pop3.Password "pass2*" "value" - Expect.equal settings.Mail.Pop3.CheckPeriod (TimeSpan.FromMinutes 2.0) "value" - - Expect.equal (List.ofSeq settings.Mail.ErrorNotificationRecipients) ["user1@sample.com*"; "user2@sample.com*"; "user3@sample.com"] "value" - Expect.equal settings.DB.ConnectionString "Data Source=server1;Initial Catalog=Database1;Integrated Security=SSPI;*" "value" - Expect.equal settings.DB.NumberOfDeadlockRepeats 50 "value" - Expect.equal settings.DB.DefaultTimeout (TimeSpan.FromMinutes 6.0) "value") - - testCase "Can load partial settings" (fun _ -> - let settings = Settings() - settings.LoadText """ - Mail: - Smtp: - Port: 4430 - Pop3: - CheckPeriod: 00:02:00 - ErrorNotificationRecipients: - - user1@sample.com* - - user2@sample.com* - - user3@sample.com - """ - Expect.equal settings.Mail.Smtp.Host "smtp.sample.com" "value" - Expect.equal settings.Mail.Smtp.Port 4430 "value" - Expect.equal settings.Mail.Smtp.User "user1" "value" - Expect.equal settings.Mail.Smtp.Password "pass1" "value" - - Expect.equal settings.Mail.Pop3.Host "pop3.sample.com" "value" - Expect.equal settings.Mail.Pop3.Port 331 "value" - Expect.equal settings.Mail.Pop3.User "user2" "value" - Expect.equal settings.Mail.Pop3.Password "pass2" "value" - Expect.equal settings.Mail.Pop3.CheckPeriod (TimeSpan.FromMinutes 2.0) "value" - - Expect.sequenceEqual settings.Mail.ErrorNotificationRecipients ["user1@sample.com*"; "user2@sample.com*"; "user3@sample.com"] "value" - - Expect.equal settings.DB.ConnectionString "Data Source=server1;Initial Catalog=Database1;Integrated Security=SSPI;" "value" - Expect.equal settings.DB.NumberOfDeadlockRepeats 5 "value" - Expect.equal settings.DB.DefaultTimeout (TimeSpan.FromMinutes 5.0) "value") - - testCase "Can load settings containing unknown nodes" (fun _ -> - let settings = Settings() - settings.LoadText """ - Mail: - Smtp: - Port: 4430 - NestedUnknown: value1 - TopLevelUnknown: - Value: 1 - - """ - Expect.equal settings.Mail.Smtp.Port 4430 "value") - - testCase "Can load file and watch" (fun _ -> - let settings = Settings() - let tempFile = Path.GetTempFileName() - try - File.Copy ("Settings.yaml", tempFile, overwrite = true) - settings.LoadAndWatch tempFile |> ignore - finally - File.Delete tempFile) - - testCase "Can load file and watch and detect errors" (fun _ -> - let settings = Settings() - let tempFile = Path.GetTempFileName() - let mutable err = false - settings.Error.Add(fun _ -> err <- true) - try - File.Copy ("Settings.yaml", tempFile, overwrite=true) - use __ = settings.LoadAndWatch tempFile - System.Threading.Thread.Sleep(800) - let f = new FileStream(tempFile, FileMode.Append) - let data = ":asd:DF" |> System.Text.Encoding.ASCII.GetBytes - f.Write(data, 0, data.Length) - f.Flush() - f.Dispose() - Threading.Thread.Sleep(800) - Expect.isTrue err "error event raised" - finally - File.Delete tempFile) - - testCase "Can load empty lists" (fun _ -> - let settings = Settings() - settings.LoadText """ - Mail: - ErrorNotificationRecipients: [] - """ - Expect.isEmpty settings.Mail.ErrorNotificationRecipients "value") - - testCase "Raises Changed events" (fun _ -> - let settings = Settings() - let rootListener = Listener(settings.Changed) - let mailListener = Listener(settings.Mail.Changed) - let pop3Listener = Listener(settings.Mail.Pop3.Changed) - let smtpListener = Listener(settings.Mail.Smtp.Changed) - let dbListener = Listener(settings.DB.Changed) - - settings.LoadText """ - Mail: - Pop3: - CheckPeriod: 00:02:00 - """ - Expect.sequenceEqual - [rootListener.Events - mailListener.Events - pop3Listener.Events - smtpListener.Events - dbListener.Events] - [1; 1; 1; 0; 0] "value") - - testCase "Does not raise duplicates of parent Changed events even though several children changed" (fun _ -> - let settings = Settings() - let rootListener = Listener settings.Changed - let mailListener = Listener settings.Mail.Changed - let pop3Listener = Listener settings.Mail.Pop3.Changed - let smtpListener = Listener settings.Mail.Smtp.Changed - - settings.LoadText """ - Mail: - Smtp: - Port: 4430 - Pop3: - CheckPeriod: 00:02:00 - """ - Expect.sequenceEqual - [rootListener.Events - mailListener.Events - pop3Listener.Events - smtpListener.Events] - [1; 1; 1; 1] "value") - ] - -type Lists = YamlConfig<"Lists.yaml"> - -let [] listTests = - testList "Yaml Config Provider tests - lists" (Seq.toList <| - testFixture (fun f () -> f (Lists())) [ - "Can load sequence of maps (single item)", fun settings -> - settings.LoadText """ - items: - - part_no: Test - descrip: Some description - price: 347 - quantity: 14 - """ - Expect.equal settings.items.Count 1 "value" - Expect.equal settings.items.[0].part_no "Test" "value" - Expect.equal settings.items.[0].descrip "Some description" "value" - Expect.equal settings.items.[0].quantity 14 "value" - - "Can load sequence of maps (multiple items)", fun settings -> - settings.LoadText """ - items: - - part_no: Test - descrip: Some description - price: 347 - quantity: 14 - - part_no: A4786 - descrip: Water Bucket (Filled) - price: 147 - quantity: 4 - - - part_no: E1628 - descrip: High Heeled "Ruby" Slippers - size: 8 - price: 10027 - quantity: 1 - """ - Expect.equal settings.items.Count 3 "value" - Expect.equal settings.items.[0].part_no "Test" "value" - Expect.equal settings.items.[0].descrip "Some description" "value" - Expect.equal settings.items.[0].quantity 14 "value" - - Expect.equal settings.items.[2].part_no "E1628" "value" - Expect.equal settings.items.[2].descrip "High Heeled \"Ruby\" Slippers" "value" - Expect.equal settings.items.[2].quantity 1 "value" - - "Can load nested lists", fun settings -> - settings.LoadText """ - Fix82: - id: "myApp" - constraints: - - - - "attribute" - - "OPERATOR" - - "value" - - - - "field" - - "OP" - labels: - environment: "staging" - """ - Expect.equal settings.Fix82.constraints.Count 2 "value" - Expect.equal settings.Fix82.constraints.[0].Count 3 "value" - Expect.equal settings.Fix82.constraints.[0].[0] "attribute" "value" - Expect.equal settings.Fix82.constraints.[0].[1] "OPERATOR" "value" - Expect.equal settings.Fix82.constraints.[0].[2] "value" "value" - Expect.equal settings.Fix82.constraints.[1].Count 2 "value" - Expect.equal settings.Fix82.constraints.[1].[0] "field" "value" - Expect.equal settings.Fix82.constraints.[1].[1] "OP" "value" - - //"Check that list defaults are OK", fun settings -> - // Expect.equal settings.items.Count 2 "value" - // Expect.equal settings.Archive.Count 3 "value" - ]) - -type NumericKeys = YamlConfig - -type MixedTypes = YamlConfig - -let [] numericTests = - testList "Yaml Config Provider - numeric tests" [ - testCase "Numeric map keys are OK" (fun _ -> - let sut = NumericKeys() - Expect.equal sut.``1`` 10 "value" - Expect.equal sut.``2`` 20 "value" - Expect.equal sut.``3a`` "foo" "value") - - testCase "Mixed types are read as strings" (fun _ -> - let mt = MixedTypes() - mt.LoadText(""" - Items: - - Item: asdf - - Item: http://fsharp.org - - Item: 14 - """) - Expect.equal mt.Items.[0].Item "asdf" "value" - Expect.equal mt.Items.[1].Item "http://fsharp.org/" "value" - Expect.equal mt.Items.[2].Item "14" "value") - ] \ No newline at end of file +// +//open FSharp.Configuration +//open System +//open System.IO +//open Expecto +// +//type Settings = YamlConfig<"Settings.yaml"> +// +//let private assertFilesAreEqual expected actual = +// let read file = (File.ReadAllText file).Replace("\r\n", "\n") +// Expect.equal (read expected) (read actual) "files" +// +//type private Listener(event: IEvent) = +// let events = ref 0 +// do event.Add (fun _ -> incr events) +// member __.Events = !events +// +//let [] tests = +// testList "Yaml Config Provider tests" [ +// testCase "Can return a string from the settings file" (fun _ -> +// let settings = Settings() +// Expect.equal settings.DB.ConnectionString "Data Source=server1;Initial Catalog=Database1;Integrated Security=SSPI;" "value") +// +// testCase "Can return an int from the settings file" (fun _ -> +// let settings = Settings() +// Expect.equal settings.DB.NumberOfDeadlockRepeats 5 "value") +// +// testCase "Can return an int64 from the settings file" (fun _ -> +// let settings = Settings() +// Expect.equal settings.DB.Id 21474836470L "value") +// +// testCase "Can return an double from the settings file" (fun _ -> +// let settings = Settings() +// Expect.equal settings.JustStuff.SomeDoubleValue 0.5 "value") +// +// testCase "Can return a TimeSpan from the settings file" (fun _ -> +// let settings = Settings() +// Expect.equal settings.DB.DefaultTimeout (TimeSpan.FromMinutes 5.0) "value") +// +// testCase "Can return a guid from the settings file" (fun _ -> +// let settings = Settings() +// Expect.equal settings.JustStuff.SomeGuid (Guid.Parse "{7B7EB384-FEBA-4409-B560-66FF63F1E8D0}") "value") +// +// testCase "Can return a different guid from the settings file" (fun _ -> +// let settings = Settings() +// Expect.equal settings.JustStuff.DifferentGuid (Guid.Parse "9d165087-9b74-4313-ab90-89be897d3d93") "value") +// +// testCase "Can return a list from the settings file" (fun _ -> +// let settings = Settings() +// Expect.equal settings.Mail.ErrorNotificationRecipients.Count 2 "value" +// Expect.equal settings.Mail.ErrorNotificationRecipients.[0] "user1@sample.com" "value" +// Expect.equal settings.Mail.ErrorNotificationRecipients.[1] "user2@sample.com" "value") +// +// testCase "Can write to a string in the settings file" (fun _ -> +// let settings = Settings() +// settings.DB.ConnectionString <- "Data Source=server2" +// Expect.equal settings.DB.ConnectionString "Data Source=server2" "value") +// +// testCase "Can write to an int in the settings file" (fun _ -> +// let settings = Settings() +// settings.DB.NumberOfDeadlockRepeats <- 6 +// Expect.equal settings.DB.NumberOfDeadlockRepeats 6 "value") +// +// testCase "Can write to an double in the settings file" (fun _ -> +// let settings = Settings() +// settings.JustStuff.SomeDoubleValue <- 0.5 +// Expect.equal settings.JustStuff.SomeDoubleValue 0.5 "value") +// +// testCase "Can write to a guid in the settings file" (fun _ -> +// let settings = Settings() +// let guid = Guid.NewGuid() +// settings.JustStuff.SomeGuid <- guid +// Expect.equal settings.JustStuff.SomeGuid guid "value") +// +// testCase "Can save a settings file to a specified location" (fun _ -> +// let settings = Settings() +// settings.DB.NumberOfDeadlockRepeats <- 11 +// settings.DB.DefaultTimeout <- System.TimeSpan.FromMinutes 6. +// settings.JustStuff.SomeDoubleValue <- 0.5 +// settings.Save "SettingsModifed.yaml" +// assertFilesAreEqual "SettingsModifed.yaml" "Settings2.yaml") +// +// testCase "Can save settings to the file it was loaded from last time" (fun _ -> +// let settings = Settings() +// let tempFile = Path.GetTempFileName() +// try +// File.Copy ("Settings.yaml", tempFile, overwrite=true) +// settings.Load tempFile +// settings.DB.NumberOfDeadlockRepeats <- 11 +// settings.DB.DefaultTimeout <- System.TimeSpan.FromMinutes 6. +// settings.Save() +// assertFilesAreEqual tempFile "Settings2.yaml" +// finally File.Delete tempFile) +// +// testCase "Throws exception during saving if it was not loaded from a file and location is not specified" (fun _ -> +// let settings = Settings() +// Expect.throwsT (fun() -> settings.Save()) "throws") +// +// testCase "Can loads full settings" (fun _ -> +// let settings = Settings() +// settings.LoadText """ +// Mail: +// Smtp: +// Host: smtp.sample.com* +// Port: 4430 +// User: user1* +// Password: pass1* +// Pop3: +// Host: pop3.sample.com* +// Port: 3310 +// User: user2* +// Password: pass2* +// CheckPeriod: 00:02:00 +// ErrorNotificationRecipients: +// - user1@sample.com* +// - user2@sample.com* +// - user3@sample.com +// DB: +// ConnectionString: Data Source=server1;Initial Catalog=Database1;Integrated Security=SSPI;* +// NumberOfDeadlockRepeats: 50 +// DefaultTimeout: 00:06:00 +// """ +// Expect.equal settings.Mail.Smtp.Host "smtp.sample.com*" "value" +// Expect.equal settings.Mail.Smtp.Port 4430 "value" +// Expect.equal settings.Mail.Smtp.User "user1*" "value" +// Expect.equal settings.Mail.Smtp.Password "pass1*" "value" +// +// Expect.equal settings.Mail.Pop3.Host "pop3.sample.com*" "value" +// Expect.equal settings.Mail.Pop3.Port 3310 "value" +// Expect.equal settings.Mail.Pop3.User "user2*" "value" +// Expect.equal settings.Mail.Pop3.Password "pass2*" "value" +// Expect.equal settings.Mail.Pop3.CheckPeriod (TimeSpan.FromMinutes 2.0) "value" +// +// Expect.equal (List.ofSeq settings.Mail.ErrorNotificationRecipients) ["user1@sample.com*"; "user2@sample.com*"; "user3@sample.com"] "value" +// Expect.equal settings.DB.ConnectionString "Data Source=server1;Initial Catalog=Database1;Integrated Security=SSPI;*" "value" +// Expect.equal settings.DB.NumberOfDeadlockRepeats 50 "value" +// Expect.equal settings.DB.DefaultTimeout (TimeSpan.FromMinutes 6.0) "value") +// +// testCase "Can load partial settings" (fun _ -> +// let settings = Settings() +// settings.LoadText """ +// Mail: +// Smtp: +// Port: 4430 +// Pop3: +// CheckPeriod: 00:02:00 +// ErrorNotificationRecipients: +// - user1@sample.com* +// - user2@sample.com* +// - user3@sample.com +// """ +// Expect.equal settings.Mail.Smtp.Host "smtp.sample.com" "value" +// Expect.equal settings.Mail.Smtp.Port 4430 "value" +// Expect.equal settings.Mail.Smtp.User "user1" "value" +// Expect.equal settings.Mail.Smtp.Password "pass1" "value" +// +// Expect.equal settings.Mail.Pop3.Host "pop3.sample.com" "value" +// Expect.equal settings.Mail.Pop3.Port 331 "value" +// Expect.equal settings.Mail.Pop3.User "user2" "value" +// Expect.equal settings.Mail.Pop3.Password "pass2" "value" +// Expect.equal settings.Mail.Pop3.CheckPeriod (TimeSpan.FromMinutes 2.0) "value" +// +// Expect.sequenceEqual settings.Mail.ErrorNotificationRecipients ["user1@sample.com*"; "user2@sample.com*"; "user3@sample.com"] "value" +// +// Expect.equal settings.DB.ConnectionString "Data Source=server1;Initial Catalog=Database1;Integrated Security=SSPI;" "value" +// Expect.equal settings.DB.NumberOfDeadlockRepeats 5 "value" +// Expect.equal settings.DB.DefaultTimeout (TimeSpan.FromMinutes 5.0) "value") +// +// testCase "Can load settings containing unknown nodes" (fun _ -> +// let settings = Settings() +// settings.LoadText """ +// Mail: +// Smtp: +// Port: 4430 +// NestedUnknown: value1 +// TopLevelUnknown: +// Value: 1 +// +// """ +// Expect.equal settings.Mail.Smtp.Port 4430 "value") +// +// testCase "Can load file and watch" (fun _ -> +// let settings = Settings() +// let tempFile = Path.GetTempFileName() +// try +// File.Copy ("Settings.yaml", tempFile, overwrite = true) +// settings.LoadAndWatch tempFile |> ignore +// finally +// File.Delete tempFile) +// +// testCase "Can load file and watch and detect errors" (fun _ -> +// let settings = Settings() +// let tempFile = Path.GetTempFileName() +// let mutable err = false +// settings.Error.Add(fun _ -> err <- true) +// try +// File.Copy ("Settings.yaml", tempFile, overwrite=true) +// use __ = settings.LoadAndWatch tempFile +// System.Threading.Thread.Sleep(800) +// let f = new FileStream(tempFile, FileMode.Append) +// let data = ":asd:DF" |> System.Text.Encoding.ASCII.GetBytes +// f.Write(data, 0, data.Length) +// f.Flush() +// f.Dispose() +// Threading.Thread.Sleep(800) +// Expect.isTrue err "error event raised" +// finally +// File.Delete tempFile) +// +// testCase "Can load empty lists" (fun _ -> +// let settings = Settings() +// settings.LoadText """ +// Mail: +// ErrorNotificationRecipients: [] +// """ +// Expect.isEmpty settings.Mail.ErrorNotificationRecipients "value") +// +// testCase "Raises Changed events" (fun _ -> +// let settings = Settings() +// let rootListener = Listener(settings.Changed) +// let mailListener = Listener(settings.Mail.Changed) +// let pop3Listener = Listener(settings.Mail.Pop3.Changed) +// let smtpListener = Listener(settings.Mail.Smtp.Changed) +// let dbListener = Listener(settings.DB.Changed) +// +// settings.LoadText """ +// Mail: +// Pop3: +// CheckPeriod: 00:02:00 +// """ +// Expect.sequenceEqual +// [rootListener.Events +// mailListener.Events +// pop3Listener.Events +// smtpListener.Events +// dbListener.Events] +// [1; 1; 1; 0; 0] "value") +// +// testCase "Does not raise duplicates of parent Changed events even though several children changed" (fun _ -> +// let settings = Settings() +// let rootListener = Listener settings.Changed +// let mailListener = Listener settings.Mail.Changed +// let pop3Listener = Listener settings.Mail.Pop3.Changed +// let smtpListener = Listener settings.Mail.Smtp.Changed +// +// settings.LoadText """ +// Mail: +// Smtp: +// Port: 4430 +// Pop3: +// CheckPeriod: 00:02:00 +// """ +// Expect.sequenceEqual +// [rootListener.Events +// mailListener.Events +// pop3Listener.Events +// smtpListener.Events] +// [1; 1; 1; 1] "value") +// ] +// +//type Lists = YamlConfig<"Lists.yaml"> +// +//let [] listTests = +// testList "Yaml Config Provider tests - lists" (Seq.toList <| +// testFixture (fun f () -> f (Lists())) [ +// "Can load sequence of maps (single item)", fun settings -> +// settings.LoadText """ +// items: +// - part_no: Test +// descrip: Some description +// price: 347 +// quantity: 14 +// """ +// Expect.equal settings.items.Count 1 "value" +// Expect.equal settings.items.[0].part_no "Test" "value" +// Expect.equal settings.items.[0].descrip "Some description" "value" +// Expect.equal settings.items.[0].quantity 14 "value" +// +// "Can load sequence of maps (multiple items)", fun settings -> +// settings.LoadText """ +// items: +// - part_no: Test +// descrip: Some description +// price: 347 +// quantity: 14 +// - part_no: A4786 +// descrip: Water Bucket (Filled) +// price: 147 +// quantity: 4 +// +// - part_no: E1628 +// descrip: High Heeled "Ruby" Slippers +// size: 8 +// price: 10027 +// quantity: 1 +// """ +// Expect.equal settings.items.Count 3 "value" +// Expect.equal settings.items.[0].part_no "Test" "value" +// Expect.equal settings.items.[0].descrip "Some description" "value" +// Expect.equal settings.items.[0].quantity 14 "value" +// +// Expect.equal settings.items.[2].part_no "E1628" "value" +// Expect.equal settings.items.[2].descrip "High Heeled \"Ruby\" Slippers" "value" +// Expect.equal settings.items.[2].quantity 1 "value" +// +// "Can load nested lists", fun settings -> +// settings.LoadText """ +// Fix82: +// id: "myApp" +// constraints: +// - +// - "attribute" +// - "OPERATOR" +// - "value" +// - +// - "field" +// - "OP" +// labels: +// environment: "staging" +// """ +// Expect.equal settings.Fix82.constraints.Count 2 "value" +// Expect.equal settings.Fix82.constraints.[0].Count 3 "value" +// Expect.equal settings.Fix82.constraints.[0].[0] "attribute" "value" +// Expect.equal settings.Fix82.constraints.[0].[1] "OPERATOR" "value" +// Expect.equal settings.Fix82.constraints.[0].[2] "value" "value" +// Expect.equal settings.Fix82.constraints.[1].Count 2 "value" +// Expect.equal settings.Fix82.constraints.[1].[0] "field" "value" +// Expect.equal settings.Fix82.constraints.[1].[1] "OP" "value" +// +// //"Check that list defaults are OK", fun settings -> +// // Expect.equal settings.items.Count 2 "value" +// // Expect.equal settings.Archive.Count 3 "value" +// ]) +// +//type NumericKeys = YamlConfig +// +//type MixedTypes = YamlConfig +// +//let [] numericTests = +// testList "Yaml Config Provider - numeric tests" [ +// testCase "Numeric map keys are OK" (fun _ -> +// let sut = NumericKeys() +// Expect.equal sut.``1`` 10 "value" +// Expect.equal sut.``2`` 20 "value" +// Expect.equal sut.``3a`` "foo" "value") +// +// testCase "Mixed types are read as strings" (fun _ -> +// let mt = MixedTypes() +// mt.LoadText(""" +// Items: +// - Item: asdf +// - Item: http://fsharp.org +// - Item: 14 +// """) +// Expect.equal mt.Items.[0].Item "asdf" "value" +// Expect.equal mt.Items.[1].Item "http://fsharp.org/" "value" +// Expect.equal mt.Items.[2].Item "14" "value") +// ] \ No newline at end of file diff --git a/tests/FSharp.Configuration.Tests/app.config b/tests/FSharp.Configuration.Tests/app.config index 035347c1..e211e467 100644 --- a/tests/FSharp.Configuration.Tests/app.config +++ b/tests/FSharp.Configuration.Tests/app.config @@ -57,11 +57,6 @@ - - True - - -