Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build-everything.proj
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@

<!-- +++++++++++++++++++++++ Project selection for testing +++++++++++++++++++++++++++++++ -->

<ItemGroup Condition="'$(TEST_NET40_COREUNIT_SUITE)'=='1'" >
<ItemGroup Condition="'$(TEST_NET40_COMPILERUNIT_SUITE)'=='1'" >
<ProjectsWithNet40 Include="tests/FSharp.Core.UnitTests/FSharp.Core.Unittests.fsproj"/>
<ProjectsWithNet40 Include="tests/FSharp.Build.UnitTests/FSharp.Build.UnitTests.fsproj"/>
</ItemGroup>
Expand Down
35 changes: 23 additions & 12 deletions build.cmd
Original file line number Diff line number Diff line change
Expand Up @@ -841,7 +841,7 @@ echo SNEXE32: %SNEXE32%
echo SNEXE64: %SNEXE64%
echo

if "%TEST_NET40_COMPILERUNIT_SUITE%" == "0" if "%TEST_FCS%" == "0" if "%TEST_NET40_COREUNIT_SUITE%" == "0" if "%TEST_CORECLR_COREUNIT_SUITE%" == "0" if "%TEST_VS_IDEUNIT_SUITE%" == "0" if "%TEST_NET40_FSHARP_SUITE%" == "0" if "%TEST_NET40_FSHARPQA_SUITE%" == "0" goto :success
if "%TEST_NET40_COMPILERUNIT_SUITE%" == "0" if "%TEST_FCS%" == "0" if "%TEST_NET40_COREUNIT_SUITE%" == "0" if "TEST_CORECLR_FSHARP_SUITE" == "0" if "%TEST_CORECLR_COREUNIT_SUITE%" == "0" if "%TEST_VS_IDEUNIT_SUITE%" == "0" if "%TEST_NET40_FSHARP_SUITE%" == "0" if "%TEST_NET40_FSHARPQA_SUITE%" == "0" goto :success

if "%no_test%" == "1" goto :success

Expand Down Expand Up @@ -996,38 +996,49 @@ if "%TEST_NET40_COMPILERUNIT_SUITE%" == "1" (
echo -----------------------------------------------------------------
goto :failure
)
)

REM ---------------- net40-coreunit -----------------------

if "%TEST_NET40_COREUNIT_SUITE%" == "1" (

set OUTPUTARG=
set ERRORARG=
set OUTPUTFILE=
set ERRORFILE=
set XMLFILE=!RESULTSDIR!\test-net40-coreunit-results.xml
set XMLFILE=!RESULTSDIR!\test-net40-buildunit-results.xml
if "%CI%" == "1" (
set ERRORFILE=!RESULTSDIR!\test-net40-coreunit-errors.log
set OUTPUTFILE=!RESULTSDIR!\test-net40-coreunit-output.log
set OUTPUTFILE=!RESULTSDIR!\test-net40-buildunit-output.log
set ERRORFILE=!RESULTSDIR!\test-net40-buildunit-errors.log
set ERRORARG=--err:"!ERRORFILE!"
set OUTPUTARG=--output:"!OUTPUTFILE!"
)

set ERRORFILE=!RESULTSDIR!\test-net40-buildunit-errors.log
echo "!NUNIT3_CONSOLE!" --verbose --framework:V4.0 --result:"!XMLFILE!;format=nunit3" !OUTPUTARG! !ERRORARG! --work:"!FSCBINPATH!" "!FSCBINPATH!\FSharp.Build.UnitTests.dll" !WHERE_ARG_NUNIT!
"!NUNIT3_CONSOLE!" --verbose --framework:V4.0 --result:"!XMLFILE!;format=nunit3" !OUTPUTARG! !ERRORARG! --work:"!FSCBINPATH!" "!FSCBINPATH!\FSharp.Build.UnitTests.dll" !WHERE_ARG_NUNIT!


if errorlevel 1 (
echo -----------------------------------------------------------------
type "!OUTPUTFILE!"
echo -----------------------------------------------------------------
type "!ERRORFILE!"
echo -----------------------------------------------------------------
echo Error: Running tests net40-coreunit failed, see logs above -- FAILED
echo Error: Running tests net40-compilernit failed, see logs above -- FAILED
echo -----------------------------------------------------------------
goto :failure
)
)

REM ---------------- net40-coreunit -----------------------

