diff --git a/build-everything.proj b/build-everything.proj index 34b2eb335d8..8341ed59621 100644 --- a/build-everything.proj +++ b/build-everything.proj @@ -61,7 +61,7 @@ - + diff --git a/build.cmd b/build.cmd index 2a86730556c..bd86cc75fb3 100644 --- a/build.cmd +++ b/build.cmd @@ -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 @@ -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! diff --git a/src/fsharp/FSharp.Build/WriteCodeFragment.fs b/src/fsharp/FSharp.Build/WriteCodeFragment.fs index 1002a489b10..a36193da547 100644 --- a/src/fsharp/FSharp.Build/WriteCodeFragment.fs +++ b/src/fsharp/FSharp.Build/WriteCodeFragment.fs @@ -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 @@ -73,7 +73,11 @@ type WriteCodeFragment() = | (0, _) -> combinedNamedParameters // only named arguments | (_, 0) -> combinedOrderedParameters // only positional arguments | (_, _) -> combinedOrderedParameters + ", " + combinedNamedParameters // both positional and named arguments - sprintf "[]" attributeName args + match language.ToLowerInvariant() with + | "f#" -> sprintf "[]" attributeName args + | "c#" -> sprintf "[assembly: %s(%s)]" attributeName args + | "vb" -> sprintf "" 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 @@ -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 = @"// + let boilerplate = + match _language.ToLowerInvariant() with + | "f#" -> "// \n// Generated by the FSharp WriteCodeFragment class.\n// \nnamespace FSharp\n\nopen System\nopen System.Reflection\n" + | "c#" -> "// \n// Generated by the FSharp WriteCodeFragment class.\n// \n\nusing System;\nusing System.Reflection;" + | "vb" -> "'------------------------------------------------------------------------------\n' \n' Generated by the FSharp WriteCodeFragment class.\n' \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 @@ -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 diff --git a/tests/FSharp.Build.UnitTests/WriteCodeFragmentTests.fs b/tests/FSharp.Build.UnitTests/WriteCodeFragmentTests.fs index 70800400d27..977c265be01 100644 --- a/tests/FSharp.Build.UnitTests/WriteCodeFragmentTests.fs +++ b/tests/FSharp.Build.UnitTests/WriteCodeFragmentTests.fs @@ -8,12 +8,12 @@ open Microsoft.FSharp.Build open NUnit.Framework [] -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 = "[]" Assert.AreEqual(fullExpectedAttributeText, actualAttributeText) @@ -37,3 +37,68 @@ type WriteCodeFragmentTests()= member this.``Escaped string parameters``() = verifyAttribute "SomeAttribute" [("_Parameter1", "\"uno\"")] "SomeAttribute(\"\\\"uno\\\"\")" // this should look like: SomeAttribute("\"uno\"") + + +[] +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) + + [] + member this.``No parameters``() = + verifyAttribute "SomeAttribute" [] "SomeAttribute()" + + [] + member this.``Skipped and out of order positional parameters``() = + verifyAttribute "SomeAttribute" [("_Parameter3", "3"); ("_Parameter5", "5"); ("_Parameter2", "2")] "SomeAttribute(null, \"2\", \"3\", null, \"5\")" + + [] + member this.``Named parameters``() = + verifyAttribute "SomeAttribute" [("One", "1"); ("Two", "2")] "SomeAttribute(One = \"1\", Two = \"2\")" + + [] + member this.``Named and positional parameters``() = + verifyAttribute "SomeAttribute" [("One", "1"); ("_Parameter2", "2.2"); ("Two", "2")] "SomeAttribute(null, \"2.2\", One = \"1\", Two = \"2\")" + + [] + member this.``Escaped string parameters``() = + verifyAttribute "SomeAttribute" [("_Parameter1", "\"uno\"")] "SomeAttribute(\"\\\"uno\\\"\")" + // this should look like: SomeAttribute("\"uno\"") + + +[] +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 = "" + Assert.AreEqual(fullExpectedAttributeText, actualAttributeText) + + [] + member this.``No parameters``() = + verifyAttribute "SomeAttribute" [] "SomeAttribute()" + + [] + member this.``Skipped and out of order positional parameters``() = + verifyAttribute "SomeAttribute" [("_Parameter3", "3"); ("_Parameter5", "5"); ("_Parameter2", "2")] "SomeAttribute(null, \"2\", \"3\", null, \"5\")" + + [] + member this.``Named parameters``() = + verifyAttribute "SomeAttribute" [("One", "1"); ("Two", "2")] "SomeAttribute(One = \"1\", Two = \"2\")" + + [] + member this.``Named and positional parameters``() = + verifyAttribute "SomeAttribute" [("One", "1"); ("_Parameter2", "2.2"); ("Two", "2")] "SomeAttribute(null, \"2.2\", One = \"1\", Two = \"2\")" + + [] + member this.``Escaped string parameters``() = + verifyAttribute "SomeAttribute" [("_Parameter1", "\"uno\"")] "SomeAttribute(\"\\\"uno\\\"\")" + // this should look like: SomeAttribute("\"uno\"") +