language-dart-0.2.0.0: test/PrettySpec.hs
{-# LANGUAGE QuasiQuotes #-}
module PrettySpec where
import Test.Hspec
import Language.Dart.Pretty
import Language.Dart.Syntax
import Text.RawString.QQ
import TestHelper
spec :: Spec
spec =
describe "prettyPrint" $ do
it "preserves operator precedence" $ do
let l = BinaryExpression (intExp 1) "+" (intExp 2)
r = BinaryExpression (intExp 3) "-" (intExp 2)
e = BinaryExpression l "*" r
prettyPrint e `shouldBe` "(1 + 2) * (3 - 2)"
it "prints an import directive" $ do
let libraryUri = strLit "package:analyzer/src/dart/ast/ast.dart"
as = SimpleIdentifier "a"
imp = ImportDirective Nothing
[]
libraryUri
[]
False
(Just as)
[ ShowCombinator [SimpleIdentifier "TypeName"]
, ShowCombinator [SimpleIdentifier "ArgumentList"]
]
prettyPrint imp `shouldBe` [r|import "package:analyzer/src/dart/ast/ast.dart" as a show TypeName, show ArgumentList;|]
it "prints a function declaration" $ do
let formals = FormalParameterList [formal numType "aNumber"]
arg = Literal' . StringLiteral' . SingleStringLiteral' $
StringInterpolation [ InterpolationString "The number is "
, InterpolationExpression (identExp "aNumber")
, InterpolationString "."]
body = BlockFunctionBody Sync
(Block [ ExpressionStatement (
InvocationExpression (
MethodInvocation Nothing
(SimpleIdentifier "print")
Nothing
(ArgumentList [arg])))])
funExp = FunctionExpression Nothing formals body
funDecl = FunctionDeclaration Nothing [] False Nothing Empty (SimpleIdentifier "printNumber") funExp
prettyPrint funDecl `shouldBe` [r|printNumber(num aNumber)
{
print("The number is ${aNumber}.");
}|]
it "prints an optional position parameter" $ do
let formals = FormalParameterList [formal strType "from", formal strType "msg", posFormal strType "device"]
str1 = Literal' . StringLiteral' . SingleStringLiteral' $
StringInterpolation [ InterpolationExpression (identExp "from")
, InterpolationString " says "
, InterpolationExpression (identExp "msg")
]
str2 = Literal' . StringLiteral' . SingleStringLiteral' $
StringInterpolation [ InterpolationExpression (identExp "result")
, InterpolationString " with a "
, InterpolationExpression (identExp "device")
]
body = BlockFunctionBody Sync
(Block [ VariableDeclarationStatement (
VariableDeclarationList Nothing
[]
FCVTVar
[VariableDeclaration (SimpleIdentifier "result") (Just str1)])
, IfStatement (BinaryExpression (identExp "device") "!=" nullExp)
(Block' (Block [ ExpressionStatement (
AssignmentExpression (identExp "result") "=" str2)]))
Nothing
, ReturnStatement (Just (identExp "result"))
])
funExp = FunctionExpression Nothing formals body
funDecl = FunctionDeclaration Nothing [] False (Just strType) Empty (SimpleIdentifier "say") funExp
prettyPrint funDecl `shouldBe` [r|String say(String from, String msg, [String device])
{
var result = "${from} says ${msg}";
if (device != null)
{
result = "${result} with a ${device}";
}
return result;
}|]
it "prints an expression function" $ do
let body = ExpressionFunctionBody False (
ConditionalExpression (BinaryExpression (identExp "msg") "==" nullExp)
(InvocationExpression
(MethodInvocation (Just SuperExpression)
(SimpleIdentifier "toString")
Nothing
(ArgumentList [])))
(identExp "msg"))
funExp = FunctionExpression Nothing (FormalParameterList []) body
funDecl = FunctionDeclaration Nothing [] False (Just strType) Empty (SimpleIdentifier "toString") funExp
prettyPrint funDecl `shouldBe` "String toString() => msg == null ? super.toString() : msg;"
it "prints an enum" $ do
let enumConstDecls = [ EnumConstantDeclaration Nothing [] (SimpleIdentifier "red")
, EnumConstantDeclaration Nothing [] (SimpleIdentifier "green")
, EnumConstantDeclaration Nothing [] (SimpleIdentifier "blue")
]
enumDecl = EnumDeclaration Nothing [] (SimpleIdentifier "Color") enumConstDecls
prettyPrint enumDecl `shouldBe` [r|enum Color
{
red,
green,
blue
}|]
it "prints a for loop" $ do
let variableList = VariableDeclarationList Nothing
[]
FCVTVar
[VariableDeclaration (SimpleIdentifier "i") (Just (intExp 0))]
condition = BinaryExpression (identExp "i") "<" (intExp 5)
updater = PostfixExpression (identExp "i") "++"
body = (Block' (Block [ ExpressionStatement (
InvocationExpression (
MethodInvocation (Just (identExp "message"))
(SimpleIdentifier "write")
Nothing
(ArgumentList [strLitExp "!"])))]))
forLoop = ForStatement (Just variableList)
Nothing
(Just condition)
[updater]
body
prettyPrint forLoop `shouldBe` [r|for (var i = 0; i < 5; i++)
{
message.write("!");
}|]
it "prints a list literal" $ do
let litExp = Literal' . TypedLiteral $ ListLiteral False Nothing [intExp 0, intExp 1, intExp 2]
prettyPrint litExp `shouldBe` "[0, 1, 2]"
it "prints parameterized types" $ do
let consName = ConstructorName (TypeName (SimpleIdentifier' (SimpleIdentifier "Map"))
(Just (TypeArgumentList [tyName "int", tyName "View"])))
Nothing
let exp = InstanceCreationExpression NCNew consName (ArgumentList [])
prettyPrint exp `shouldBe` "new Map<int, View>()"
it "prints a switch statement" $ do
let switchMembers = [ SwitchCase [] (strLitExp "CLOSED") [funStmt "executeClosed", (BreakStatement Nothing)]
, SwitchCase [] (strLitExp "PENDING") [funStmt "executePending", (BreakStatement Nothing)]
, SwitchCase [] (strLitExp "APPROVED") [funStmt "executeApproved", (BreakStatement Nothing)]
, SwitchCase [] (strLitExp "DENIED") [funStmt "executeDenied", (BreakStatement Nothing)]
, SwitchCase [] (strLitExp "OPEN") [funStmt "executeOpen", (BreakStatement Nothing)]
, SwitchDefault [] [funStmt "executeUnknown"]
]
switch = SwitchStatement (identExp "command") switchMembers
prettyPrint switch `shouldBe` [r|switch (command)
{
case "CLOSED":
executeClosed();
break;
case "PENDING":
executePending();
break;
case "APPROVED":
executeApproved();
break;
case "DENIED":
executeDenied();
break;
case "OPEN":
executeOpen();
break;
default:
executeUnknown();
}|]
it "prints a try statement" $ do
let arg = Literal' . StringLiteral' . SingleStringLiteral' $
StringInterpolation [ InterpolationString "Error: "
, InterpolationExpression (identExp "e")
]
try = TryStatement (Block [funStmt "breedMoreLlamas"])
[CatchClause Nothing (SimpleIdentifier "e") Nothing (Block [funStmt1 "print" arg])]
(Just (Block [funStmt "cleanLlamaStalls"]))
prettyPrint try `shouldBe` [r|try
{
breedMoreLlamas();
}
catch (e)
{
print("Error: ${e}");
}
finally
{
cleanLlamaStalls();
}|]
it "prints a constructor" $ do
let varDeclList ty name = VariableDeclarationList Nothing
[]
(FCVTType (tyName ty))
[VariableDeclaration (SimpleIdentifier name) Nothing]
returnType = SimpleIdentifier' (SimpleIdentifier "Point")
consFormals1 = FormalParameterList [ NormalFormalParameter' (FieldFormalParameter Nothing [] Nothing True (SimpleIdentifier "x"))
, NormalFormalParameter' (FieldFormalParameter Nothing [] Nothing True (SimpleIdentifier "y"))
]
consFormals2 = FormalParameterList [ NormalFormalParameter' (
FieldFormalParameter Nothing
[]
(Just (FCVTType (tyName "Map")))
False
(SimpleIdentifier "json"))
]
methodFormals = FormalParameterList [ NormalFormalParameter' (
FieldFormalParameter Nothing
[]
(Just (FCVTType (tyName "Point")))
False
(SimpleIdentifier "other"))
]
consBody = BlockFunctionBody Sync
(Block [ ExpressionStatement (
AssignmentExpression (identExp "x")
"="
(IndexExpressionForTarget (identExp "json") (strLitExp "x")))
, ExpressionStatement (
AssignmentExpression (identExp "y")
"="
(IndexExpressionForTarget (identExp "json") (strLitExp "y")))
])
exp1 = BinaryExpression (identExp "x") "-" (PropertyAccess (identExp "other") (SimpleIdentifier "x"))
exp2 = BinaryExpression (identExp "y") "-" (PropertyAccess (identExp "other") (SimpleIdentifier "y"))
methodBody = BlockFunctionBody Sync
(Block [ VariableDeclarationStatement (
VariableDeclarationList Nothing
[]
FCVTVar
[VariableDeclaration (SimpleIdentifier "dx") (Just exp1)])
, VariableDeclarationStatement (
VariableDeclarationList Nothing
[]
FCVTVar
[VariableDeclaration (SimpleIdentifier "dy") (Just exp2)])
, ReturnStatement (Just (
InvocationExpression (
MethodInvocation Nothing
(SimpleIdentifier "sqrt")
Nothing
(ArgumentList [BinaryExpression (BinaryExpression (identExp "dx") "*" (identExp "dx"))
"+"
(BinaryExpression (identExp "dy") "*" (identExp "dy"))]))))
])
classMembers = [ FieldDeclaration Nothing [] False (varDeclList "num" "x")
, FieldDeclaration Nothing [] False (varDeclList "num" "y")
, ConstructorDeclaration Nothing [] False False False returnType Nothing consFormals1 [] Nothing Nothing
, ConstructorDeclaration Nothing [] False False False returnType (Just (SimpleIdentifier "fromJson")) consFormals2 [] Nothing (Just consBody)
, MethodDeclaration Nothing [] False Nothing (Just (tyName "num")) Empty False (SimpleIdentifier "distanceTo") Nothing (Just methodFormals) methodBody
]
clazz = ClassDeclaration Nothing
[]
False
(SimpleIdentifier "Point")
Nothing
Nothing
Nothing
Nothing
classMembers
prettyPrint clazz `shouldBe` [r|class Point
{
num x;
num y;
Point(this.x, this.y);
Point.fromJson(Map json)
{
x = json["x"];
y = json["y"];
}
num distanceTo(Point other)
{
var dx = x - other.x;
var dy = y - other.y;
return sqrt(dx * dx + dy * dy);
}
}|]
it "prints the initializer lists of a constructor" $ do
let varDeclList ty name = VariableDeclarationList Nothing
[]
(FCVTType (tyName ty))
[VariableDeclaration (SimpleIdentifier name) Nothing]
returnType = SimpleIdentifier' (SimpleIdentifier "Point")
formals = FormalParameterList [ NormalFormalParameter' (FieldFormalParameter Nothing [] Nothing True (SimpleIdentifier "x"))
, NormalFormalParameter' (FieldFormalParameter Nothing [] Nothing True (SimpleIdentifier "y"))
]
exp = InvocationExpression (
MethodInvocation Nothing
(SimpleIdentifier "sqrt")
Nothing
(ArgumentList [BinaryExpression (BinaryExpression (identExp "x") "*" (identExp "x"))
"+"
(BinaryExpression (identExp "y") "*" (identExp "y"))]))
classMembers = [ FieldDeclaration Nothing [] False (varDeclList "num" "x")
, FieldDeclaration Nothing [] False (varDeclList "num" "y")
, FieldDeclaration Nothing [] False (varDeclList "num" "distanceFromOrigin")
, ConstructorDeclaration Nothing
[]
False
False
False
returnType
Nothing
formals
[ ConstructorFieldInitializer False (SimpleIdentifier "x") (identExp "x")
, ConstructorFieldInitializer False (SimpleIdentifier "y") (identExp "y")
, ConstructorFieldInitializer False (SimpleIdentifier "distanceFromOrigin") exp
]
Nothing
Nothing
]
clazz = ClassDeclaration Nothing
[]
False
(SimpleIdentifier "Point")
Nothing
Nothing
Nothing
Nothing
classMembers
prettyPrint clazz `shouldBe` [r|class Point
{
num x;
num y;
num distanceFromOrigin;
Point(this.x, this.y) : x = x,
y = y,
distanceFromOrigin = sqrt(x * x + y * y);
}|]
it "prints the implement clause" $ do
let implements = ImplementsClause [tyName "Comparable", tyName "Location"]
clazz = ClassDeclaration Nothing
[]
False
(SimpleIdentifier "Point")
Nothing
Nothing
Nothing
(Just implements)
[]
prettyPrint clazz `shouldBe` [r|class Point implements Comparable, Location
{
}|]
it "prints the metadata" $ do
let annotation = Annotation (SimpleIdentifier' (SimpleIdentifier "override")) Nothing Nothing
methodFormals = FormalParameterList [ NormalFormalParameter' (
FieldFormalParameter Nothing
[]
(Just (FCVTType (tyName "Invocation")))
False
(SimpleIdentifier "mirror"))
]
methodDecl = MethodDeclaration Nothing
[annotation]
False
Nothing
(Just (tyName "void"))
Empty
False
(SimpleIdentifier "noSuchMethod")
Nothing
(Just methodFormals)
(BlockFunctionBody Sync (Block []))
prettyPrint methodDecl `shouldBe` [r|@override
void noSuchMethod(Invocation mirror)
{
}|]
main :: IO ()
main = hspec spec