1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
|
namespace MonoDevelopTests
open System
open System.IO
open System.Reflection
open System.Runtime.CompilerServices
open System.Threading.Tasks
open FsUnit
open Microsoft.FSharp.Compiler.SourceCodeServices
open MonoDevelop.Core
open MonoDevelop.Core.ProgressMonitoring
open MonoDevelop.FSharp
open MonoDevelop.Ide
open MonoDevelop.Ide.Projects
open MonoDevelop.Ide.Templates
open MonoDevelop.PackageManagement.Tests.Helpers
open MonoDevelop.Projects
open MonoDevelop.Projects.MSBuild
open MonoDevelop.FSharp.Shared
open NUnit.Framework
[<TestFixture>]
type ``Template tests``() =
inherit UnitTests.TestBase()
let toTask computation : Task = Async.StartAsTask computation :> _
let monitor = UnitTests.Util.GetMonitor ()
do
FixtureSetup.initialiseMonoDevelop()
let getField name =
typeof<IdeApp>.GetField(name, BindingFlags.NonPublic ||| BindingFlags.Static)
let workspace = getField "workspace"
workspace.SetValue(null, new RootWorkspace())
let workbench = getField "workbench"
workbench.SetValue(null, new MonoDevelop.Ide.Gui.Workbench())
let templateService = TemplatingService()
let templateMatch (template:SolutionTemplate) =
template.IsMatch (SolutionTemplateVisibility.All)
let predicate = new Predicate<SolutionTemplate>(templateMatch)
let rec flattenCategories (category: TemplateCategory) =
seq {
yield category
yield! category.Categories |> Seq.collect flattenCategories
}
let solutionTemplates =
templateService.GetProjectTemplateCategories (predicate)
|> Seq.collect flattenCategories
|> Seq.collect(fun c -> c.Templates)
|> Seq.choose(fun s -> s.GetTemplate("F#") |> Option.ofObj)
|> Seq.filter(fun t -> t.Id.IndexOf("SharedAssets") = -1) // shared assets projects can't be built standalone
|> List.ofSeq
let templatesDir = UnitTests.Util.TmpDir / "fsharp-buildtemplates"
let getErrorsForProject (solution:Solution) =
asyncSeq {
let config = solution.DefaultConfigurationSelector
let ctx = TargetEvaluationContext (LogVerbosity=MSBuildVerbosity.Quiet)
let! result = solution.Build(monitor, config, ctx) |> Async.AwaitTask
match result.HasWarnings, result.HasErrors with
//| "Xamarin.tvOS.FSharp.SingleViewApp", _, false //MTOUCH : warning MT0094: Both profiling (--profiling) and incremental builds (--fastdev) is not supported when building for tvOS. Incremental builds have ben disabled.]
| false, false ->
// xbuild worked, now check for editor squiggles
let projects =
solution.Items
|> Seq.ofType<DotNetProject> |> List.ofSeq
for project in projects do
let checker = FSharpChecker.Create()
let! refs = project.GetReferences (config) |> Async.AwaitTask
let projectOptions = languageService.GetProjectOptionsFromProjectFile project config refs
let! checkResult = checker.ParseAndCheckProject projectOptions.Value
for error in checkResult.Errors do
yield "Editor error", error.FileName, error.Message
| _ ->
for error in result.Errors do
if not error.IsWarning then
yield "Build error", error.FileName, error.ErrorText
}
let testWithParameters (tt:string) (buildFolder:string) (parameters:string) =
if not MonoDevelop.Core.Platform.IsMac then
Assert.Ignore ()
toTask <| async {
let projectTemplate = ProjectTemplate.ProjectTemplates |> Seq.find (fun t -> t.Id = tt)
let dir = FilePath (templatesDir/buildFolder)
dir.Delete()
Directory.CreateDirectory (dir |> string) |> ignore
let cinfo = new ProjectCreateInformation (ProjectBasePath = dir, ProjectName = tt, SolutionName = tt, SolutionPath = dir)
cinfo.Parameters.["CreateSharedAssetsProject"] <- "False"
cinfo.Parameters.["CreatePortableDotNetProject"] <- "True"
cinfo.Parameters.["CreateMonoTouchProject"] <- "True"
cinfo.Parameters.["UseXamarinAndroidSupportv7AppCompat"] <- "True"
cinfo.Parameters.["CreateAndroidProject"] <- "True"
cinfo.Parameters.["UseUniversal"] <- "True"
cinfo.Parameters.["UseIPad"] <- "False"
cinfo.Parameters.["UseIPhone"] <- "False"
cinfo.Parameters.["CreateiOSUITest"] <- "False"
cinfo.Parameters.["CreateAndroidUITest"] <- "False"
cinfo.Parameters.["MinimumOSVersion"] <- "10.7"
cinfo.Parameters.["AppIdentifier"] <- tt
cinfo.Parameters.["AndroidMinSdkVersionAttribute"] <- "android:minSdkVersion=\"27\""
cinfo.Parameters.["AndroidThemeAttribute"] <- ""
for templateParameter in TemplateParameter.CreateParameters (parameters) do
cinfo.Parameters.[templateParameter.Name] <- templateParameter.Value
let! item = projectTemplate.CreateWorkspaceItem (cinfo) |> Async.AwaitTask
use sln = item :?> Solution
let createTemplate (template:SolutionTemplate) =
let config = NewProjectConfiguration(
CreateSolution = false,
ProjectName = tt,
SolutionName = tt,
Location = (dir |> string)
)
templateService.ProcessTemplate(template, config, sln.RootFolder)
let folder = new SolutionFolder()
let solutionTemplate =
solutionTemplates
|> Seq.find(fun t -> t.Id = tt)
let projects = sln.Items |> Seq.filter(fun i -> i :? DotNetProject) |> Seq.cast<DotNetProject> |> List.ofSeq
// Save solution before installing NuGet packages to prevent any Imports from being added
// in the wrong place. Android projects now use the Xamarin.Build.Download NuGet package which
// will add its own .props Import at the top of the project file. Saving the project the first time
// after installing this NuGet package results in the Xamarin.Android.FSharp.targets Import being
// added at the top of the project which causes a compile error about the OutputType not being defined.
// This is because the Import is grouped with the Xamarin.Build.Download .props Import which is inserted
// at the top of the project file.
do! sln.SaveAsync(monitor)
do! NuGetPackageInstaller.InstallPackages (sln, projectTemplate.PackageReferencesForCreatedProjects)
let errors = getErrorsForProject sln |> AsyncSeq.toSeq |> List.ofSeq
match errors with
| [] -> Assert.Pass()
| errors -> Assert.Fail (sprintf "%A" errors)
}
let test templateId = testWithParameters templateId templateId ""
[<TestFixtureSetUp>]
member x.Setup() =
let config =
"""
<configuration>
<config>
<add key="repositoryPath" value="packages" />
</config>
<packageSources>
<clear /> <!-- ensure only the sources defined below are used -->
<add key="NuGet official package source" value="https://api.nuget.org/v3/index.json" />
</packageSources>
</configuration>
"""
Directory.CreateDirectory templatesDir |> ignore
let configFileName = templatesDir/"NuGet.Config"
File.WriteAllText (configFileName, config, Text.Encoding.UTF8)
// HACK: Work around issue in "Xamarin Forms FSharp ClassLibrary" test
// the template is broken and doesn't define a framework, so gets the default net45
// however the base tests UnitTests.TestBase change the default to net40 resulting in
//"Could not install package 'FSharp.Core 4.3.3'. You are trying to install this package into a project that targets '.NETFramework,Version=v4.0',"
MonoDevelop.Projects.Services.ProjectService.DefaultTargetFramework
<- Runtime.SystemAssemblyService.GetTargetFramework (MonoDevelop.Core.Assemblies.TargetFrameworkMoniker.NET_4_5);
[<Test;AsyncStateMachine(typeof<Task>)>]
member x.``FSharp portable project``() =
async {
let name = "FSharpPortableLibrary"
let projectTemplate = ProjectTemplate.ProjectTemplates |> Seq.find (fun t -> t.Id = name)
let dir = FilePath (templatesDir/"fsportable")
dir.Delete()
let cinfo = new ProjectCreateInformation (ProjectBasePath = dir, ProjectName = name, SolutionName = name, SolutionPath = dir)
let! item = projectTemplate.CreateWorkspaceItem (cinfo) |> Async.AwaitTask
let sln = item :?> Solution
let proj = sln.Items.[0] :?> FSharpProject
proj.IsPortableLibrary |> should equal true
} |> toTask
[<Test;AsyncStateMachine(typeof<Task>)>]
member x.``Can build netcoreapp11 MVC web app``()=
async {
let projectPath = UnitTests.Util.GetSampleProject ("fsharp-aspnetcoremvc11", "aspnetcoremvc11.sln")
let! w = Services.ProjectService.ReadWorkspaceItem (monitor, FilePath(projectPath)) |> Async.AwaitTask
use solution = w :?> Solution
let project =
solution.Items
|> Seq.ofType<DotNetProject>
|> Seq.head
let! res = project.RunTarget(monitor, "Restore", ConfigurationSelector.Default)
do! project.ReevaluateProject (monitor)
let fsharpFiles =
project.Files
|> Seq.filter(fun f -> f.FilePath.Extension = ".fs")
|> Seq.map(fun f -> f.IsImported)
fsharpFiles |> Seq.length |> should equal 3
fsharpFiles |> Seq.iter(fun imported -> imported |> should equal false)
let wwwrootFiles =
project.Files
|> Seq.filter(fun f -> f.FilePath.ToString().Contains("wwwroot"))
|> Seq.map(fun f -> f.IsImported)
wwwrootFiles |> Seq.length |> should equal 41
wwwrootFiles |> Seq.iter(fun imported -> imported |> should equal true)
let errors = getErrorsForProject solution |> AsyncSeq.toSeq |> List.ofSeq
match errors with
| [] -> Assert.Pass()
| errors -> Assert.Fail (sprintf "%A" errors)
} |> toTask
[<Ignore("Currently not testable as SDK project is dependent on wizard being ran");AsyncStateMachine(typeof<Task>)>]member x.``Xamarin Forms FSharp FormsApp``()= testWithParameters "Xamarin.Forms.FSharp.FormsApp" "Xamarin.Forms.FSharp.FormsApp" "SafeUserDefinedProjectName=Xamarin_Forms_FSharp_FormsApp_Shared"
[<Test;AsyncStateMachine(typeof<Task>)>]member x.``FSharpPortableLibrary``()= test "FSharpPortableLibrary"
[<Test;AsyncStateMachine(typeof<Task>)>]member x.``Xamarin Forms FSharp ClassLibrary``()= test "Xamarin.Forms.FSharp.ClassLibrary"
[<Test;AsyncStateMachine(typeof<Task>)>]member x.``Xamarin Forms FSharp UITestApp-Mac``()= test "Xamarin.Forms.FSharp.UITestApp-Mac"
[<Test;AsyncStateMachine(typeof<Task>)>]member x.``Xamarin iOS FSharp SingleViewApp``()= test "Xamarin.iOS.FSharp.SingleViewApp"
[<Test;AsyncStateMachine(typeof<Task>)>]member x.``Xamarin iOS FSharp ClassLibrary``()= test "Xamarin.iOS.FSharp.ClassLibrary"
[<Test;AsyncStateMachine(typeof<Task>)>]member x.``Xamarin iOS FSharp UnitTestsApp``()= test "Xamarin.iOS.FSharp.UnitTestsApp"
[<Test;AsyncStateMachine(typeof<Task>)>]member x.``Xamarin Android FSharp AndroidApp``()= test "Xamarin.Android.FSharp.AndroidApp"
[<Test;AsyncStateMachine(typeof<Task>)>]member x.``Xamarin Android FSharp OpenGLGame``()= test "Xamarin.Android.FSharp.OpenGLGame"
[<Test;AsyncStateMachine(typeof<Task>)>]member x.``Xamarin Android FSharp ClassLibrary``()= test "Xamarin.Android.FSharp.ClassLibrary"
[<Test;AsyncStateMachine(typeof<Task>)>]member x.``Xamarin Android FSharp UnitTestApp``()= test "Xamarin.Android.FSharp.UnitTestApp"
[<Ignore;AsyncStateMachine(typeof<Task>)>]member x.``Xamarin Mac FSharp CocoaApp-XIB``()= test "Xamarin.Mac.FSharp.CocoaApp-XIB"
[<Test;AsyncStateMachine(typeof<Task>)>]member x.``Xamarin Mac FSharp ClassLibrary``()= test "Xamarin.Mac.FSharp.ClassLibrary"
[<Test;AsyncStateMachine(typeof<Task>)>]member x.``Xamarin tvOS FSharp SingleViewApp``()= test "Xamarin.tvOS.FSharp.SingleViewApp"
[<Test;AsyncStateMachine(typeof<Task>)>]member x.``MonoDevelop FSharp ConsoleProject``()= test "MonoDevelop.FSharp.ConsoleProject"
[<Test;AsyncStateMachine(typeof<Task>)>]member x.``FSharpGtkProject``()= test "FSharpGtkProject"
[<Test;AsyncStateMachine(typeof<Task>)>]member x.``MonoDevelop FSharp LibraryProject``()= test "MonoDevelop.FSharp.LibraryProject"
[<Test;AsyncStateMachine(typeof<Task>)>]member x.``FSharpNUnitLibraryProject``()= test "FSharpNUnitLibraryProject"
[<Test;AsyncStateMachine(typeof<Task>)>]
member x.``Xamarin Forms FSharp FormsApp Shared``() =
testWithParameters "Xamarin.Forms.FSharp.FormsApp" "Xamarin.Forms.FSharp.FormsApp.Shared" "SafeUserDefinedProjectName=Xamarin_Forms_FSharp_FormsApp_Shared;CreateSharedAssetsProject=True;CreatePortableDotNetProject=False"
[<Test;AsyncStateMachine(typeof<Task>)>]
member x.``Xamarin Forms FSharp FormsApp Shared with XAML``() =
testWithParameters "Xamarin.Forms.FSharp.FormsApp" "Xamarin.Forms.FSharp.FormsApp.Shared.XAML" "CreateXamlProject=True;SafeUserDefinedProjectName=Xamarin_Forms_FSharp_FormsApp_Shared_XAML;CreateSharedAssetsProject=True;CreatePortableDotNetProject=False"
|