22
33namespace Tanigami \Specification ;
44
5+ use Doctrine \Common \Collections \Criteria ;
6+ use Doctrine \Common \Collections \Expr \ClosureExpressionVisitor ;
7+ use Doctrine \Common \Collections \Expr \Comparison ;
8+ use Doctrine \Common \Collections \Expr \CompositeExpression ;
9+ use Doctrine \Common \Collections \Expr \ExpressionVisitor ;
10+ use Doctrine \Common \Collections \Expr \Value ;
511use PHPUnit \Framework \TestCase ;
612use stdClass ;
713
814class SpecificationTest extends TestCase
915{
1016 public function testSpecification ()
1117 {
12- $ trueSpec = new FakeSpecification (true );
13- $ falseSpec = new FakeSpecification (false );
18+ $ trueSpec = new BoolSpecification (true );
19+ $ falseSpec = new BoolSpecification (false );
1420 $ this ->assertTrue ($ trueSpec ->isSatisfiedBy (new stdClass ));
1521 $ this ->assertFalse ($ falseSpec ->isSatisfiedBy (new stdClass ));
1622 }
1723
1824 public function testNotSpecification ()
1925 {
20- $ trueSpec = new FakeSpecification (true );
21- $ falseSpec = new FakeSpecification (false );
26+ $ trueSpec = new BoolSpecification (true );
27+ $ falseSpec = new BoolSpecification (false );
2228 $ notTrueSpec = $ trueSpec ->not ();
2329 $ notFalseSpec = $ falseSpec ->not ();
2430 $ this ->assertFalse ($ notTrueSpec ->isSatisfiedBy (new stdClass ));
@@ -27,8 +33,8 @@ public function testNotSpecification()
2733
2834 public function testAndSpecification ()
2935 {
30- $ trueSpec = new FakeSpecification (true );
31- $ falseSpec = new FakeSpecification (false );
36+ $ trueSpec = new BoolSpecification (true );
37+ $ falseSpec = new BoolSpecification (false );
3238 $ trueAndTrueSpec = $ trueSpec ->and ($ trueSpec );
3339 $ trueAndFalseSpec = $ trueSpec ->and ($ falseSpec );
3440 $ this ->assertTrue ($ trueAndTrueSpec ->isSatisfiedBy (new stdClass ));
@@ -37,8 +43,8 @@ public function testAndSpecification()
3743
3844 public function testOrSpecification ()
3945 {
40- $ trueSpec = new FakeSpecification (true );
41- $ falseSpec = new FakeSpecification (false );
46+ $ trueSpec = new BoolSpecification (true );
47+ $ falseSpec = new BoolSpecification (false );
4248 $ trueOrTrueSpec = $ trueSpec ->or ($ trueSpec );
4349 $ trueOrFalseSpec = $ trueSpec ->or ($ falseSpec );
4450 $ this ->assertTrue ($ trueOrTrueSpec ->isSatisfiedBy (new stdClass ));
@@ -47,30 +53,56 @@ public function testOrSpecification()
4753
4854 public function testAnyOfSpecification ()
4955 {
50- $ trueSpec = new FakeSpecification (true );
51- $ falseSpec = new FakeSpecification (false );
56+ $ trueSpec = new BoolSpecification (true );
57+ $ falseSpec = new BoolSpecification (false );
5258 $ this ->assertTrue ((new AnyOfSpecification ($ trueSpec , $ trueSpec , $ trueSpec ))->isSatisfiedBy (new stdClass ));
5359 $ this ->assertFalse ((new AnyOfSpecification ($ trueSpec , $ trueSpec , $ falseSpec ))->isSatisfiedBy (new stdClass ));
5460 }
5561
5662 public function testOneOfSpecification ()
5763 {
58- $ trueSpec = new FakeSpecification (true );
59- $ falseSpec = new FakeSpecification (false );
64+ $ trueSpec = new BoolSpecification (true );
65+ $ falseSpec = new BoolSpecification (false );
6066 $ this ->assertFalse ((new OneOfSpecification ($ falseSpec , $ falseSpec , $ falseSpec ))->isSatisfiedBy (new stdClass ));
6167 $ this ->assertTrue ((new OneOfSpecification ($ falseSpec , $ falseSpec , $ trueSpec ))->isSatisfiedBy (new stdClass ));
6268 }
6369
6470 public function testNoneOfSpecification ()
6571 {
66- $ trueSpec = new FakeSpecification (true );
67- $ falseSpec = new FakeSpecification (false );
72+ $ trueSpec = new BoolSpecification (true );
73+ $ falseSpec = new BoolSpecification (false );
6874 $ this ->assertTrue ((new NoneOfSpecification ($ falseSpec , $ falseSpec , $ falseSpec ))->isSatisfiedBy (new stdClass ));
6975 $ this ->assertFalse ((new NoneOfSpecification ($ falseSpec , $ falseSpec , $ trueSpec ))->isSatisfiedBy (new stdClass ));
7076 }
77+
78+ public function testCriteriaComposition ()
79+ {
80+ $ trueSpec = new BoolSpecification (true );
81+ $ falseSpec = new BoolSpecification (false );
82+ $ compositeSpec =
83+ new AnyOfSpecification (
84+ $ trueSpec ->and ($ falseSpec )->or ($ trueSpec )->and ($ falseSpec ),
85+ new OneOfSpecification ($ trueSpec , $ falseSpec , $ trueSpec ),
86+ $ trueSpec
87+ );
88+ $ visitor = new Visitor ();
89+ $ compositeSpec ->criteria ()->getWhereExpression ()->visit ($ visitor );
90+ $ this ->assertSame (
91+ '((((((bool = 1) AND (bool = 0)) OR (bool = 1)) AND (bool = 0)) AND (((bool = 1) OR (bool = 0)) OR (bool = 1))) AND (bool = 1)) ' ,
92+ $ visitor ->trace ()
93+ );
94+ }
95+
96+ /**
97+ * @expectedException \BadMethodCallException
98+ */
99+ public function testCriteriaIsNotSupported ()
100+ {
101+ (new BoolSpecification (true ))->not ()->criteria ();
102+ }
71103}
72104
73- class FakeSpecification extends Specification
105+ class BoolSpecification extends Specification
74106{
75107 private $ bool ;
76108
@@ -83,4 +115,45 @@ public function isSatisfiedBy($object): bool
83115 {
84116 return $ this ->bool ;
85117 }
118+
119+ public function criteria (): Criteria
120+ {
121+ return new Criteria (Criteria::expr ()->eq ('bool ' , $ this ->bool ));
122+ }
123+ }
124+
125+ class Visitor extends ExpressionVisitor
126+ {
127+ private $ trace ;
128+
129+ public function walkComparison (Comparison $ comparison )
130+ {
131+ $ this ->trace .= '( ' ;
132+ $ this ->trace .= $ comparison ->getField ();
133+ $ this ->trace .= ' ' . $ comparison ->getOperator () . ' ' ;
134+ $ this ->trace .= $ this ->walkValue ($ comparison ->getValue ());
135+ $ this ->trace .= ') ' ;
136+ }
137+
138+ public function walkCompositeExpression (CompositeExpression $ expr )
139+ {
140+ $ this ->trace .= '( ' ;
141+ foreach ($ expr ->getExpressionList () as $ i => $ child ) {
142+ if ($ i !== 0 ) {
143+ $ this ->trace .= (' ' . $ expr ->getType () . ' ' );
144+ }
145+ $ expressionList [] = $ this ->dispatch ($ child );
146+ }
147+ $ this ->trace .= ') ' ;
148+ }
149+
150+ public function walkValue (Value $ value )
151+ {
152+ return $ value ->getValue () ? '1 ' : '0 ' ;
153+ }
154+
155+ public function trace ()
156+ {
157+ return $ this ->trace ;
158+ }
86159}
0 commit comments