diff --git a/Dockerfile b/Dockerfile index bf5b7d7..8a82b39 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:7.0.401-alpine3.18-amd64 AS build +FROM mcr.microsoft.com/dotnet/sdk:8.0.201-alpine3.19-amd64 AS build WORKDIR /tmp @@ -19,6 +19,7 @@ RUN dotnet add package FsCheck -v 2.16.3 RUN dotnet add package FsCheck.Xunit -v 2.14.3 RUN dotnet add package FSharp.Core -v 6.0.1 RUN dotnet add package FSharp.Core -v 7.0.400 +RUN dotnet add package FSharp.Core -v 8.0.101 RUN dotnet add package FParsec -v 1.1.1 WORKDIR /app @@ -32,7 +33,7 @@ COPY src/Exercism.TestRunner.FSharp/ ./ RUN dotnet publish -r linux-musl-x64 -c Release -o /opt/test-runner --no-restore --self-contained true # Build runtime image -FROM mcr.microsoft.com/dotnet/sdk:7.0.401-alpine3.18-amd64 AS runtime +FROM mcr.microsoft.com/dotnet/sdk:8.0.201-alpine3.19-amd64 AS runtime WORKDIR /opt/test-runner # Enable rolling forward the .NET SDK used to be backwards-compatible diff --git a/src/Exercism.TestRunner.FSharp/Exercism.TestRunner.FSharp.fsproj b/src/Exercism.TestRunner.FSharp/Exercism.TestRunner.FSharp.fsproj index 5ab531a..3b3ccf5 100644 --- a/src/Exercism.TestRunner.FSharp/Exercism.TestRunner.FSharp.fsproj +++ b/src/Exercism.TestRunner.FSharp/Exercism.TestRunner.FSharp.fsproj @@ -2,7 +2,7 @@ Exe - net7.0 + net8.0 @@ -20,11 +20,10 @@ - - + + - - + diff --git a/src/Exercism.TestRunner.FSharp/Rewrite.fs b/src/Exercism.TestRunner.FSharp/Rewrite.fs index b8566f3..0cf2379 100644 --- a/src/Exercism.TestRunner.FSharp/Rewrite.fs +++ b/src/Exercism.TestRunner.FSharp/Rewrite.fs @@ -3,9 +3,9 @@ module Exercism.TestRunner.FSharp.Rewrite open System.IO open Exercism.TestRunner.FSharp.Core open Exercism.TestRunner.FSharp.Visitor -open FSharp.Compiler.Syntax -open FSharp.Compiler.Text open Fantomas.Core +open Fantomas.FCS.Syntax +open Fantomas.FCS.Text open Fantomas.FCS.Parse type ParseResult = @@ -18,13 +18,6 @@ type RewriteResult = type EnableAllTests() = inherit SyntaxVisitor() - - default this.VisitSynAttributeList(attrs: SynAttributeList) : SynAttributeList = - base.VisitSynAttributeList( - { attrs with - Attributes = - attrs.Attributes - |> List.filter (fun attr -> attr.TypeName.LongIdent.Head.idText <> "Ignore") }) override _.VisitSynAttribute(attr: SynAttribute) : SynAttribute = let isSkipExpr expr = @@ -33,32 +26,42 @@ type EnableAllTests() = | _ -> false match attr.ArgExpr with - | SynExpr.Paren(expr, leftParenRange, rightParenRange, range) -> + | SynExpr.Paren(expr, leftParenRange, rightParenRange, range) -> match expr with - | SynExpr.App _ when isSkipExpr expr -> - let newExpr = SynExpr.Const(SynConst.Unit, attr.ArgExpr.Range) - base.VisitSynAttribute({ attr with ArgExpr = newExpr }) + | SynExpr.App _ when isSkipExpr(expr) -> + let noAttributesArgExpr = SynExpr.Const(SynConst.Unit, attr.ArgExpr.Range) + base.VisitSynAttribute({ attr with ArgExpr = noAttributesArgExpr }) | SynExpr.Tuple(iStruct, exprs, commaRanges, tplRange) -> - let newExpr = - SynExpr.Paren( - SynExpr.Tuple(iStruct, exprs |> List.filter (isSkipExpr >> not), commaRanges, tplRange), leftParenRange, rightParenRange, range) - base.VisitSynAttribute({ attr with ArgExpr = newExpr }) + match List.tryFindIndex isSkipExpr exprs with + | Some index -> + let newExpr = + SynExpr.Paren( + SynExpr.Tuple( + iStruct, + exprs |> List.removeAt index, + commaRanges |> List.removeAt (index - 1), tplRange + ), + leftParenRange, + rightParenRange, + range) + base.VisitSynAttribute({ attr with ArgExpr = newExpr }) + | None -> base.VisitSynAttribute(attr) | _ -> base.VisitSynAttribute(attr) | _ -> base.VisitSynAttribute(attr) let private parseFile (filePath: string) = if File.Exists(filePath) then let source = File.ReadAllText(filePath) - let sourceText = source |> SourceText.ofString - let tree, diagnostics = parseFile false sourceText [] - Some tree // TODO: use diagnostics to determine success + let sourceText = source |> SourceText.ofString + let tree, _ = CodeFormatter.ParseAsync(false, source) |> Async.RunSynchronously |> Array.head + Some tree |> Option.map (fun tree -> ParseSuccess(source, sourceText, tree)) |> Option.defaultValue ParseError else ParseError -let private toCode code tree = - CodeFormatter.FormatASTAsync(tree, code, FormatConfig.FormatConfig.Default) +let private toCode tree = + CodeFormatter.FormatASTAsync(tree) |> Async.RunSynchronously |> SourceText.ofString @@ -67,12 +70,17 @@ let private enableAllTests parsedInput = let private rewriteProjectFile (context: TestRunContext) = let originalProjectFile = File.ReadAllText(context.ProjectFile) - originalProjectFile, originalProjectFile.Replace("net5.0", "net6.0").Replace("net6.0", "net7.0") + let rewrittenProjectFile = + originalProjectFile + .Replace("net5.0", "net8.0") + .Replace("net6.0", "net8.0") + .Replace("net7.0", "net8.0") + originalProjectFile, rewrittenProjectFile let rewriteTests (context: TestRunContext) = match parseFile context.TestsFile with - | ParseSuccess (originalSource, originalSourceText, originalTestTree) -> - let rewrittenTestCode = originalTestTree |> enableAllTests |> toCode originalSource - let (originalProjectFile, rewrittenProjectFile) = rewriteProjectFile context + | ParseSuccess (originalSource, originalSourceText, originalTestTree) -> + let rewrittenTestCode = originalTestTree |> enableAllTests |> toCode + let originalProjectFile, rewrittenProjectFile = rewriteProjectFile context RewriteSuccess(originalSourceText, originalTestTree, rewrittenTestCode, originalProjectFile, rewrittenProjectFile) | ParseError -> RewriteError diff --git a/src/Exercism.TestRunner.FSharp/Testing.fs b/src/Exercism.TestRunner.FSharp/Testing.fs index 1fc2f98..5e44883 100644 --- a/src/Exercism.TestRunner.FSharp/Testing.fs +++ b/src/Exercism.TestRunner.FSharp/Testing.fs @@ -1,6 +1,5 @@ module Exercism.TestRunner.FSharp.Testing -open System open System.Diagnostics open System.IO open System.Text.RegularExpressions @@ -8,8 +7,8 @@ open System.Xml.Serialization open Exercism.TestRunner.FSharp.Core open Exercism.TestRunner.FSharp.Rewrite open Exercism.TestRunner.FSharp.Visitor -open FSharp.Compiler.Syntax -open FSharp.Compiler.Text +open Fantomas.FCS.Syntax +open Fantomas.FCS.Text module String = let normalize (str: string) = str.Replace("\r\n", "\n").Trim() @@ -17,7 +16,7 @@ module String = let isNullOrWhiteSpace = System.String.IsNullOrWhiteSpace module Process = - let exec fileName arguments workingDirectory = + let exec (fileName: string) (arguments: string) workingDirectory = let psi = ProcessStartInfo(fileName, arguments) psi.WorkingDirectory <- workingDirectory psi.RedirectStandardInput <- true @@ -257,7 +256,9 @@ module DotnetCli = let runTests originalTestCode originalTestTree context = let solutionDir = Path.GetDirectoryName(context.TestsFile) - Process.exec "dotnet" $"test --verbosity=quiet --logger \"trx;LogFileName=%s{Path.GetFileName(context.TestResultsFile)}\" /flp:v=q" solutionDir + + Process.exec "dotnet" "restore --source /root/.nuget/packages/" solutionDir + Process.exec "dotnet" $"test --no-restore --verbosity=quiet --logger \"trx;LogFileName=%s{Path.GetFileName(context.TestResultsFile)}\" /flp:v=q" solutionDir let buildErrors = parseBuildErrors context diff --git a/src/Exercism.TestRunner.FSharp/Visitor.fs b/src/Exercism.TestRunner.FSharp/Visitor.fs index fe5069d..ec61a7c 100644 --- a/src/Exercism.TestRunner.FSharp/Visitor.fs +++ b/src/Exercism.TestRunner.FSharp/Visitor.fs @@ -1,22 +1,22 @@ module Exercism.TestRunner.FSharp.Visitor -open FSharp.Compiler.Syntax -open FSharp.Compiler.SyntaxTrivia -open FSharp.Compiler.Text -open FSharp.Compiler.Xml +open Fantomas.FCS.Syntax +open Fantomas.FCS.SyntaxTrivia +open Fantomas.FCS.Text +open Fantomas.FCS.Xml type SyntaxVisitor() = abstract VisitInput: ParsedInput -> ParsedInput default this.VisitInput(input: ParsedInput): ParsedInput = match input with - | ParsedInput.ImplFile(ParsedImplFileInput(file, isScript, qualName, pragmas, hashDirectives, modules, isLastCompiland, trivia)) -> + | ParsedInput.ImplFile(ParsedImplFileInput(file, isScript, qualName, pragmas, hashDirectives, modules, isLastCompiland, trivia, identifiers)) -> ParsedInput.ImplFile (ParsedImplFileInput (file, isScript, qualName, pragmas, hashDirectives, - List.map this.VisitSynModuleOrNamespace modules, isLastCompiland, this.VisitParsedImplFileInputTrivia(trivia))) - | ParsedInput.SigFile(ParsedSigFileInput(file, qualifiedName, pragmas, directives, synModuleOrNamespaceSigs, trivia)) -> - ParsedInput.SigFile(ParsedSigFileInput(file, qualifiedName, pragmas, directives, synModuleOrNamespaceSigs, trivia)) + List.map this.VisitSynModuleOrNamespace modules, isLastCompiland, this.VisitParsedImplFileInputTrivia(trivia), identifiers)) + | ParsedInput.SigFile(ParsedSigFileInput(file, qualifiedName, pragmas, directives, synModuleOrNamespaceSigs, trivia, identifiers)) -> + ParsedInput.SigFile(ParsedSigFileInput(file, qualifiedName, pragmas, directives, synModuleOrNamespaceSigs, trivia, identifiers)) abstract VisitParsedImplFileInputTrivia : ParsedImplFileInputTrivia -> ParsedImplFileInputTrivia default this.VisitParsedImplFileInputTrivia(trivia: ParsedImplFileInputTrivia) = trivia @@ -108,10 +108,10 @@ type SyntaxVisitor() = (this.VisitSynType typ, this.VisitSynExpr expr, leftParenRange, sep, rightParentRange)), copyInfo |> Option.map (fun (expr, opt) -> (this.VisitSynExpr expr, opt)), recordFields |> List.map this.VisitRecordField, range) - | SynExpr.AnonRecd(isStruct, copyInfo, recordFields, range) -> + | SynExpr.AnonRecd(isStruct, copyInfo, recordFields, range, trivia) -> SynExpr.AnonRecd (isStruct, copyInfo |> Option.map (fun (expr, opt) -> (this.VisitSynExpr expr, opt)), - recordFields |> List.map this.VisitAnonRecordField, range) + recordFields |> List.map this.VisitAnonRecordField, range, trivia) | SynExpr.New(isProtected, typeName, expr, range) -> SynExpr.New(isProtected, this.VisitSynType typeName, this.VisitSynExpr expr, range) | SynExpr.ObjExpr(objType, argOptions, withKeyword, bindings, members, extraImpls, newExprRange, range) -> @@ -159,8 +159,8 @@ type SyntaxVisitor() = SynExpr.TryFinally (this.VisitSynExpr tryExpr, this.VisitSynExpr finallyExpr, range, trySeqPoint, withSeqPoint, trivia) | SynExpr.Lazy(ex, range) -> SynExpr.Lazy(this.VisitSynExpr ex, range) - | SynExpr.Sequential(seqPoint, isTrueSeq, expr1, expr2, range) -> - SynExpr.Sequential(seqPoint, isTrueSeq, this.VisitSynExpr expr1, this.VisitSynExpr expr2, range) + | SynExpr.Sequential(seqPoint, isTrueSeq, expr1, expr2, range, trivia) -> + SynExpr.Sequential(seqPoint, isTrueSeq, this.VisitSynExpr expr1, this.VisitSynExpr expr2, range, trivia) | SynExpr.SequentialOrImplicitYield(seqPoint, expr1, expr2, ifNotStmt, range) -> SynExpr.SequentialOrImplicitYield (seqPoint, this.VisitSynExpr expr1, this.VisitSynExpr expr2, this.VisitSynExpr ifNotStmt, range) @@ -233,11 +233,13 @@ type SyntaxVisitor() = (this.VisitSynExpr e1, this.VisitLongIdent longId, i, this.VisitSynExpr e2, range) | SynExpr.ArbitraryAfterError(debugStr, range) -> SynExpr.ArbitraryAfterError(debugStr, range) | SynExpr.FromParseError(expr, range) -> SynExpr.FromParseError(this.VisitSynExpr expr, range) - | SynExpr.DiscardAfterMissingQualificationAfterDot(expr, range) -> - SynExpr.DiscardAfterMissingQualificationAfterDot(this.VisitSynExpr expr, range) + | SynExpr.DiscardAfterMissingQualificationAfterDot(expr, dotRange, range) -> + SynExpr.DiscardAfterMissingQualificationAfterDot(this.VisitSynExpr expr, dotRange, range) | SynExpr.Fixed(expr, range) -> SynExpr.Fixed(this.VisitSynExpr expr, range) | SynExpr.InterpolatedString(contents, kind, range) -> SynExpr.InterpolatedString(List.map this.VisitSynInterpolatedStringPart contents, kind, range) | SynExpr.Typar(synTypar, range) -> SynExpr.Typar(this.VisitSynTypar synTypar, range) + | SynExpr.DotLambda(expr, range, trivia) -> SynExpr.DotLambda(this.VisitSynExpr expr, range, trivia) + | SynExpr.WhileBang(whileDebugPoint, whileExpr, doExpr, range) -> SynExpr.WhileBang(whileDebugPoint, this.VisitSynExpr whileExpr, this.VisitSynExpr doExpr, range) abstract VisitSynInterpolatedStringPart: SynInterpolatedStringPart -> SynInterpolatedStringPart @@ -255,8 +257,8 @@ type SyntaxVisitor() = abstract VisitRecordFieldName: RecordFieldName -> RecordFieldName default this.VisitRecordFieldName((ident: SynLongIdent, correct: bool)) = (this.VisitSynLongIdent ident, correct) - abstract VisitAnonRecordField: (Ident * range option * SynExpr) -> Ident * range option * SynExpr - default this.VisitAnonRecordField((ident: Ident, r: range option, expr: SynExpr)) = (this.VisitIdent ident, r, this.VisitSynExpr expr) + abstract VisitAnonRecordField: (SynLongIdent * range option * SynExpr) -> SynLongIdent * range option * SynExpr + default this.VisitAnonRecordField((ident: SynLongIdent, r: range option, expr: SynExpr)) = (this.VisitSynLongIdent ident, r, this.VisitSynExpr expr) abstract VisitAnonRecordTypeField: (Ident * SynType) -> Ident * SynType default this.VisitAnonRecordTypeField((ident: Ident, t: SynType)) = (this.VisitIdent ident, this.VisitSynType t) @@ -265,7 +267,7 @@ type SyntaxVisitor() = default this.VisitSynMemberSig(ms: SynMemberSig): SynMemberSig = match ms with - | SynMemberSig.Member(valSig, flags, range) -> SynMemberSig.Member(this.VisitSynValSig valSig, flags, range) + | SynMemberSig.Member(valSig, flags, range, trivia) -> SynMemberSig.Member(this.VisitSynValSig valSig, flags, range, trivia) | SynMemberSig.Interface(typeName, range) -> SynMemberSig.Interface(this.VisitSynType typeName, range) | SynMemberSig.Inherit(typeName, range) -> SynMemberSig.Inherit(this.VisitSynType typeName, range) | SynMemberSig.ValField(f, range) -> SynMemberSig.ValField(this.VisitSynField f, range) @@ -323,18 +325,18 @@ type SyntaxVisitor() = SynMemberDefn.GetSetMember(memberDefnForGet |> Option.map this.VisitSynBinding, memberDefnForSet |> Option.map this.VisitSynBinding, range1, synMemberGetSetTrivia) | SynMemberDefn.Open(target, range) -> SynMemberDefn.Open(this.VisitSynOpenDeclTarget target, range) | SynMemberDefn.Member(memberDefn, range) -> SynMemberDefn.Member(this.VisitSynBinding memberDefn, range) - | SynMemberDefn.ImplicitCtor(access, attrs, ctorArgs, selfIdentifier, doc, range) -> + | SynMemberDefn.ImplicitCtor(access, attrs, ctorArgs, selfIdentifier, doc, range, trivia) -> SynMemberDefn.ImplicitCtor (Option.map this.VisitSynAccess access, attrs |> List.map this.VisitSynAttributeList, - this.VisitSynSimplePats ctorArgs, Option.map this.VisitIdent selfIdentifier, this.VisitPreXmlDoc(doc), range) + this.VisitSynPat ctorArgs, Option.map this.VisitIdent selfIdentifier, this.VisitPreXmlDoc(doc), range, trivia) | SynMemberDefn.ImplicitInherit(inheritType, inheritArgs, inheritAlias, range) -> SynMemberDefn.ImplicitInherit (this.VisitSynType inheritType, this.VisitSynExpr inheritArgs, Option.map this.VisitIdent inheritAlias, range) | SynMemberDefn.LetBindings(bindings, isStatic, isRecursive, range) -> SynMemberDefn.LetBindings(bindings |> List.map this.VisitSynBinding, isStatic, isRecursive, range) - | SynMemberDefn.AbstractSlot(valSig, flags, range) -> - SynMemberDefn.AbstractSlot(this.VisitSynValSig valSig, flags, range) + | SynMemberDefn.AbstractSlot(valSig, flags, range, trivia) -> + SynMemberDefn.AbstractSlot(this.VisitSynValSig valSig, flags, range, trivia) | SynMemberDefn.Interface(typ, withKeyword, members, range) -> SynMemberDefn.Interface (this.VisitSynType typ, withKeyword, Option.map (List.map this.VisitSynMemberDefn) members, range) @@ -364,10 +366,8 @@ type SyntaxVisitor() = default this.VisitSynSimplePats(sp: SynSimplePats): SynSimplePats = match sp with - | SynSimplePats.SimplePats(pats, range) -> - SynSimplePats.SimplePats(pats |> List.map this.VisitSynSimplePat, range) - | SynSimplePats.Typed(pats, typ, range) -> - SynSimplePats.Typed(this.VisitSynSimplePats pats, this.VisitSynType typ, range) + | SynSimplePats.SimplePats(pats, commaRanges, range) -> + SynSimplePats.SimplePats(pats |> List.map this.VisitSynSimplePat, commaRanges, range) abstract VisitSynBinding: SynBinding -> SynBinding @@ -420,7 +420,8 @@ type SyntaxVisitor() = default this.VisitSynTyparDecl(std: SynTyparDecl): SynTyparDecl = match std with - | SynTyparDecl(attrs, typar) -> SynTyparDecl(attrs |> List.map this.VisitSynAttributeList, this.VisitSynTypar typar) + | SynTyparDecl(attrs, typar, intersectionConstraints, trivia) -> + SynTyparDecl(attrs |> List.map this.VisitSynAttributeList, this.VisitSynTypar typar, intersectionConstraints |> List.map this.VisitSynType, trivia) abstract VisitSynTypar: SynTypar -> SynTypar @@ -459,7 +460,7 @@ type SyntaxVisitor() = (this.VisitSynLongIdent longDotId, Option.map this.VisitIdent ident, Option.map this.VisitSynValTyparDecls svtd, this.VisitSynArgPats ctorArgs, Option.map this.VisitSynAccess access, range) - | SynPat.Tuple(isStruct, pats, range) -> SynPat.Tuple(isStruct, pats |> List.map this.VisitSynPat, range) + | SynPat.Tuple(isStruct, pats, commaRanges, range) -> SynPat.Tuple(isStruct, pats |> List.map this.VisitSynPat, commaRanges, range) | SynPat.Paren(pat, range) -> SynPat.Paren(this.VisitSynPat pat, range) | SynPat.ArrayOrList(isList, pats, range) -> SynPat.ArrayOrList(isList, pats |> List.map this.VisitSynPat, range) @@ -473,7 +474,6 @@ type SyntaxVisitor() = | SynPat.OptionalVal(ident, range) -> SynPat.OptionalVal(this.VisitIdent ident, range) | SynPat.IsInst(typ, range) -> SynPat.IsInst(this.VisitSynType typ, range) | SynPat.QuoteExpr(expr, range) -> SynPat.QuoteExpr(this.VisitSynExpr expr, range) - | SynPat.DeprecatedCharRange(c, c2, range) -> SynPat.DeprecatedCharRange(c, c2, range) | SynPat.InstanceMember(ident, ident2, ident3, access, range) -> SynPat.InstanceMember (this.VisitIdent ident, this.VisitIdent ident2, Option.map this.VisitIdent ident3, @@ -580,10 +580,10 @@ type SyntaxVisitor() = default this.VisitSynEnumCase(sec: SynEnumCase): SynEnumCase = match sec with - | SynEnumCase(attrs, ident, cnst, cnstRange, doc, trivia, range) -> + | SynEnumCase(attrs, ident, expr, doc, trivia, range) -> SynEnumCase - (attrs |> List.map this.VisitSynAttributeList, this.VisitSynIdent ident, this.VisitSynConst cnst, - cnstRange, this.VisitPreXmlDoc(doc), trivia, range) + (attrs |> List.map this.VisitSynAttributeList, this.VisitSynIdent ident, this.VisitSynExpr expr, + this.VisitPreXmlDoc(doc), trivia, range) abstract VisitSynField: SynField -> SynField @@ -618,8 +618,6 @@ type SyntaxVisitor() = | SynType.WithGlobalConstraints(typeName, constraints, range) -> SynType.WithGlobalConstraints(this.VisitSynType typeName, constraints, range) | SynType.HashConstraint(synType, range) -> SynType.HashConstraint(this.VisitSynType synType, range) - | SynType.MeasureDivide(dividendType, divisorType, range) -> - SynType.MeasureDivide(this.VisitSynType dividendType, this.VisitSynType divisorType, range) | SynType.MeasurePower(measureType, cnst, range) -> SynType.MeasurePower(this.VisitSynType measureType, cnst, range) | SynType.StaticConstant(constant, range) -> SynType.StaticConstant(this.VisitSynConst constant, range) @@ -632,6 +630,8 @@ type SyntaxVisitor() = SynType.Or(this.VisitSynType lhsType, this.VisitSynType rhsType, range, this.VisitSynTypeOrTrivia synTypeOrTrivia) | SynType.SignatureParameter(synAttributeLists, optional, identOption, usedType, range) -> SynType.SignatureParameter(List.map this.VisitSynAttributeList synAttributeLists, optional, Option.map this.VisitIdent identOption, this.VisitSynType usedType, range) + | SynType.FromParseError range -> SynType.FromParseError range + | SynType.Intersection(typar, types, range, trivia) -> SynType.Intersection(Option.map this.VisitSynTypar typar, types |> List.map this.VisitSynType, range, trivia) abstract VisitSynTypeOrTrivia: SynTypeOrTrivia -> SynTypeOrTrivia default this.VisitSynTypeOrTrivia(synTypeOrTrivia: SynTypeOrTrivia): SynTypeOrTrivia = synTypeOrTrivia diff --git a/tests/AllTestsWithTask/AllTestsWithTask.fsproj b/tests/AllTestsWithTask/AllTestsWithTask.fsproj index 3a25184..3efb84f 100644 --- a/tests/AllTestsWithTask/AllTestsWithTask.fsproj +++ b/tests/AllTestsWithTask/AllTestsWithTask.fsproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 false diff --git a/tests/ClassBasedTests/ClassBasedTests.fsproj b/tests/ClassBasedTests/ClassBasedTests.fsproj index 0def9cc..98b0d99 100644 --- a/tests/ClassBasedTests/ClassBasedTests.fsproj +++ b/tests/ClassBasedTests/ClassBasedTests.fsproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 false diff --git a/tests/DifferentTestCodeFormats/DifferentTestCodeFormats.fsproj b/tests/DifferentTestCodeFormats/DifferentTestCodeFormats.fsproj index 94f53ac..5856853 100644 --- a/tests/DifferentTestCodeFormats/DifferentTestCodeFormats.fsproj +++ b/tests/DifferentTestCodeFormats/DifferentTestCodeFormats.fsproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 false diff --git a/tests/DifferentTypesOfTests/DifferentTypesOfTests.fsproj b/tests/DifferentTypesOfTests/DifferentTypesOfTests.fsproj index 69b3d54..947130b 100644 --- a/tests/DifferentTypesOfTests/DifferentTypesOfTests.fsproj +++ b/tests/DifferentTypesOfTests/DifferentTypesOfTests.fsproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 false diff --git a/tests/DotnetSevenProject/DotnetSevenProject.fs b/tests/DotnetSevenProject/DotnetSevenProject.fs new file mode 100644 index 0000000..863d2cc --- /dev/null +++ b/tests/DotnetSevenProject/DotnetSevenProject.fs @@ -0,0 +1,7 @@ +module DotnetSixProject + +let add x y = x + y + +let sub x y = x - y + +let mul x y = x * y diff --git a/tests/DotnetSevenProject/DotnetSevenProject.fsproj b/tests/DotnetSevenProject/DotnetSevenProject.fsproj new file mode 100644 index 0000000..7ca81b5 --- /dev/null +++ b/tests/DotnetSevenProject/DotnetSevenProject.fsproj @@ -0,0 +1,22 @@ + + + + net7.0 + + false + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/DotnetSevenProject/DotnetSevenProjectTests.fs b/tests/DotnetSevenProject/DotnetSevenProjectTests.fs new file mode 100644 index 0000000..fd93a7a --- /dev/null +++ b/tests/DotnetSevenProject/DotnetSevenProjectTests.fs @@ -0,0 +1,15 @@ +module DotnetSixProjectTests + +open Xunit +open FsUnit.Xunit +open Exercism.Tests +open DotnetSixProject + +[] +let ``Add should add numbers`` () = add 1 1 |> should equal 2 + +[] +let ``Sub should subtract numbers`` () = sub 7 3 |> should equal 4 + +[] +let ``Mul should multiply numbers`` () = mul 2 3 |> should equal 6 diff --git a/tests/DotnetSevenProject/expected_results.json b/tests/DotnetSevenProject/expected_results.json new file mode 100644 index 0000000..ce56be2 --- /dev/null +++ b/tests/DotnetSevenProject/expected_results.json @@ -0,0 +1,21 @@ +{ + "version": 3, + "status": "pass", + "tests": [ + { + "name": "Add should add numbers", + "status": "pass", + "test_code": "add 1 1 |\u003E should equal 2" + }, + { + "name": "Sub should subtract numbers", + "status": "pass", + "test_code": "sub 7 3 |\u003E should equal 4" + }, + { + "name": "Mul should multiply numbers", + "status": "pass", + "test_code": "mul 2 3 |\u003E should equal 6" + } + ] +} \ No newline at end of file diff --git a/tests/MultipleCompileErrors/MultipleCompileErrors.fsproj b/tests/MultipleCompileErrors/MultipleCompileErrors.fsproj index 3b0de41..c4bcbf5 100644 --- a/tests/MultipleCompileErrors/MultipleCompileErrors.fsproj +++ b/tests/MultipleCompileErrors/MultipleCompileErrors.fsproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 false diff --git a/tests/MultipleTestsWithAllPasses/MultipleTestsWithAllPasses.fsproj b/tests/MultipleTestsWithAllPasses/MultipleTestsWithAllPasses.fsproj index d5c3d9b..fc69380 100644 --- a/tests/MultipleTestsWithAllPasses/MultipleTestsWithAllPasses.fsproj +++ b/tests/MultipleTestsWithAllPasses/MultipleTestsWithAllPasses.fsproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 false diff --git a/tests/MultipleTestsWithMultipleFails/MultipleTestsWithMultipleFails.fsproj b/tests/MultipleTestsWithMultipleFails/MultipleTestsWithMultipleFails.fsproj index 104c721..188305b 100644 --- a/tests/MultipleTestsWithMultipleFails/MultipleTestsWithMultipleFails.fsproj +++ b/tests/MultipleTestsWithMultipleFails/MultipleTestsWithMultipleFails.fsproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 false diff --git a/tests/MultipleTestsWithSingleFail/MultipleTestsWithSingleFail.fsproj b/tests/MultipleTestsWithSingleFail/MultipleTestsWithSingleFail.fsproj index 47a34c9..0c45b73 100644 --- a/tests/MultipleTestsWithSingleFail/MultipleTestsWithSingleFail.fsproj +++ b/tests/MultipleTestsWithSingleFail/MultipleTestsWithSingleFail.fsproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 false diff --git a/tests/MultipleTestsWithTestOutput/MultipleTestsWithTestOutput.fsproj b/tests/MultipleTestsWithTestOutput/MultipleTestsWithTestOutput.fsproj index 72542a2..d00b37f 100644 --- a/tests/MultipleTestsWithTestOutput/MultipleTestsWithTestOutput.fsproj +++ b/tests/MultipleTestsWithTestOutput/MultipleTestsWithTestOutput.fsproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 false diff --git a/tests/MultipleTestsWithTestOutputExceedingLimit/MultipleTestsWithTestOutputExceedingLimit.fsproj b/tests/MultipleTestsWithTestOutputExceedingLimit/MultipleTestsWithTestOutputExceedingLimit.fsproj index 9bc4e87..7695de6 100644 --- a/tests/MultipleTestsWithTestOutputExceedingLimit/MultipleTestsWithTestOutputExceedingLimit.fsproj +++ b/tests/MultipleTestsWithTestOutputExceedingLimit/MultipleTestsWithTestOutputExceedingLimit.fsproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 false diff --git a/tests/NotImplemented/NotImplemented.fsproj b/tests/NotImplemented/NotImplemented.fsproj index a09ba83..3b28590 100644 --- a/tests/NotImplemented/NotImplemented.fsproj +++ b/tests/NotImplemented/NotImplemented.fsproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 false diff --git a/tests/QuotedAndNonQuotedTests/QuotedAndNonQuotedTests.fsproj b/tests/QuotedAndNonQuotedTests/QuotedAndNonQuotedTests.fsproj index 1415c84..6bdf6f4 100644 --- a/tests/QuotedAndNonQuotedTests/QuotedAndNonQuotedTests.fsproj +++ b/tests/QuotedAndNonQuotedTests/QuotedAndNonQuotedTests.fsproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 false diff --git a/tests/SingleCompileError/SingleCompileError.fsproj b/tests/SingleCompileError/SingleCompileError.fsproj index d1b9636..7928d23 100644 --- a/tests/SingleCompileError/SingleCompileError.fsproj +++ b/tests/SingleCompileError/SingleCompileError.fsproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 false diff --git a/tests/SingleTestThatFails/SingleTestThatFails.fsproj b/tests/SingleTestThatFails/SingleTestThatFails.fsproj index c566666..76d8e7e 100644 --- a/tests/SingleTestThatFails/SingleTestThatFails.fsproj +++ b/tests/SingleTestThatFails/SingleTestThatFails.fsproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 false diff --git a/tests/SingleTestThatPasses/SingleTestThatPasses.fsproj b/tests/SingleTestThatPasses/SingleTestThatPasses.fsproj index ce76471..8eeddac 100644 --- a/tests/SingleTestThatPasses/SingleTestThatPasses.fsproj +++ b/tests/SingleTestThatPasses/SingleTestThatPasses.fsproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 false diff --git a/tests/SomeTestsWithTask/SomeTestsWithTask.fsproj b/tests/SomeTestsWithTask/SomeTestsWithTask.fsproj index 2d35683..e3e0928 100644 --- a/tests/SomeTestsWithTask/SomeTestsWithTask.fsproj +++ b/tests/SomeTestsWithTask/SomeTestsWithTask.fsproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 false diff --git a/tests/TestWithParentheses/TestWithParentheses.fsproj b/tests/TestWithParentheses/TestWithParentheses.fsproj index ecce244..45a0597 100644 --- a/tests/TestWithParentheses/TestWithParentheses.fsproj +++ b/tests/TestWithParentheses/TestWithParentheses.fsproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 false diff --git a/tests/UseCultureAttribute/UseCultureAttribute.fsproj b/tests/UseCultureAttribute/UseCultureAttribute.fsproj index 818308e..a4bdd7b 100644 --- a/tests/UseCultureAttribute/UseCultureAttribute.fsproj +++ b/tests/UseCultureAttribute/UseCultureAttribute.fsproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 false