if "%TEST_NET40_COREUNIT_SUITE%" == "1" (

set OUTPUTARG=
set ERRORARG=
set OUTPUTFILE=
set ERRORFILE=
set XMLFILE=!RESULTSDIR!\test-net40-coreunit-results.xml
if "%CI%" == "1" (
set ERRORFILE=!RESULTSDIR!\test-net40-coreunit-errors.log
set OUTPUTFILE=!RESULTSDIR!\test-net40-coreunit-output.log
set ERRORARG=--err:"!ERRORFILE!"
set OUTPUTARG=--output:"!OUTPUTFILE!"
)

echo "!NUNIT3_CONSOLE!" --verbose --framework:V4.0 --result:"!XMLFILE!;format=nunit3" !OUTPUTARG! !ERRORARG! --work:"!FSCBINPATH!" "!FSCBINPATH!\FSharp.Core.UnitTests.dll" !WHERE_ARG_NUNIT!
"!NUNIT3_CONSOLE!" --verbose --framework:V4.0 --result:"!XMLFILE!;format=nunit3" !OUTPUTARG! !ERRORARG! --work:"!FSCBINPATH!" "!FSCBINPATH!\FSharp.Core.UnitTests.dll" !WHERE_ARG_NUNIT!
Expand Down
31 changes: 21 additions & 10 deletions src/fsharp/FSharp.Build/WriteCodeFragment.fs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ type WriteCodeFragment() =
| _ -> sb.Append(c)) (StringBuilder().Append("\""))
sb.Append("\"").ToString()

static member GenerateAttribute (item:ITaskItem) =
static member GenerateAttribute (item:ITaskItem, language:string) =
let attributeName = item.ItemSpec
let args =
// mimicking the behavior from https://github.com/Microsoft/msbuild/blob/70ce7e9ccb891b63f0859f1f7f0b955693ed3742/src/Tasks/WriteCodeFragment.cs#L355-L415
Expand Down Expand Up @@ -73,7 +73,11 @@ type WriteCodeFragment() =
| (0, _) -> combinedNamedParameters // only named arguments
| (_, 0) -> combinedOrderedParameters // only positional arguments
| (_, _) -> combinedOrderedParameters + ", " + combinedNamedParameters // both positional and named arguments
sprintf "[<assembly: %s(%s)>]" attributeName args
match language.ToLowerInvariant() with
| "f#" -> sprintf "[<assembly: %s(%s)>]" attributeName args
| "c#" -> sprintf "[assembly: %s(%s)]" attributeName args
| "vb" -> sprintf "<Assembly: %s(%s)>" attributeName args
| _ -> failwith "Language name must be one of F#, C# or VB"

// adding this property to maintain API equivalence with the MSBuild task
member this.Language
Expand All @@ -93,27 +97,32 @@ type WriteCodeFragment() =
with get() = _outputFile
and set(value) = _outputFile <- value


interface ITask with
member this.BuildEngine
with get() = _buildEngine
and set(value) = _buildEngine <- value

member this.HostObject
with get() = _hostObject
and set(value) = _hostObject <- value

member this.Execute() =
try
if isNull _outputFile && isNull _outputDirectory then failwith "Output location must be specified"
if _language.ToLowerInvariant() <> "f#" then failwith "Language name must be F#"
let boilerplate = @"// <auto-generated>
let boilerplate =
match _language.ToLowerInvariant() with
| "f#" -> "// <auto-generated>\n// Generated by the FSharp WriteCodeFragment class.\n// </auto-generated>\nnamespace FSharp\n\nopen System\nopen System.Reflection\n"
| "c#" -> "// <auto-generated>\n// Generated by the FSharp WriteCodeFragment class.\n// </auto-generated>\n\nusing System;\nusing System.Reflection;"
| "vb" -> "'------------------------------------------------------------------------------\n' <auto-generated>\n' Generated by the FSharp WriteCodeFragment class.\n' </auto-generated>\n'------------------------------------------------------------------------------\n\nOption Strict Off\nOption Explicit On\n\nImports System\nImports System.Reflection"
| _ -> failwith "Language name must be one of F#, C# or VB"

namespace FSharp

open System
open System.Reflection"
let sb = StringBuilder().AppendLine(boilerplate).AppendLine()
let code = Array.fold (fun (sb:StringBuilder) (item:ITaskItem) -> sb.AppendLine(WriteCodeFragment.GenerateAttribute item)) sb _assemblyAttributes
code.AppendLine().AppendLine("do()") |> ignore
let code = Array.fold (fun (sb:StringBuilder) (item:ITaskItem) -> sb.AppendLine(WriteCodeFragment.GenerateAttribute (item, _language.ToLowerInvariant()))) sb _assemblyAttributes

if _language.ToLowerInvariant() = "f#" then code.AppendLine("do()") |> ignore
let fileName = _outputFile.ItemSpec

let outputFileItem =
if not (isNull _outputFile) && not (isNull _outputDirectory) && not (Path.IsPathRooted(fileName)) then
TaskItem(Path.Combine(_outputDirectory.ItemSpec, fileName)) :> ITaskItem
Expand All @@ -122,12 +131,14 @@ open System.Reflection"
TaskItem(tempFile) :> ITaskItem
else
_outputFile

let codeText = code.ToString()
let alreadyExists = (try File.Exists fileName && File.ReadAllText(fileName) = codeText with _ -> false)
if not alreadyExists then
File.WriteAllText(fileName, codeText)
_outputFile <- outputFileItem
true

