module Language.GLSL.Tests where
import Text.ParserCombinators.Parsec hiding (State, parse)
import Text.PrettyPrint.HughesPJClass (prettyShow, Pretty)
import Test.HUnit
import Language.GLSL.Syntax
import Language.GLSL.Parser
import Language.GLSL.Pretty ()
tests :: IO ()
tests = do
mapM_ runTestTT parsingTests
return ()
parsingTests :: [Test]
parsingTests =
[ legalExpressionsTests
, illegalExpressionsTests
, legalDeclarationsTests
, illegalDeclarationsTests
, legalFunctionDefinitionsTests
, legalCommentsTests
, illegalCommentsTests
, TestLabel "expressions id" $ TestList $
map expressionsId testExpressionsTrue
, TestLabel "declarations id" $ TestList $
map declarationsId testDeclarationsTrue
, TestLabel "function definitions id" $ TestList $
map functionDefinitionsId testFunctionDefinitionsTrue
]
parsePrettyId :: TranslationUnit -> Bool
parsePrettyId e = case pass translationUnit (prettyShow e) of
Left _ -> False
Right e' -> e == e'
parsePrettyIdExpr :: Expr -> Bool
parsePrettyIdExpr e = case pass expression (prettyShow e) of
Left _ -> False
Right e' -> e == e'
parsePrettyIdDecl :: Declaration -> Bool
parsePrettyIdDecl e = case pass declaration (prettyShow e) of
Left _ -> False
Right e' -> e == e'
check :: Pretty a => P a -> String -> IO ()
check p str = case pass p str of
Left err -> print err
Right ast -> putStrLn $ prettyShow ast
parsePrettyIdFunc :: ExternalDeclaration -> Bool
parsePrettyIdFunc e = case pass functionDefinition (prettyShow e) of
Left _ -> False
Right e' -> e == e'
expressionsId :: String -> Test
expressionsId str = TestCase . assertBool ("expressionsId: " ++ str) . parsePrettyIdExpr $ ast
where ast = case pass expression str of
Left _ -> error "does not even parse the original string"
Right a -> a
declarationsId :: String -> Test
declarationsId str = TestCase . assertBool ("declarationsId: " ++ str) . parsePrettyIdDecl $ ast
where ast = case pass declaration str of
Left _ -> error "does not even parse the original string"
Right a -> a
functionDefinitionsId :: String -> Test
functionDefinitionsId str = TestCase . assertBool ("functionDefinitionsId: " ++ str) . parsePrettyIdFunc $ ast
where ast = case pass functionDefinition str of
Left _ -> error "does not even parse the original string"
Right a -> a
pass :: P a -> String -> Either ParseError a
pass p = runParser (do {skipMany blank ; r <- p ; eof ; return r}) S "pass"
isRight :: Either a b -> Bool
isRight (Right _) = True
isRight (Left _) = False
isLeft :: Either a b -> Bool
isLeft = not . isRight
doesParse :: P a -> String -> Test
doesParse p str =
TestCase . assertBool ("doesParse: " ++ str) . isRight . pass p $ str
doesNotParse :: P a -> String -> Test
doesNotParse p str =
TestCase . assertBool ("doesNotParse: " ++ str) . isLeft . pass p $ str
legalExpressionsTests :: Test
legalExpressionsTests = TestLabel "legal expressions" $
TestList $ map (doesParse expression) testExpressionsTrue
illegalExpressionsTests :: Test
illegalExpressionsTests = TestLabel "illegal expressions" $
TestList $ map (doesNotParse expression) testExpressionsFalse
testExpressionsTrue :: [String]
testExpressionsTrue =
[ "a"
, "avoid"
, "filters"
, "0"
, "1"
, ".1"
, "0x01"
, "0xF"
, "07"
, "a++"
, "a--"
, "a++--"
, "a--++"
, "a++++"
, "a----"
, "++a"
, "--a"
, "++--a"
, "--++a"
, "++++a"
, "----a"
, "a ++"
, "+a"
, "+ a"
, "a + b"
, "a + b++"
, "a + ++b"
, "a + + b"
, "a ++ +b"
, "a()"
, "float()"
, "a ()"
, "a( )"
, "a ( )"
, "a.a"
, "a.a()"
, "a.length()"
, "a[1]"
, "a[1].x"
, "a[1].x()"
, "a().b"
, "a().b[1]"
, "a().b()"
, "a.b.c"
]
testExpressionsFalse :: [String]
testExpressionsFalse =
[ "void"
, "filter"
, ".A"
, "08"
, "0A"
, "+"
, "++"
, "a+"
, "a +"
, "a . a"
, "a[]"
]
legalDeclarationsTests :: Test
legalDeclarationsTests = TestLabel "legal declarations" $
TestList $ map (doesParse declaration) testDeclarationsTrue
illegalDeclarationsTests :: Test
illegalDeclarationsTests = TestLabel "illegal declarations" $
TestList $ map (doesNotParse declaration) testDeclarationsFalse
testDeclarationsTrue :: [String]
testDeclarationsTrue =
[ "int a;"
, "int a, b, c;"
, "precision highp float;"
, "int a = 1;"
, "struct a { int b; };"
, "struct a { int b; float c; };"
, "layout (origin_upper_left) in;"
, "layout (origin_upper_left) in vec4 gl_FragCoord;"
, "layout (origin_upper_left, pixel_center_integer) in vec4 gl_FragCoord;"
, "bool success;"
, "bool done = false;"
, "int a = 123;"
, "int a = 123u;"
, "int a = 123U;"
, "int a = 0123;"
, "int a = 0123u;"
, "int a = 0123U;"
, "int a = 0x123;"
, "int a = 0x123u;"
, "int a = 0x123U;"
, "int a = 0x12ABu;"
, "int a = 0x12ABU;"
, "int a = 0X123;"
, "int a = 0X123u;"
, "int a = 0X123U;"
, "int a = 0X12ABu;"
, "int a = 0X12ABU;"
, "float a = 1.0;"
, "float a = 1.;"
, "float a = .0;"
, "float a = 1e1;"
, "float a = 1.0e1;"
, "float a = 1.e1;"
, "float a = 1.0e-1;"
, "float a = 1.0e+1;"
, "float a = 1.0e+1f;"
, "float a = 1.0e+1F;"
, "vec2 texcoord1, texcoord2;"
, "mat3x2 m;"
, "struct light { float intensity; vec3 position; } lightVar;"
, "const struct light { float intensity; vec3 position; } lightVar;"
, "float frequencies[3];"
, "uniform vec4 lightPosition[4];"
, "light lights[];"
, "const int numLights = 2;"
, "light lights[numLights];"
, "float[5] a;"
, "float a[5];"
, "float a[5] = float[](3.4, 4.2, 5.0, 5.2, 1.1);"
, "float a[5] = float[5](3.4, 4.2, 5.0, 5.2, 1.1);"
, "const int a;"
, "in int a;"
, "centroid in int a;"
, "smooth in int a;"
, "bool success;"
, "bool done = false;"
, "int i;"
, "int i, j = 42;"
, "int j = 1;"
, "uint k = 3u;"
, "float x = 1.0;"
, "float a = 1.5, b;"
, "vec2 texcoord1, texcoord2;"
, "vec3 position;"
, "vec4 myRGBA;"
, "ivec2 textureLookup;"
, "bvec3 less;"
, "mat2 mat2D;"
, "mat3 optMatrix;"
, "mat4 view;"
, "mat3x2 m;"
, "struct light\
\{\
\float intensity;\
\vec3 position;\
\} lightVar;"
, "light lightVar3;"
, "float frequencies[3];"
, "uniform vec4 lightPosition[4];"
, "light lights[];"
, "const int numLights = 2;"
, "light lights[numLights];"
, "int a[5];"
, "const float coef = 2.75;"
, "const vec3 zAxis = vec3 (0.0, 0.0, 1.0);"
, "in vec4 position;"
, "in vec3 normal;"
, "in vec2 texCoord[4];"
, "in float foo[];"
, "centroid out vec2 TexCoord;"
, "invariant centroid out vec4 Color;"
, "invariant flat centroid out vec4 Color;"
, "noperspective out float temperature;"
, "flat out vec3 myColor;"
, "noperspective centroid out vec2 myTexCoord;"
, "out vec4 FragmentColor;"
, "out uint Luminosity;"
, "uniform Transform\
\{\
\ mat4 ModelViewMatrix;\
\ mat4 ModelViewProjectionMatrix;\
\ uniform mat3 NormalMatrix;\
\ float Deformation;\
\};"
, "in Material\
\{\
\ smooth in vec4 Color1;\
\ smooth vec4 Color2;\
\ vec2 TexCoord;\
\};"
, "out Vertex\
\{\
\ vec4 Position;\
\ vec2 Texture;\
\} Coords;"
, "uniform Transform {\
\ mat4 ModelViewMatrix;\
\ mat4 ModelViewProjectionMatrix;\
\ float Deformation;\
\} transforms[4];"
, "layout (triangles) in;"
, "layout (origin_upper_left) in vec4 gl_FragCoord;"
, "layout (pixel_center_integer) in vec4 gl_FragCoord;"
, "layout (origin_upper_left, pixel_center_integer) in vec4 gl_FragCoord;"
, "layout (triangle_strip, max_vertices = 60) out;"
, "layout (triangle_strip) out;"
, "layout (max_vertices = 60) out;"
, "layout (shared, column_major) uniform;"
, "layout (std140) uniform Transform {\
\ mat4 M1;\
\ layout (column_major) mat4 M2;\
\ mat3 N1;\
\};"
, "flat out vec4 gl_FrontColor;"
, "lowp float color;"
, "out mediump vec2 P;"
, "highp mat4 m;"
, "precision highp float;"
, "precision highp int;"
, "precision mediump int;"
, "invariant gl_Position;"
, "out vec3 Color;"
, "invariant Color;"
, "invariant centroid out vec3 Color;"
, "vec4 color = vec4(0.0, 1.0, 0.0, 1.0);"
, "int i = 1 - 5 * 4 + 3;"
, "int i = 1 - (5 * 4) + 3;"
, "int i = (1 - 5) * 4 + 3;"
, "int i = (1 - 5) * (4 + 3);"
, "bool b = 1 < 2;"
]
testDeclarationsFalse :: [String]
testDeclarationsFalse =
[ "int a"
, "int a, b c;"
, "precision high float;"
, "precision float f();"
, "int float;"
, "struct a { };"
, "struct a { int b, float c; };"
, "int a = 0128;"
, "int a = 0xu;"
, "float a = .e1;"
, "float a = 1.0e+1G;"
, "int f();"
, "int f(void);"
, "int f ( void ) ;"
, "lowp ivec2 foo(lowp mat3);"
, "float[5] foo();"
, "void foo (float[5]);"
, "void foo (float a[5]);"
, "float[] foo();"
, "float[5] foo();"
, "float[5] foo(int[4]);"
, "int f ();"
, "float a[5][3];"
]
legalFunctionDefinitionsTests :: Test
legalFunctionDefinitionsTests = TestLabel "legal function definition" $
TestList $ map (doesParse functionDefinition) testFunctionDefinitionsTrue
testFunctionDefinitionsTrue :: [String]
testFunctionDefinitionsTrue =
[ "void main ()\n\
\{\n\
\}"
, "void main ()\n\
\{\n\
\ if (intensity < 0.0)\n\
\ return;\n\
\}"
]
legalCommentsTests :: Test
legalCommentsTests = TestLabel "legal comments" $
TestList $ map (doesParse declaration) testCommentsTrue
illegalCommentsTests :: Test
illegalCommentsTests = TestLabel "illegal comments" $
TestList $ map (doesNotParse declaration) testCommentsFalse
testCommentsTrue :: [String]
testCommentsTrue =
[ "int a; // a comment"
, "int a; /* another comment */"
, "int a; // a comment\n"
, "int a; /* another comment */\n"
, "int a; /* another comment\non multiple\nlines.*/"
, "int a; /* another comment\non multiple\nlines.*/\n"
, "int a; /* another comment\non multiple\nlines.\n*/"
, "/* before */ int a;"
, "// before\nint a;"
, "int /* middle */ a;"
, "int/* middle */a;"
, "int a/* middle */;"
, "int a; /* not a // nested comment */"
]
testCommentsFalse :: [String]
testCommentsFalse =
[ "int a; /* no /* nested */ comment */"
]
legalTranslationUnitsTests :: Test
legalTranslationUnitsTests = TestLabel "legal translation unit" $
TestList $ map (doesParse translationUnit) $
testDeclarationsTrue ++ testFunctionDefinitionsTrue