elm-review/tests/Simplify/InferTest.elm
2022-09-01 16:22:25 +02:00

536 lines
24 KiB
Elm

module Simplify.InferTest exposing (all)
import AssocList
import Elm.Syntax.Expression exposing (Expression(..))
import Elm.Syntax.Infix as Infix exposing (InfixDirection(..))
import Elm.Syntax.Node exposing (Node(..))
import Elm.Syntax.Range as Range
import Expect exposing (Expectation)
import Simplify.Infer exposing (DeducedValue(..), Fact(..), Inferred(..), deduceNewFacts, empty, falseExpr, get, infer, trueExpr)
import Test exposing (Test, describe, test)
all : Test
all =
describe "Infer"
[ simpleTests
, detailedTests
, deduceNewFactsTests
]
simpleTests : Test
simpleTests =
describe "get"
[ test "should infer a is true when a is True" <|
\() ->
empty
|> infer [ FunctionOrValue [] "a" ] True
|> get (FunctionOrValue [] "a")
|> Expect.equal (Just trueExpr)
, test "should infer a is true when a is False" <|
\() ->
empty
|> infer [ FunctionOrValue [] "a" ] False
|> get (FunctionOrValue [] "a")
|> Expect.equal (Just falseExpr)
, test "should infer a is 1 when a == 1 is True" <|
\() ->
empty
|> infer
[ OperatorApplication "=="
Infix.Non
(n (FunctionOrValue [] "a"))
(n (Floatable 1))
]
True
|> get (FunctionOrValue [] "a")
|> Expect.equal (Just (Floatable 1))
, test "should not infer a when a == 1 is False" <|
\() ->
empty
|> infer
[ OperatorApplication "=="
Infix.Non
(n (FunctionOrValue [] "a"))
(n (Floatable 1))
]
False
|> get (FunctionOrValue [] "a")
|> Expect.equal Nothing
, test "should infer a is true when a && b is True" <|
\() ->
empty
|> infer
[ OperatorApplication "&&"
Infix.Right
(n (FunctionOrValue [] "a"))
(n (FunctionOrValue [] "b"))
]
True
|> get (FunctionOrValue [] "a")
|> Expect.equal (Just trueExpr)
, test "should infer b is true when a && b is True" <|
\() ->
empty
|> infer
[ OperatorApplication "&&"
Infix.Right
(n (FunctionOrValue [] "a"))
(n (FunctionOrValue [] "b"))
]
True
|> get (FunctionOrValue [] "b")
|> Expect.equal (Just trueExpr)
, test "should not infer a when a || b is True" <|
\() ->
empty
|> infer
[ OperatorApplication "||"
Infix.Right
(n (FunctionOrValue [] "a"))
(n (FunctionOrValue [] "b"))
]
True
|> get (FunctionOrValue [] "a")
|> Expect.equal Nothing
, test "should not infer b when a || b is True" <|
\() ->
empty
|> infer
[ OperatorApplication "||"
Infix.Right
(n (FunctionOrValue [] "a"))
(n (FunctionOrValue [] "b"))
]
True
|> get (FunctionOrValue [] "b")
|> Expect.equal Nothing
, test "should infer a is false when a || b is False" <|
\() ->
empty
|> infer
[ OperatorApplication "||"
Infix.Right
(n (FunctionOrValue [] "a"))
(n (FunctionOrValue [] "b"))
]
False
|> get (FunctionOrValue [] "a")
|> Expect.equal (Just falseExpr)
, test "should infer b is false when a || b is False" <|
\() ->
empty
|> infer
[ OperatorApplication "||"
Infix.Right
(n (FunctionOrValue [] "a"))
(n (FunctionOrValue [] "b"))
]
False
|> get (FunctionOrValue [] "b")
|> Expect.equal (Just falseExpr)
, test "should infer b is true when a || b is True and a is False" <|
\() ->
empty
|> infer
[ OperatorApplication "||"
Infix.Right
(n (FunctionOrValue [] "a"))
(n (FunctionOrValue [] "b"))
]
True
|> infer [ FunctionOrValue [] "a" ]
False
|> get (FunctionOrValue [] "b")
|> Expect.equal (Just trueExpr)
, test "should infer b is true when b || a is True and a is False" <|
\() ->
empty
|> infer
[ OperatorApplication "||"
Infix.Right
(n (FunctionOrValue [] "b"))
(n (FunctionOrValue [] "a"))
]
True
|> infer [ FunctionOrValue [] "a" ]
False
|> get (FunctionOrValue [] "b")
|> Expect.equal (Just trueExpr)
, test "should not infer b when a || b is True and a is True" <|
\() ->
empty
|> infer
[ OperatorApplication "||"
Infix.Right
(n (FunctionOrValue [] "a"))
(n (FunctionOrValue [] "b"))
]
True
|> infer [ FunctionOrValue [] "a" ]
True
|> get (FunctionOrValue [] "b")
|> Expect.equal Nothing
]
detailedTests : Test
detailedTests =
describe "infer"
[ test "should infer a when True" <|
\() ->
infer
[ FunctionOrValue [] "a" ]
True
empty
|> expectEqual
{ facts =
[ NotEquals (FunctionOrValue [] "a") falseExpr
, Equals (FunctionOrValue [] "a") trueExpr
]
, deduced =
[ ( FunctionOrValue [] "a"
, DTrue
)
]
}
, test "should infer a when False" <|
\() ->
infer
[ FunctionOrValue [] "a" ]
False
empty
|> expectEqual
{ facts =
[ NotEquals (FunctionOrValue [] "a") trueExpr
, Equals (FunctionOrValue [] "a") falseExpr
]
, deduced =
[ ( FunctionOrValue [] "a"
, DFalse
)
]
}
, test "should infer a == True when True" <|
\() ->
infer
[ OperatorApplication "=="
Infix.Non
(n (FunctionOrValue [] "a"))
(n trueExpr)
]
True
empty
|> expectEqual
{ deduced =
[ ( FunctionOrValue [] "a", DTrue )
, ( OperatorApplication "/=" Non (n (FunctionOrValue [] "a")) (n trueExpr), DFalse )
, ( OperatorApplication "==" Non (n (FunctionOrValue [] "a")) (n trueExpr), DTrue )
]
, facts =
[ Equals (FunctionOrValue [] "a") trueExpr
, NotEquals (OperatorApplication "/=" Non (n (FunctionOrValue [] "a")) (n trueExpr)) trueExpr
, NotEquals (OperatorApplication "==" Non (n (FunctionOrValue [] "a")) (n trueExpr)) falseExpr
, Equals (OperatorApplication "==" Non (n (FunctionOrValue [] "a")) (n trueExpr)) trueExpr
]
}
, test "should infer a == True when False" <|
\() ->
infer
[ OperatorApplication "=="
Infix.Non
(n (FunctionOrValue [] "a"))
(n trueExpr)
]
False
empty
|> expectEqual
{ facts =
[ Equals (FunctionOrValue [] "a") falseExpr
, NotEquals (OperatorApplication "==" Non (n (FunctionOrValue [] "a")) (n trueExpr)) trueExpr
, Equals (OperatorApplication "==" Non (n (FunctionOrValue [] "a")) (n trueExpr)) falseExpr
]
, deduced =
[ ( FunctionOrValue [] "a"
, DFalse
)
, ( OperatorApplication "=="
Non
(n (FunctionOrValue [] "a"))
(n trueExpr)
, DFalse
)
]
}
, test "should infer a == 1 when True" <|
\() ->
infer
[ OperatorApplication "=="
Infix.Non
(n (FunctionOrValue [] "a"))
(n (Floatable 1))
]
True
empty
|> expectEqual
{ deduced =
[ ( FunctionOrValue [] "a", DNumber 1 )
, ( OperatorApplication "/=" Non (n (FunctionOrValue [] "a")) (n (Floatable 1)), DFalse )
, ( OperatorApplication "==" Non (n (FunctionOrValue [] "a")) (n (Floatable 1)), DTrue )
]
, facts =
[ Equals (FunctionOrValue [] "a") (Floatable 1)
, NotEquals (OperatorApplication "/=" Non (n (FunctionOrValue [] "a")) (n (Floatable 1))) trueExpr
, NotEquals (OperatorApplication "==" Non (n (FunctionOrValue [] "a")) (n (Floatable 1))) falseExpr
, Equals (OperatorApplication "==" Non (n (FunctionOrValue [] "a")) (n (Floatable 1))) trueExpr
]
}
, test "should infer a == 1 when False" <|
\() ->
infer
[ OperatorApplication "=="
Infix.Non
(n (FunctionOrValue [] "a"))
(n (Floatable 1))
]
False
empty
|> expectEqual
{ facts =
[ NotEquals (FunctionOrValue [] "a") (Floatable 1)
, NotEquals (OperatorApplication "==" Non (n (FunctionOrValue [] "a")) (n (Floatable 1))) trueExpr
, Equals (OperatorApplication "==" Non (n (FunctionOrValue [] "a")) (n (Floatable 1))) falseExpr
]
, deduced =
[ ( OperatorApplication "=="
Non
(n (FunctionOrValue [] "a"))
(n (Floatable 1))
, DFalse
)
]
}
, test "should infer a == \"ok\" when True" <|
\() ->
infer
[ OperatorApplication "=="
Infix.Non
(n (FunctionOrValue [] "a"))
(n (Literal "\"ok\""))
]
True
empty
|> expectEqual
{ deduced =
[ ( FunctionOrValue [] "a", DString "\"ok\"" )
, ( OperatorApplication "/=" Non (n (FunctionOrValue [] "a")) (n (Literal "\"ok\"")), DFalse )
, ( OperatorApplication "==" Non (n (FunctionOrValue [] "a")) (n (Literal "\"ok\"")), DTrue )
]
, facts =
[ Equals (FunctionOrValue [] "a") (Literal "\"ok\"")
, NotEquals (OperatorApplication "/=" Non (n (FunctionOrValue [] "a")) (n (Literal "\"ok\""))) trueExpr
, NotEquals (OperatorApplication "==" Non (n (FunctionOrValue [] "a")) (n (Literal "\"ok\""))) falseExpr
, Equals (OperatorApplication "==" Non (n (FunctionOrValue [] "a")) (n (Literal "\"ok\""))) trueExpr
]
}
, test "should infer a == \"ok\" when False" <|
\() ->
infer
[ OperatorApplication "=="
Infix.Non
(n (FunctionOrValue [] "a"))
(n (Literal "\"ok\""))
]
False
empty
|> expectEqual
{ facts =
[ NotEquals (FunctionOrValue [] "a") (Literal "\"ok\"")
, NotEquals (OperatorApplication "==" Non (n (FunctionOrValue [] "a")) (n (Literal "\"ok\""))) trueExpr
, Equals (OperatorApplication "==" Non (n (FunctionOrValue [] "a")) (n (Literal "\"ok\""))) falseExpr
]
, deduced =
[ ( OperatorApplication "=="
Non
(n (FunctionOrValue [] "a"))
(n (Literal "\"ok\""))
, DFalse
)
]
}
, test "should infer a && b when True" <|
\() ->
infer
[ OperatorApplication "&&"
Infix.Right
(n (FunctionOrValue [] "a"))
(n (FunctionOrValue [] "b"))
]
True
empty
|> expectEqual
{ facts =
[ NotEquals (FunctionOrValue [] "b") falseExpr
, Equals (FunctionOrValue [] "b") trueExpr
, NotEquals (FunctionOrValue [] "a") falseExpr
, Equals (FunctionOrValue [] "a") trueExpr
, NotEquals (OperatorApplication "&&" Right (n (FunctionOrValue [] "a")) (n (FunctionOrValue [] "b"))) falseExpr
, Equals (OperatorApplication "&&" Right (n (FunctionOrValue [] "a")) (n (FunctionOrValue [] "b"))) trueExpr
]
, deduced =
[ ( FunctionOrValue [] "b", DTrue )
, ( FunctionOrValue [] "a", DTrue )
, ( OperatorApplication "&&"
Right
(n (FunctionOrValue [] "a"))
(n (FunctionOrValue [] "b"))
, DTrue
)
]
}
, test "should infer a && b when False" <|
\() ->
infer
[ OperatorApplication "&&"
Infix.Right
(n (FunctionOrValue [] "a"))
(n (FunctionOrValue [] "b"))
]
False
empty
|> expectEqual
{ facts =
[ Or [ Equals (FunctionOrValue [] "a") falseExpr, NotEquals (FunctionOrValue [] "a") trueExpr ] [ Equals (FunctionOrValue [] "b") falseExpr, NotEquals (FunctionOrValue [] "b") trueExpr ]
, NotEquals (OperatorApplication "&&" Right (n (FunctionOrValue [] "a")) (n (FunctionOrValue [] "b"))) trueExpr
, Equals (OperatorApplication "&&" Right (n (FunctionOrValue [] "a")) (n (FunctionOrValue [] "b"))) falseExpr
]
, deduced =
[ ( OperatorApplication "&&"
Right
(n (FunctionOrValue [] "a"))
(n (FunctionOrValue [] "b"))
, DFalse
)
]
}
, test "should infer a || b when True" <|
\() ->
infer
[ OperatorApplication "||"
Infix.Right
(n (FunctionOrValue [] "a"))
(n (FunctionOrValue [] "b"))
]
True
empty
|> expectEqual
{ facts =
[ Or [ Equals (FunctionOrValue [] "a") trueExpr, NotEquals (FunctionOrValue [] "a") falseExpr ] [ Equals (FunctionOrValue [] "b") trueExpr, NotEquals (FunctionOrValue [] "b") falseExpr ]
, NotEquals (OperatorApplication "||" Right (n (FunctionOrValue [] "a")) (n (FunctionOrValue [] "b"))) falseExpr
, Equals (OperatorApplication "||" Right (n (FunctionOrValue [] "a")) (n (FunctionOrValue [] "b"))) trueExpr
]
, deduced =
[ ( OperatorApplication "||"
Right
(n (FunctionOrValue [] "a"))
(n (FunctionOrValue [] "b"))
, DTrue
)
]
}
, test "should infer a || b when False" <|
\() ->
infer
[ OperatorApplication "||"
Infix.Right
(n (FunctionOrValue [] "a"))
(n (FunctionOrValue [] "b"))
]
False
empty
|> expectEqual
{ facts =
[ NotEquals (FunctionOrValue [] "b") trueExpr
, Equals (FunctionOrValue [] "b") falseExpr
, NotEquals (FunctionOrValue [] "a") trueExpr
, Equals (FunctionOrValue [] "a") falseExpr
, NotEquals (OperatorApplication "||" Right (n (FunctionOrValue [] "a")) (n (FunctionOrValue [] "b"))) trueExpr
, Equals (OperatorApplication "||" Right (n (FunctionOrValue [] "a")) (n (FunctionOrValue [] "b"))) falseExpr
]
, deduced =
[ ( FunctionOrValue [] "b", DFalse )
, ( FunctionOrValue [] "a", DFalse )
, ( OperatorApplication "||" Right (n (FunctionOrValue [] "a")) (n (FunctionOrValue [] "b")), DFalse )
]
}
, test "should infer a || b when True and a when False" <|
\() ->
empty
|> infer
[ OperatorApplication "||"
Infix.Right
(n (FunctionOrValue [] "a"))
(n (FunctionOrValue [] "b"))
]
True
|> infer [ FunctionOrValue [] "a" ]
False
|> expectEqual
{ facts =
[ NotEquals (FunctionOrValue [] "a") trueExpr
, NotEquals (FunctionOrValue [] "b") falseExpr
, Equals (FunctionOrValue [] "b") trueExpr
, Equals (FunctionOrValue [] "a") falseExpr
, Or [ Equals (FunctionOrValue [] "a") trueExpr, NotEquals (FunctionOrValue [] "a") falseExpr ] [ Equals (FunctionOrValue [] "b") trueExpr, NotEquals (FunctionOrValue [] "b") falseExpr ]
, NotEquals (OperatorApplication "||" Right (n (FunctionOrValue [] "a")) (n (FunctionOrValue [] "b"))) falseExpr
, Equals (OperatorApplication "||" Right (n (FunctionOrValue [] "a")) (n (FunctionOrValue [] "b"))) trueExpr
]
, deduced =
[ ( FunctionOrValue [] "a", DFalse )
, ( FunctionOrValue [] "b", DTrue )
, ( OperatorApplication "||" Right (n (FunctionOrValue [] "a")) (n (FunctionOrValue [] "b")), DTrue )
]
}
]
deduceNewFactsTests : Test
deduceNewFactsTests =
describe "deduceNewFacts"
[ test "should not deduce anything when facts don't share anything (a == True, b == True)" <|
\() ->
deduceNewFacts
(Equals (FunctionOrValue [] "b") trueExpr)
[ Equals (FunctionOrValue [] "a") trueExpr ]
|> Expect.equal []
, test "should deduce b is True when (a || b) and (a == False)" <|
\() ->
deduceNewFacts
(Equals (FunctionOrValue [] "a") falseExpr)
[ Or
[ Equals (FunctionOrValue [] "a") trueExpr ]
[ Equals (FunctionOrValue [] "b") trueExpr ]
]
|> Expect.equal
[ Equals (FunctionOrValue [] "b") trueExpr ]
]
expectEqual :
{ facts : List Fact
, deduced : List ( Expression, DeducedValue )
}
-> Inferred
-> Expectation
expectEqual record (Inferred inferred) =
{ facts = inferred.facts
, deduced = AssocList.toList inferred.deduced
}
|> Expect.equal record
n : Expression -> Node Expression
n =
Node Range.emptyRange