with e ->
printf "Error writing code fragment: %s" (e.ToString())
false
69 changes: 67 additions & 2 deletions tests/FSharp.Build.UnitTests/WriteCodeFragmentTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ open Microsoft.FSharp.Build
open NUnit.Framework

[<TestFixture>]
type WriteCodeFragmentTests()=
type WriteCodeFragmentFSharpTests() =

let verifyAttribute (attributeName:string) (parameters:(string*string) list) (expectedAttributeText:string) =
let taskItem = TaskItem(attributeName)
parameters |> List.iter (fun (key, value) -> taskItem.SetMetadata(key, value))
let actualAttributeText = WriteCodeFragment.GenerateAttribute (taskItem :> ITaskItem)
let actualAttributeText = WriteCodeFragment.GenerateAttribute (taskItem :> ITaskItem, "f#")
let fullExpectedAttributeText = "[<assembly: " + expectedAttributeText + ">]"
Assert.AreEqual(fullExpectedAttributeText, actualAttributeText)

Expand All @@ -37,3 +37,68 @@ type WriteCodeFragmentTests()=
member this.``Escaped string parameters``() =
verifyAttribute "SomeAttribute" [("_Parameter1", "\"uno\"")] "SomeAttribute(\"\\\"uno\\\"\")"
// this should look like: SomeAttribute("\"uno\"")


[<TestFixture>]
type WriteCodeFragmentCSharpTests() =

let verifyAttribute (attributeName:string) (parameters:(string*string) list) (expectedAttributeText:string) =
let taskItem = TaskItem(attributeName)
parameters |> List.iter (fun (key, value) -> taskItem.SetMetadata(key, value))
let actualAttributeText = WriteCodeFragment.GenerateAttribute (taskItem :> ITaskItem, "c#")
let fullExpectedAttributeText = "[assembly: " + expectedAttributeText + "]"
Assert.AreEqual(fullExpectedAttributeText, actualAttributeText)

[<Test>]
member this.``No parameters``() =
verifyAttribute "SomeAttribute" [] "SomeAttribute()"

[<Test>]
member this.``Skipped and out of order positional parameters``() =
verifyAttribute "SomeAttribute" [("_Parameter3", "3"); ("_Parameter5", "5"); ("_Parameter2", "2")] "SomeAttribute(null, \"2\", \"3\", null, \"5\")"

[<Test>]
member this.``Named parameters``() =
verifyAttribute "SomeAttribute" [("One", "1"); ("Two", "2")] "SomeAttribute(One = \"1\", Two = \"2\")"

[<Test>]
member this.``Named and positional parameters``() =
verifyAttribute "SomeAttribute" [("One", "1"); ("_Parameter2", "2.2"); ("Two", "2")] "SomeAttribute(null, \"2.2\", One = \"1\", Two = \"2\")"

[<Test>]
member this.``Escaped string parameters``() =
verifyAttribute "SomeAttribute" [("_Parameter1", "\"uno\"")] "SomeAttribute(\"\\\"uno\\\"\")"
// this should look like: SomeAttribute("\"uno\"")


[<TestFixture>]
type WriteCodeFragmentVisualBasicTests() =

let verifyAttribute (attributeName:string) (parameters:(string*string) list) (expectedAttributeText:string) =
let taskItem = TaskItem(attributeName)
parameters |> List.iter (fun (key, value) -> taskItem.SetMetadata(key, value))
let actualAttributeText = WriteCodeFragment.GenerateAttribute (taskItem :> ITaskItem, "vb")
let fullExpectedAttributeText = "<Assembly: " + expectedAttributeText + ">"
Assert.AreEqual(fullExpectedAttributeText, actualAttributeText)

[<Test>]
member this.``No parameters``() =
verifyAttribute "SomeAttribute" [] "SomeAttribute()"

[<Test>]
member this.``Skipped and out of order positional parameters``() =
verifyAttribute "SomeAttribute" [("_Parameter3", "3"); ("_Parameter5", "5"); ("_Parameter2", "2")] "SomeAttribute(null, \"2\", \"3\", null, \"5\")"

[<Test>]
member this.``Named parameters``() =
verifyAttribute "SomeAttribute" [("One", "1"); ("Two", "2")] "SomeAttribute(One = \"1\", Two = \"2\")"

[<Test>]
member this.``Named and positional parameters``() =
verifyAttribute "SomeAttribute" [("One", "1"); ("_Parameter2", "2.2"); ("Two", "2")] "SomeAttribute(null, \"2.2\", One = \"1\", Two = \"2\")"

[<Test>]
member this.``Escaped string parameters``() =
verifyAttribute "SomeAttribute" [("_Parameter1", "\"uno\"")] "SomeAttribute(\"\\\"uno\\\"\")"
// this should look like: SomeAttribute("\"uno\"")