001    package sysModel.env;
002    
003    import junit.framework.TestCase;
004    import model.ILambda;
005    import model.fish.GenericFish;
006    import sysModel.ICmdFactory;
007    import sysModel.ISecurityAdapter;
008    import sysModel.NoOpLambda;
009    import sysModel.fish.IFishFactory;
010    import sysModel.fish.AFish;
011    import sysModel.parser.DefaultTokenVisitor;
012    import sysModel.parser.Lexer;
013    import sysModel.parser.ParserException;
014    
015    import javax.swing.*;
016    import java.awt.*;
017    import java.awt.event.MouseEvent;
018    import java.util.LinkedList;
019    
020    /**
021     * Implementation of a square wrapping environment.
022     *
023     * @author Mathias G. Ricken
024     */
025    public class WrappingEnv extends BoundedEnv {
026    
027        /**
028         * Factory method for overridden Location.
029         *
030         * @param x x coordinate
031         * @param y y coordinate
032         * @return new WrappingEnv.Location at (x, y)
033         */
034        public ASquareEnv.Location makeLocation(double x, double y) {
035            return new Location(x, y);
036        }
037    
038        /**
039         * Overridden location class that does wrapping.
040         *
041         * @author Mathias G. Ricken
042         */
043        public class Location extends ASquareEnv.Location {
044            /**
045             * Ctor for location.
046             *
047             * @param x x position
048             * @param y y position
049             */
050            public Location(double x, double y) {
051                super(x, y);
052            }
053    
054            /**
055             * Return the location of a neighbor in the given direction.
056             *
057             * @param dir the direction of the neighbor to be returned
058             * @return neighbor in that direction
059             */
060            public ASquareEnv.Location getNeighbor(Direction dir) {
061                double newX = getX() + dir.getDeltaX();
062                double newY = getY() + dir.getDeltaY();
063                if (0 > newX) {
064                    newX = _width + newX;
065                }
066                else if (newX >= _width) {
067                    newX = newX - _width;
068                }
069                if (0 > newY) {
070                    newY = _height + newY;
071                }
072                else if (newY >= _height) {
073                    newY = newY - _height;
074                }
075                return makeLocation(newX, newY);
076            }
077        }
078    
079        /**
080         * Construct a new square wrapping environment. Does not set this object up for actual use. Note: This constructor
081         * needs to exist and be public for the "environment selection" dialog to work.
082         *
083         * @param cmdFactory command factory to use
084         * @param sm         security manager to control fish action
085         */
086        public WrappingEnv(ICmdFactory cmdFactory, ISecurityAdapter sm) {
087            super(cmdFactory, sm);
088        }
089    
090        /**
091         * Construct a new square wrapping environment.
092         *
093         * @param cmdFactory command factory to use
094         * @param sm         security manager to control fish actions
095         * @param width      width of environment
096         * @param height     height of environment
097         */
098        public WrappingEnv(ICmdFactory cmdFactory, ISecurityAdapter sm, int width, int height) {
099            super(cmdFactory, sm, width, height);
100        }
101    
102        /**
103         * Get the environment settings class.
104         *
105         * @return environment settings class
106         */
107        public AEnvFactory makeEnvFactory() {
108            return new AEnvFactory() {
109                private JTextField _rowField;
110                private JTextField _colField;
111    
112                {
113                    setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
114                    add(new JLabel("rows: "));
115                    add(_rowField = new JTextField("10"));
116                    add(new JLabel("  cols: "));
117                    add(_colField = new JTextField("10"));
118                }
119    
120                public AGlobalEnv create() {
121                    return new WrappingEnv(_cmdFactory,
122                                           _securityAdapter,
123                                           Integer.parseInt(_colField.getText()),
124                                           Integer.parseInt(_rowField.getText()));
125                }
126    
127                public String toString() {
128                    return WrappingEnv.class.getName();
129                }
130            };
131        }
132    
133        /**
134         * Factory method for parsing a stream of tokens and creating a global environment from it.
135         *
136         * @param l lexer
137         * @return new global environment
138         */
139        protected AGlobalEnv parseEnvironment(final Lexer l) {
140            // have to read size of environment
141            return (AGlobalEnv) l.nextToken().execute(new DefaultTokenVisitor() {
142                public Object defaultCase() {
143                    throw new ParserException("Invalid token");
144                }
145    
146                public Object numCase(final double width) {
147                    // width was read
148                    return (AGlobalEnv) l.nextToken().execute(new DefaultTokenVisitor() {
149                        public Object defaultCase() {
150                            throw new ParserException("Invalid token");
151                        }
152    
153                        public Object numCase(double height) {
154                            // height was read
155                            BoundedEnv env = new WrappingEnv(_cmdFactory, _securityAdapter, (int) width, (int) height);
156    
157                            // parse fish
158                            env.parseFish(l);
159    
160                            return env;
161                        }
162                    });
163                }
164            });
165        }
166    
167        /*****************************************************************************************************************
168         * Tests follow
169         *****************************************************************************************************************/
170    
171        /**
172         * Test cases for WrappingEnv.
173         *
174         * @author Mathias Ricken
175         */
176        public static class Test_WrappingEnv extends TestCase {
177            private ICmdFactory _cmdFactory;
178            private ISecurityAdapter _sm;
179            private WrappingEnv _env;
180            private IFishFactory _fishFactory;
181    
182            private static final ILambda _notify = new ILambda() {
183                public Object apply(Object param) {
184                    return "notifyCmd";
185                }
186            };
187            private static final ILambda _delete = new ILambda() {
188                public Object apply(Object param) {
189                    return "deleteCmd";
190                }
191            };
192            private static final ILambda _add = new ILambda() {
193                public Object apply(Object param) {
194                    return "addCmd";
195                }
196            };
197    
198            public void setUp() throws Exception {
199                super.setUp();
200                _cmdFactory = new ICmdFactory() {
201                    public ILambda makeNotifyCmd(ILambda lambda) {
202                        return _notify;
203                    }
204    
205                    public ILambda makeDeleteCmd(ALocalEnv env) {
206                        return _delete;
207                    }
208    
209                    public ILambda makeAddCmd(AFish fish) {
210                        return _add;
211                    }
212                };
213                _sm = new ISecurityAdapter() {
214                    public void setProtected(boolean _protected) {
215                    }
216                    public ThreadGroup getFishThreadGroup() {
217                        return null;
218                    }
219                    public ClassLoader getClassLoader() {
220                        return null;
221                    }
222                    public void handleException(Throwable t) {
223                    }
224                };
225    
226                _env = new WrappingEnv(_cmdFactory, _sm, 10, 10);
227    
228                _fishFactory = new IFishFactory() {
229                    /**
230                     * Create a new fish.
231                     *
232                     * @return new fish
233                     */
234                    public AFish createFish() {
235                        return new GenericFish(Color.RED);
236                    }
237                };
238            }
239    
240            int countNonEmpty() {
241                int count = 0;
242                WrappingEnv.IField[][] map = _env._fieldMap;
243                IFieldVisitor countVisitor = new IFieldVisitor() {
244                    public Object emptyCase(EmptyField host, Object param) {
245                        return new Integer(0);
246                    }
247    
248                    public Object nonEmptyCase(NonEmptyField host, Object param) {
249                        return new Integer(1);
250                    }
251                };
252                for (int i = 0; i < map.length; i++) {
253                    WrappingEnv.IField[] iFields = map[i];
254                    for (int j = 0; j < iFields.length; j++) {
255                        WrappingEnv.IField iField = iFields[j];
256                        count += ((Integer) iField.execute(countVisitor, null)).intValue();
257                    }
258                }
259                return count;
260            }
261    
262            /**
263             * Test addFishToInternalData.
264             */
265            public void testAddFish() {
266                assertEquals(0, countNonEmpty());
267    
268                ALocalEnv lTop = _env.makeLocalEnv(new Point.Double(1.0, 1.0));
269                GenericFish fTop = new GenericFish(Color.RED);
270                fTop.setLocalEnvironment(lTop);
271                _env.addFishToInternalData(lTop, fTop);
272    
273                assertEquals(1, countNonEmpty());
274    
275                ALocalEnv lBottom = _env.makeLocalEnv(new Point.Double(1.0, 2.0));
276                GenericFish fBottom = new GenericFish(Color.RED);
277                fBottom.setLocalEnvironment(lBottom);
278                _env.addFishToInternalData(lBottom, fBottom);
279    
280                assertEquals(2, countNonEmpty());
281            }
282    
283            /**
284             * Test editFish.
285             */
286            public void testEditFish() {
287                assertEquals(0, countNonEmpty());
288    
289                ASquareLocalEnvironment l = (ASquareLocalEnvironment) _env.makeLocalEnv(new Point.Double(1.0, 1.0));
290                GenericFish f = new GenericFish(Color.RED);
291                f.setLocalEnvironment(l);
292                _env.addFishToInternalData(l, f);
293                WrappingEnv.Direction d = l.direction();
294    
295                assertEquals(1, countNonEmpty());
296                assertEquals(0.0, d.getAngle(), 0.01);
297    
298                ILambda lambda = _env.editFish(l, _fishFactory, MouseEvent.BUTTON1);
299                assertEquals(1, countNonEmpty());
300                assertEquals(Math.PI / 2.0, d.getAngle(), 0.01);
301                assertEquals(NoOpLambda.instance(), lambda);
302    
303                lambda = _env.editFish(l, _fishFactory, MouseEvent.BUTTON1);
304                assertEquals(1, countNonEmpty());
305                assertEquals(Math.PI, d.getAngle(), 0.01);
306                assertEquals(NoOpLambda.instance(), lambda);
307    
308                lambda = _env.editFish(l, _fishFactory, MouseEvent.BUTTON1);
309                assertEquals(1, countNonEmpty());
310                assertEquals(3 * Math.PI / 2.0, d.getAngle(), 0.01);
311                assertEquals(NoOpLambda.instance(), lambda);
312    
313                lambda = _env.editFish(l, _fishFactory, MouseEvent.BUTTON1);
314                assertEquals(0, countNonEmpty());
315                assertEquals(0, d.getAngle(), 0.01);
316                assertEquals(_delete, lambda);
317            }
318    
319            /**
320             * Test getViewPosition.
321             */
322            public void testGetViewPosition() {
323                assertTrue(_env.getViewPosition(new Point.Double(0, 0)).equals(new Point.Double(0, 0)));
324                assertTrue(_env.getViewPosition(new Point.Double(1.0, 0)).equals(new Point.Double(1.0, 0)));
325                assertTrue(_env.getViewPosition(new Point.Double(1.2, 0)).equals(new Point.Double(1.2, 0)));
326                assertTrue(_env.getViewPosition(new Point.Double(0, 1.0)).equals(new Point.Double(0, 1.0)));
327                assertTrue(_env.getViewPosition(new Point.Double(0, 1.3)).equals(new Point.Double(0, 1.3)));
328                assertTrue(_env.getViewPosition(new Point.Double(-2.5, 0)).equals(new Point.Double(-2.5, 0)));
329                assertTrue(_env.getViewPosition(new Point.Double(-3.0, 0)).equals(new Point.Double(-3.0, 0)));
330                assertTrue(_env.getViewPosition(new Point.Double(0, -2.5)).equals(new Point.Double(0, -2.5)));
331                assertTrue(_env.getViewPosition(new Point.Double(0, -3.0)).equals(new Point.Double(0, -3.0)));
332                assertTrue(_env.getViewPosition(new Point.Double(2.0, 1.0)).equals(new Point.Double(2.0, 1.0)));
333                assertTrue(_env.getViewPosition(new Point.Double(-4.0, -2.3)).equals(new Point.Double(-4.0, -2.3)));
334            }
335    
336            /**
337             * Test getPanDelta.
338             */
339            public void testGetPanDelta() {
340                assertTrue(_env.getPanDelta(new Point.Double(0, 0)).equals(new Point.Double(0, 0)));
341                assertTrue(_env.getPanDelta(new Point.Double(1.0, 0)).equals(new Point.Double(0, 0)));
342                assertTrue(_env.getPanDelta(new Point.Double(1.2, 0)).equals(new Point.Double(0, 0)));
343                assertTrue(_env.getPanDelta(new Point.Double(0, 1.0)).equals(new Point.Double(0, 0)));
344                assertTrue(_env.getPanDelta(new Point.Double(0, 1.3)).equals(new Point.Double(0, 0)));
345                assertTrue(_env.getPanDelta(new Point.Double(-2.5, 0)).equals(new Point.Double(0, 0)));
346                assertTrue(_env.getPanDelta(new Point.Double(-3.0, 0)).equals(new Point.Double(0, 0)));
347                assertTrue(_env.getPanDelta(new Point.Double(0, -2.5)).equals(new Point.Double(0, 0)));
348                assertTrue(_env.getPanDelta(new Point.Double(0, -3.0)).equals(new Point.Double(0, 0)));
349                assertTrue(_env.getPanDelta(new Point.Double(2.0, 1.0)).equals(new Point.Double(0, 0)));
350                assertTrue(_env.getPanDelta(new Point.Double(-4.0, -2.3)).equals(new Point.Double(0, 0)));
351            }
352        }
353    
354        /**
355         * Test cases for WrappingEnv.LocalEnv.
356         *
357         * @author Mathias Ricken
358         */
359        public static class Test_WrappingEnv_LocalEnv extends TestCase {
360            private ICmdFactory _cmdFactory;
361            private ISecurityAdapter _sm;
362            private WrappingEnv _env;
363    
364            private static class SuccessException extends RuntimeException {
365                public SuccessException() {
366                    super();
367                }
368            }
369    
370            private static final ILambda _notify = new ILambda() {
371                public Object apply(Object param) {
372                    return "notifyCmd";
373                }
374            };
375            private static final ILambda _delete = new ILambda() {
376                public Object apply(Object param) {
377                    return "deleteCmd";
378                }
379            };
380            private static final ILambda _add = new ILambda() {
381                public Object apply(Object param) {
382                    return "addCmd";
383                }
384            };
385    
386            public void setUp() throws Exception {
387                super.setUp();
388                _cmdFactory = new ICmdFactory() {
389                    public ILambda makeNotifyCmd(ILambda lambda) {
390                        return _notify;
391                    }
392    
393                    public ILambda makeDeleteCmd(ALocalEnv env) {
394                        return _delete;
395                    }
396    
397                    public ILambda makeAddCmd(AFish fish) {
398                        return _add;
399                    }
400                };
401                _sm = new ISecurityAdapter() {
402                    public void setProtected(boolean _protected) {
403                    }
404                    public ThreadGroup getFishThreadGroup() {
405                        return null;
406                    }
407                    public ClassLoader getClassLoader() {
408                        return null;
409                    }
410                    public void handleException(Throwable t) {
411                    }
412                };
413    
414                _env = new WrappingEnv(_cmdFactory, _sm, 10, 10);
415            }
416    
417            /**
418             * Test local environment's execute.
419             */
420            public void testExecute() {
421                ALocalEnv l = _env.makeLocalEnv(new Point.Double(1, 1));
422    
423                try {
424                    l.execute(new AGlobalEnv.ILocalEnvVisitor() {
425                        public Object emptyCase(ALocalEnv host, Object param) {
426                            // ok
427                            throw new SuccessException();
428                        }
429    
430                        public Object nonEmptyCase(ALocalEnv host, Object param) {
431                            throw new RuntimeException("Should be empty");
432                        }
433                    }, null);
434                    fail("emptyCase should have been called --");
435                }
436                catch (SuccessException e) {
437                }
438    
439    
440                GenericFish f = new GenericFish(Color.RED);
441                f.setLocalEnvironment(l);
442                _env.addFish(l, f);
443                l.setState(NonEmptyLocalEnvState.Singleton);
444                try {
445                    l.execute(new AGlobalEnv.ILocalEnvVisitor() {
446                        public Object emptyCase(ALocalEnv host, Object param) {
447                            throw new RuntimeException("Should be non-empty");
448                        }
449    
450                        public Object nonEmptyCase(ALocalEnv host, Object param) {
451                            // ok
452                            throw new SuccessException();
453                        }
454                    }, null);
455                    fail("nonEmptyCase should have been called --");
456                }
457                catch (SuccessException e) {
458                }
459    
460                ALocalEnv l2 = _env.makeLocalEnv(new Point.Double(1, 1));
461                try {
462                    l2.execute(new AGlobalEnv.ILocalEnvVisitor() {
463                        public Object emptyCase(ALocalEnv host, Object param) {
464                            throw new RuntimeException("Should be non-empty");
465                        }
466    
467                        public Object nonEmptyCase(ALocalEnv host, Object param) {
468                            // ok
469                            throw new SuccessException();
470                        }
471                    }, null);
472                    fail("nonEmptyCase should have been called --");
473                }
474                catch (SuccessException e) {
475                }
476    
477                ALocalEnv l3 = _env.makeLocalEnv(new Point.Double(1.4, 1.6));
478                try {
479                    l3.execute(new AGlobalEnv.ILocalEnvVisitor() {
480                        public Object emptyCase(ALocalEnv host, Object param) {
481                            throw new RuntimeException("Should be non-empty");
482                        }
483    
484                        public Object nonEmptyCase(ALocalEnv host, Object param) {
485                            // ok
486                            throw new SuccessException();
487                        }
488                    }, null);
489                    fail("nonEmptyCase should have been called --");
490                }
491                catch (SuccessException e) {
492                }
493    
494                ALocalEnv l4 = _env.makeLocalEnv(new Point.Double(1.0, 2.0));
495                try {
496                    l4.execute(new AGlobalEnv.ILocalEnvVisitor() {
497                        public Object emptyCase(ALocalEnv host, Object param) {
498                            // ok
499                            throw new SuccessException();
500                        }
501    
502                        public Object nonEmptyCase(ALocalEnv host, Object param) {
503                            throw new RuntimeException("Should be empty");
504                        }
505                    }, null);
506                    fail("emptyCase should have been called --");
507                }
508                catch (SuccessException e) {
509                }
510    
511                GenericFish f4 = new GenericFish(Color.RED);
512                f4.setLocalEnvironment(l4);
513                _env.addFish(l4, f4);
514                l4.setState(NonEmptyLocalEnvState.Singleton);
515                try {
516                    l4.execute(new AGlobalEnv.ILocalEnvVisitor() {
517                        public Object emptyCase(ALocalEnv host, Object param) {
518                            throw new RuntimeException("Should be non-empty");
519                        }
520    
521                        public Object nonEmptyCase(ALocalEnv host, Object param) {
522                            // ok
523                            throw new SuccessException();
524                        }
525                    }, null);
526                    fail("nonEmptyCase should have been called --");
527                }
528                catch (SuccessException e) {
529                }
530            }
531    
532            /**
533             * Test local environment's tryMoveFwd.
534             */
535            public void testTryMoveFwd() {
536                ALocalEnv lTop = _env.makeLocalEnv(new Point.Double(1.0, 1.0));
537                GenericFish fTop = new GenericFish(Color.RED);
538                fTop.setLocalEnvironment(lTop);
539                _env.addFish(lTop, fTop);
540                lTop.setState(NonEmptyLocalEnvState.Singleton);
541    
542                ALocalEnv lBottom = _env.makeLocalEnv(new Point.Double(1.0, 2.0));
543                GenericFish fBottom = new GenericFish(Color.RED);
544                fBottom.setLocalEnvironment(lBottom);
545                _env.addFish(lBottom, fBottom);
546                lBottom.setState(NonEmptyLocalEnvState.Singleton);
547    
548                // move lBottom into lTop --> blocked
549                Integer i = (Integer) lBottom.tryMoveFwd(fBottom, new IBlockedCommand() {
550                    public Object apply(Object param) {
551                        // ok
552                        return new Integer(456);
553                    }
554                }, new IOpenCommand() {
555                    public Object apply(Object param) {
556                        throw new RuntimeException("Should be blocked");
557                    }
558                });
559                assertEquals("Error in delegation, blockedCmd not called, or incorrect return value --",
560                             new Integer(456),
561                             i);
562    
563                // move lTop --> open, don't move
564                i = (Integer) lTop.tryMoveFwd(fTop, new IBlockedCommand() {
565                    public Object apply(Object param) {
566                        throw new RuntimeException("Should be open");
567                    }
568                }, new IOpenCommand() {
569                    public Object apply(Object param) {
570                        assertNotNull("Error, deactivatable move lambda needs to be passed to openCmd --", param);
571                        assertEquals("Error, deactivatable move lambda needs to be passed to openCmd --",
572                                     DeactivatableLambda.class,
573                                     param.getClass());
574                        // ok
575                        return new Integer(123);
576                    }
577                });
578                assertEquals("Error in delegation, openCmd not called, or incorrect return value --", new Integer(123), i);
579    
580                // move lBottom into lTop --> blocked
581                i = (Integer) lBottom.tryMoveFwd(fBottom, new IBlockedCommand() {
582                    public Object apply(Object param) {
583                        // ok
584                        return new Integer(789);
585                    }
586                }, new IOpenCommand() {
587                    public Object apply(Object param) {
588                        throw new RuntimeException("Should be blocked");
589                    }
590                });
591                assertEquals("Error in delegation, blockedCmd not called, or incorrect return value --",
592                             new Integer(789),
593                             i);
594    
595                // move lTop --> open, move
596                i = (Integer) lTop.tryMoveFwd(fTop, new IBlockedCommand() {
597                    public Object apply(Object param) {
598                        throw new RuntimeException("Should be open");
599                    }
600                }, new IOpenCommand() {
601                    public Object apply(Object param) {
602                        assertNotNull("Error, deactivatable move lambda needs to be passed to openCmd --", param);
603                        assertEquals("Error, deactivatable move lambda needs to be passed to openCmd --",
604                                     DeactivatableLambda.class,
605                                     param.getClass());
606                        // ok, make move
607                        ((ILambda) param).apply(null);
608                        return new Integer(111);
609                    }
610                });
611                assertEquals("Error in delegation, openCmd not called, or incorrect return value --", new Integer(111), i);
612    
613                // move lBottom --> open
614                i = (Integer) lBottom.tryMoveFwd(fBottom, new IBlockedCommand() {
615                    public Object apply(Object param) {
616                        throw new RuntimeException("Should be open");
617                    }
618                }, new IOpenCommand() {
619                    public Object apply(Object param) {
620                        assertNotNull("Error, deactivatable move lambda needs to be passed to openCmd --", param);
621                        assertEquals("Error, deactivatable move lambda needs to be passed to openCmd --",
622                                     DeactivatableLambda.class,
623                                     param.getClass());
624                        // ok
625                        return new Integer(222);
626                    }
627                });
628                assertEquals("Error in delegation, openCmd not called, or incorrect return value --", new Integer(222), i);
629    
630                // move lTop into edge, wrap --> open
631                i = (Integer) lTop.tryMoveFwd(fTop, new IBlockedCommand() {
632                    public Object apply(Object param) {
633                        throw new RuntimeException("Should be open");
634                    }
635                }, new IOpenCommand() {
636                    public Object apply(Object param) {
637                        assertNotNull("Error, deactivatable move lambda needs to be passed to openCmd --", param);
638                        assertEquals("Error, deactivatable move lambda needs to be passed to openCmd --",
639                                     DeactivatableLambda.class,
640                                     param.getClass());
641                        // ok
642                        return new Integer(333);
643                    }
644                });
645                assertEquals("Error in delegation, openCmd not called, or incorrect return value --", new Integer(333), i);
646    
647                // turn and move lTop --> open
648                lTop.turnRight(fTop, Math.PI / 2.0);
649                i = (Integer) lTop.tryMoveFwd(fTop, new IBlockedCommand() {
650                    public Object apply(Object param) {
651                        throw new RuntimeException("Should be open");
652                    }
653                }, new IOpenCommand() {
654                    public Object apply(Object param) {
655                        assertNotNull("Error, deactivatable move lambda needs to be passed to openCmd --", param);
656                        assertEquals("Error, deactivatable move lambda needs to be passed to openCmd --",
657                                     DeactivatableLambda.class,
658                                     param.getClass());
659                        // ok
660                        return new Integer(444);
661                    }
662                });
663                assertEquals("Error in delegation, openCmd not called, or incorrect return value --", new Integer(444), i);
664            }
665    
666            int countNonEmpty() {
667                int count = 0;
668                WrappingEnv.IField[][] map = _env._fieldMap;
669                IFieldVisitor countVisitor = new IFieldVisitor() {
670                    public Object emptyCase(EmptyField host, Object param) {
671                        return new Integer(0);
672                    }
673    
674                    public Object nonEmptyCase(NonEmptyField host, Object param) {
675                        return new Integer(1);
676                    }
677                };
678                for (int i = 0; i < map.length; i++) {
679                    WrappingEnv.IField[] iFields = map[i];
680                    for (int j = 0; j < iFields.length; j++) {
681                        WrappingEnv.IField iField = iFields[j];
682                        count += ((Integer) iField.execute(countVisitor, null)).intValue();
683                    }
684                }
685                return count;
686            }
687    
688            /**
689             * Test local environment's tryBreedFwd.
690             */
691            public void testTryBreedFwd() {
692                assertEquals(0, countNonEmpty());
693    
694                ALocalEnv lTop = _env.makeLocalEnv(new Point.Double(1.0, 1.0));
695                GenericFish fTop = new GenericFish(Color.RED);
696                fTop.setLocalEnvironment(lTop);
697                _env.addFish(lTop, fTop);
698                lTop.setState(NonEmptyLocalEnvState.Singleton);
699    
700                assertEquals(1, countNonEmpty());
701    
702                ALocalEnv lBottom = _env.makeLocalEnv(new Point.Double(1.0, 2.0));
703                GenericFish fBottom = new GenericFish(Color.RED);
704                fBottom.setLocalEnvironment(lBottom);
705                _env.addFish(lBottom, fBottom);
706                lBottom.setState(NonEmptyLocalEnvState.Singleton);
707    
708                assertEquals(2, countNonEmpty());
709    
710                // breed lBottom into lTop --> blocked
711                Integer i = (Integer) lBottom.tryBreedFwd(fBottom, new IBlockedCommand() {
712                    public Object apply(Object param) {
713                        // ok
714                        return new Integer(456);
715                    }
716                }, new IOpenCommand() {
717                    public Object apply(Object param) {
718                        throw new RuntimeException("Should be blocked");
719                    }
720                });
721                assertEquals("Error in delegation, blockedCmd not called, or incorrect return value --",
722                             new Integer(456),
723                             i);
724    
725                // breed lTop --> open, don't breed
726                i = (Integer) lTop.tryBreedFwd(fTop, new IBlockedCommand() {
727                    public Object apply(Object param) {
728                        throw new RuntimeException("Should be open");
729                    }
730                }, new IOpenCommand() {
731                    public Object apply(Object param) {
732                        assertNotNull("Error, deactivatable breed lambda needs to be passed to openCmd --", param);
733                        assertEquals("Error, deactivatable breed lambda needs to be passed to openCmd --",
734                                     DeactivatableLambda.class,
735                                     param.getClass());
736                        // ok
737                        return new Integer(123);
738                    }
739                });
740                assertEquals("Error in delegation, openCmd not called, or incorrect return value --", new Integer(123), i);
741    
742                assertEquals(2, countNonEmpty());
743    
744                // breed lBottom into lTop --> blocked
745                i = (Integer) lBottom.tryBreedFwd(fBottom, new IBlockedCommand() {
746                    public Object apply(Object param) {
747                        // ok
748                        return new Integer(456);
749                    }
750                }, new IOpenCommand() {
751                    public Object apply(Object param) {
752                        throw new RuntimeException("Should be blocked");
753                    }
754                });
755                assertEquals("Error in delegation, blockedCmd not called, or incorrect return value --",
756                             new Integer(456),
757                             i);
758    
759                // breed lTop --> open, breed
760                i = (Integer) lTop.tryBreedFwd(fTop, new IBlockedCommand() {
761                    public Object apply(Object param) {
762                        throw new RuntimeException("Should be open");
763                    }
764                }, new IOpenCommand() {
765                    public Object apply(Object param) {
766                        assertNotNull("Error, deactivatable breed lambda needs to be passed to openCmd --", param);
767                        assertEquals("Error, deactivatable breed lambda needs to be passed to openCmd --",
768                                     DeactivatableLambda.class,
769                                     param.getClass());
770                        // ok, breed
771                        ((ILambda) param).apply(null);
772                        return new Integer(123);
773                    }
774                });
775                assertEquals("Error in delegation, openCmd not called, or incorrect return value --", new Integer(123), i);
776    
777                assertEquals(3, countNonEmpty());
778    
779                // breed lBottom into lTop --> blocked
780                i = (Integer) lBottom.tryBreedFwd(fBottom, new IBlockedCommand() {
781                    public Object apply(Object param) {
782                        // ok
783                        return new Integer(456);
784                    }
785                }, new IOpenCommand() {
786                    public Object apply(Object param) {
787                        throw new RuntimeException("Should be blocked");
788                    }
789                });
790                assertEquals("Error in delegation, blockedCmd not called, or incorrect return value --",
791                             new Integer(456),
792                             i);
793    
794                // breed lTop --> blocked
795                i = (Integer) lTop.tryBreedFwd(fTop, new IBlockedCommand() {
796                    public Object apply(Object param) {
797                        // ok
798                        return new Integer(456);
799                    }
800                }, new IOpenCommand() {
801                    public Object apply(Object param) {
802                        throw new RuntimeException("Should be blocked");
803                    }
804                });
805                assertEquals("Error in delegation, blockedCmd not called, or incorrect return value --",
806                             new Integer(456),
807                             i);
808    
809                // turn and breed lTop --> open, don't breed
810                lTop.turnRight(fTop, Math.PI / 2.0);
811                i = (Integer) lTop.tryBreedFwd(fTop, new IBlockedCommand() {
812                    public Object apply(Object param) {
813                        throw new RuntimeException("Should be open");
814                    }
815                }, new IOpenCommand() {
816                    public Object apply(Object param) {
817                        assertNotNull("Error, deactivatable breed lambda needs to be passed to openCmd --", param);
818                        assertEquals("Error, deactivatable breed lambda needs to be passed to openCmd --",
819                                     DeactivatableLambda.class,
820                                     param.getClass());
821                        // ok
822                        return new Integer(789);
823                    }
824                });
825                assertEquals("Error in delegation, openCmd not called, or incorrect return value --", new Integer(789), i);
826    
827                assertEquals(3, countNonEmpty());
828    
829                // turn and breed lTop --> open, breed
830                i = (Integer) lTop.tryBreedFwd(fTop, new IBlockedCommand() {
831                    public Object apply(Object param) {
832                        throw new RuntimeException("Should be open");
833                    }
834                }, new IOpenCommand() {
835                    public Object apply(Object param) {
836                        assertNotNull("Error, deactivatable breed lambda needs to be passed to openCmd --", param);
837                        assertEquals("Error, deactivatable breed lambda needs to be passed to openCmd --",
838                                     DeactivatableLambda.class,
839                                     param.getClass());
840                        // ok, breed
841                        ((ILambda) param).apply(null);
842                        return new Integer(789);
843                    }
844                });
845                assertEquals("Error in delegation, openCmd not called, or incorrect return value --", new Integer(789), i);
846    
847                assertEquals(4, countNonEmpty());
848    
849                // turn and breed lTop --> blocked
850                i = (Integer) lTop.tryBreedFwd(fTop, new IBlockedCommand() {
851                    public Object apply(Object param) {
852                        // ok
853                        return new Integer(789);
854                    }
855                }, new IOpenCommand() {
856                    public Object apply(Object param) {
857                        throw new RuntimeException("Should be blocked");
858                    }
859                });
860                assertEquals("Error in delegation, blockedCmd not called, or incorrect return value --",
861                             new Integer(789),
862                             i);
863    
864                assertEquals(4, countNonEmpty());
865            }
866    
867            /**
868             * Test local environment's turnRight.
869             */
870            public void testTurnRight() {
871                ASquareLocalEnvironment l = (ASquareLocalEnvironment) _env.makeLocalEnv(new Point.Double(1.0, 1.0));
872                GenericFish f = new GenericFish(Color.RED);
873                f.setLocalEnvironment(l);
874                _env.addFish(l, f);
875                l.setState(NonEmptyLocalEnvState.Singleton);
876                WrappingEnv.Direction d = l.direction();
877    
878                assertEquals(0.0, d.getAngle(), 0.01);
879                l.turnRight(f, Math.PI / 2);
880                assertEquals(Math.PI / 2.0, d.getAngle(), 0.01);
881                l.turnRight(f, Math.PI / 2);
882                assertEquals(Math.PI, d.getAngle(), 0.01);
883                l.turnRight(f, Math.PI / 2);
884                assertEquals(3 * Math.PI / 2.0, d.getAngle(), 0.01);
885                l.turnRight(f, Math.PI / 2);
886                assertEquals(0, d.getAngle(), 0.01);
887            }
888    
889            /**
890             * Test local environment's removeFish.
891             */
892            public void testRemoveFish() {
893                assertEquals(0, countNonEmpty());
894    
895                ALocalEnv lTop = _env.makeLocalEnv(new Point.Double(1.0, 1.0));
896                GenericFish fTop = new GenericFish(Color.RED);
897                fTop.setLocalEnvironment(lTop);
898                _env.addFish(lTop, fTop);
899                lTop.setState(NonEmptyLocalEnvState.Singleton);
900    
901                assertEquals(1, countNonEmpty());
902    
903                ALocalEnv lBottom = _env.makeLocalEnv(new Point.Double(1.0, 2.0));
904                GenericFish fBottom = new GenericFish(Color.RED);
905                fBottom.setLocalEnvironment(lBottom);
906                _env.addFish(lBottom, fBottom);
907                lBottom.setState(NonEmptyLocalEnvState.Singleton);
908    
909                assertEquals(2, countNonEmpty());
910    
911                lTop.removeFish(fTop);
912    
913                assertEquals(1, countNonEmpty());
914    
915                lBottom.removeFish(fBottom);
916    
917                assertEquals(0, countNonEmpty());
918            }
919    
920            /**
921             * Test to make sure only one move lambda can be executed.
922             */
923            public void testOnlyOneMove() {
924                ASquareLocalEnvironment l = (ASquareLocalEnvironment) _env.makeLocalEnv(new Point.Double(5.0, 5.0));
925                GenericFish f = new GenericFish(Color.RED);
926                f.setLocalEnvironment(l);
927                _env.addFish(l, f);
928                l.setState(NonEmptyLocalEnvState.Singleton);
929    
930                final LinkedList<ILambda> lambdas = new LinkedList<ILambda>();
931                l.tryMoveFwd(f, new IBlockedCommand() {
932                    public Object apply(Object param) {
933                        throw new RuntimeException("Should be open");
934                    }
935                }, new IOpenCommand() {
936                    public Object apply(Object param) {
937                        lambdas.add((ILambda)param);
938                        return null;
939                    }
940                });
941                f.turnRight();
942                l.tryMoveFwd(f, new IBlockedCommand() {
943                    public Object apply(Object param) {
944                        throw new RuntimeException("Should be open");
945                    }
946                }, new IOpenCommand() {
947                    public Object apply(Object param) {
948                        lambdas.add((ILambda)param);
949                        return null;
950                    }
951                });
952    
953                assertEquals(2, lambdas.size());
954    
955                lambdas.get(0).apply(null);
956                Location loc = (Location) l.location();
957                assertTrue(loc.same(_env.makeLocation(5.0, 4.0)));
958    
959                lambdas.get(1).apply(null);
960                loc = (Location) l.location();
961                assertTrue(loc.same(_env.makeLocation(5.0, 4.0)));
962    
963                lambdas.clear();
964                l.tryMoveFwd(f, new IBlockedCommand() {
965                    public Object apply(Object param) {
966                        throw new RuntimeException("Should be open");
967                    }
968                }, new IOpenCommand() {
969                    public Object apply(Object param) {
970                        lambdas.add((ILambda)param);
971                        return null;
972                    }
973                });
974                f.turnRight();
975                l.tryMoveFwd(f, new IBlockedCommand() {
976                    public Object apply(Object param) {
977                        throw new RuntimeException("Should be open");
978                    }
979                }, new IOpenCommand() {
980                    public Object apply(Object param) {
981                        lambdas.add((ILambda)param);
982                        return null;
983                    }
984                });
985    
986                assertEquals(2, lambdas.size());
987    
988                lambdas.get(1).apply(null);
989                loc = (Location) l.location();
990                assertTrue(loc.same(_env.makeLocation(6.0, 4.0)));
991    
992                lambdas.get(0).apply(null);
993                loc = (Location) l.location();
994                assertTrue(loc.same(_env.makeLocation(6.0, 4.0)));
995            }
996    
997        }
998    
999        /**
1000         * Test cases for WrappingEnv.Location.
1001         *
1002         * @author Mathias Ricken
1003         */
1004        public static class Test_WrappingEnv_Location extends TestCase {
1005            private ICmdFactory _cmdFactory;
1006            private ISecurityAdapter _sm;
1007            private WrappingEnv _env;
1008    
1009            private static final ILambda _notify = new ILambda() {
1010                public Object apply(Object param) {
1011                    return "notifyCmd";
1012                }
1013            };
1014            private static final ILambda _delete = new ILambda() {
1015                public Object apply(Object param) {
1016                    return "deleteCmd";
1017                }
1018            };
1019            private static final ILambda _add = new ILambda() {
1020                public Object apply(Object param) {
1021                    return "addCmd";
1022                }
1023            };
1024    
1025            public void setUp() throws Exception {
1026                super.setUp();
1027                _cmdFactory = new ICmdFactory() {
1028                    public ILambda makeNotifyCmd(ILambda lambda) {
1029                        return _notify;
1030                    }
1031    
1032                    public ILambda makeDeleteCmd(ALocalEnv env) {
1033                        return _delete;
1034                    }
1035    
1036                    public ILambda makeAddCmd(AFish fish) {
1037                        return _add;
1038                    }
1039                };
1040                _sm = new ISecurityAdapter() {
1041                    public void setProtected(boolean _protected) {
1042                    }
1043                    public ThreadGroup getFishThreadGroup() {
1044                        return null;
1045                    }
1046                    public ClassLoader getClassLoader() {
1047                        return null;
1048                    }
1049                    public void handleException(Throwable t) {
1050                    }
1051                };
1052    
1053                _env = new WrappingEnv(_cmdFactory, _sm, 50, 50);
1054            }
1055    
1056            /**
1057             * Test getters, setters, and ctor.
1058             */
1059            public void testGetSet() {
1060                ASquareEnv.Location l = _env.makeLocation(5, 7);
1061                assertEquals(5.0, l.getX(), 0.01);
1062                assertEquals(7.0, l.getY(), 0.01);
1063    
1064                l.setX(11);
1065                assertEquals(11.0, l.getX(), 0.01);
1066                assertEquals(7.0, l.getY(), 0.01);
1067    
1068                l.setY(13);
1069                assertEquals(11.0, l.getX(), 0.01);
1070                assertEquals(13.0, l.getY(), 0.01);
1071            }
1072    
1073            /**
1074             * Test same.
1075             */
1076            public void testSame() {
1077                ASquareEnv.Location l = _env.makeLocation(17, 23);
1078                ASquareEnv.Location l1 = _env.makeLocation(17, 23);
1079                ASquareEnv.Location l2 = _env.makeLocation(31, 37);
1080                assertEquals(true, l.same(l1));
1081                assertEquals(false, l.same(l2));
1082                assertEquals(true, l1.same(l));
1083                assertEquals(false, l2.same(l));
1084                assertEquals(false, l2.same(l1));
1085                assertEquals(false, l1.same(l2));
1086            }
1087    
1088            /**
1089             * Test inField.
1090             */
1091            public void testInField() {
1092                ASquareEnv.Location l = _env.makeLocation(17, 23);
1093                ASquareEnv.Location l1 = _env.makeLocation(17, 23);
1094                ASquareEnv.Location l2 = _env.makeLocation(17.13, 23.53);
1095                ASquareEnv.Location l3 = _env.makeLocation(17.49, 23.77);
1096                ASquareEnv.Location l4 = _env.makeLocation(31, 37);
1097                ASquareEnv.Location l5 = _env.makeLocation(31.81, 37.51);
1098                assertEquals(true, l.inField(l1));
1099                assertEquals(true, l1.inField(l));
1100                assertEquals(true, l.inField(l2));
1101                assertEquals(true, l2.inField(l));
1102                assertEquals(true, l.inField(l3));
1103                assertEquals(true, l3.inField(l));
1104                assertEquals(false, l.inField(l4));
1105                assertEquals(false, l4.inField(l));
1106                assertEquals(false, l.inField(l5));
1107                assertEquals(false, l5.inField(l));
1108            }
1109    
1110            /**
1111             * Test getNeighbor.
1112             */
1113            public void testNeighbor() {
1114                ASquareEnv.Location l = _env.makeLocation(17, 23);
1115                ASquareEnv.Location l1 = _env.makeLocation(17, 22);
1116                ASquareEnv.Location l2 = _env.makeLocation(18, 22);
1117                ASquareEnv.Location l3 = _env.makeLocation(18, 23);
1118                ASquareEnv.Location l4 = _env.makeLocation(17, 23);
1119                l = l.getNeighbor(_env.makeDirection(0, -1));
1120                assertEquals(true, l.same(l1));
1121                l = l.getNeighbor(_env.makeDirection(1, 0));
1122                assertEquals(true, l.same(l2));
1123                l = l.getNeighbor(_env.makeDirection(0, 1));
1124                assertEquals(true, l.same(l3));
1125                l = l.getNeighbor(_env.makeDirection(-1, 0));
1126                assertEquals(true, l.same(l4));
1127    
1128                // test wrapping
1129                ASquareEnv.Location w = _env.makeLocation(0, 0);
1130                ASquareEnv.Location w1 = _env.makeLocation(0, 49);
1131                ASquareEnv.Location w2 = _env.makeLocation(49, 49);
1132                ASquareEnv.Location w3 = _env.makeLocation(49, 0);
1133                ASquareEnv.Location w4 = _env.makeLocation(0, 0);
1134                w = w.getNeighbor(_env.makeDirection(0, -1));
1135                assertEquals(true, w.same(w1));
1136                w = w.getNeighbor(_env.makeDirection(-1, 0));
1137                assertEquals(true, w.same(w2));
1138                w = w.getNeighbor(_env.makeDirection(0, 1));
1139                assertEquals(true, w.same(w3));
1140                w = w.getNeighbor(_env.makeDirection(1, 0));
1141                assertEquals(true, w.same(w4));
1142            }
1143        }
1144    }