1*16467b97STreehugger Robot /* 2*16467b97STreehugger Robot [The "BSD licence"] 3*16467b97STreehugger Robot Copyright (c) 2005-2007 Kunle Odutola 4*16467b97STreehugger Robot All rights reserved. 5*16467b97STreehugger Robot 6*16467b97STreehugger Robot Redistribution and use in source and binary forms, with or without 7*16467b97STreehugger Robot modification, are permitted provided that the following conditions 8*16467b97STreehugger Robot are met: 9*16467b97STreehugger Robot 1. Redistributions of source code MUST RETAIN the above copyright 10*16467b97STreehugger Robot notice, this list of conditions and the following disclaimer. 11*16467b97STreehugger Robot 2. Redistributions in binary form MUST REPRODUCE the above copyright 12*16467b97STreehugger Robot notice, this list of conditions and the following disclaimer in 13*16467b97STreehugger Robot the documentation and/or other materials provided with the 14*16467b97STreehugger Robot distribution. 15*16467b97STreehugger Robot 3. The name of the author may not be used to endorse or promote products 16*16467b97STreehugger Robot derived from this software without specific prior WRITTEN permission. 17*16467b97STreehugger Robot 4. Unless explicitly state otherwise, any contribution intentionally 18*16467b97STreehugger Robot submitted for inclusion in this work to the copyright owner or licensor 19*16467b97STreehugger Robot shall be under the terms and conditions of this license, without any 20*16467b97STreehugger Robot additional terms or conditions. 21*16467b97STreehugger Robot 22*16467b97STreehugger Robot THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23*16467b97STreehugger Robot IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24*16467b97STreehugger Robot OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25*16467b97STreehugger Robot IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26*16467b97STreehugger Robot INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27*16467b97STreehugger Robot NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28*16467b97STreehugger Robot DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29*16467b97STreehugger Robot THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30*16467b97STreehugger Robot (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31*16467b97STreehugger Robot THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32*16467b97STreehugger Robot */ 33*16467b97STreehugger Robot 34*16467b97STreehugger Robot 35*16467b97STreehugger Robot namespace Antlr.Runtime.Tests 36*16467b97STreehugger Robot { 37*16467b97STreehugger Robot using System; 38*16467b97STreehugger Robot using StringBuilder = System.Text.StringBuilder; 39*16467b97STreehugger Robot 40*16467b97STreehugger Robot using IToken = Antlr.Runtime.IToken; 41*16467b97STreehugger Robot using Token = Antlr.Runtime.TokenTypes; 42*16467b97STreehugger Robot using CommonToken = Antlr.Runtime.CommonToken; 43*16467b97STreehugger Robot using ITree = Antlr.Runtime.Tree.ITree; 44*16467b97STreehugger Robot using ITreeNodeStream = Antlr.Runtime.Tree.ITreeNodeStream; 45*16467b97STreehugger Robot using CommonTree = Antlr.Runtime.Tree.CommonTree; 46*16467b97STreehugger Robot using CommonTreeNodeStream = Antlr.Runtime.Tree.CommonTreeNodeStream; 47*16467b97STreehugger Robot using BufferedTreeNodeStream = Antlr.Runtime.Tree.BufferedTreeNodeStream; 48*16467b97STreehugger Robot 49*16467b97STreehugger Robot using MbUnit.Framework; 50*16467b97STreehugger Robot 51*16467b97STreehugger Robot [TestFixture] 52*16467b97STreehugger Robot public class ITreeNodeStreamFixture : TestFixtureBase 53*16467b97STreehugger Robot { 54*16467b97STreehugger Robot #region BufferedTreeNodeStream Tests 55*16467b97STreehugger Robot 56*16467b97STreehugger Robot [Test] testSingleNode()57*16467b97STreehugger Robot public void testSingleNode() 58*16467b97STreehugger Robot { 59*16467b97STreehugger Robot ITree t = new CommonTree(new CommonToken(101)); 60*16467b97STreehugger Robot 61*16467b97STreehugger Robot ITreeNodeStream stream = CreateCommonTreeNodeStream(t); 62*16467b97STreehugger Robot string expected = " 101"; 63*16467b97STreehugger Robot string actual = GetStringOfEntireStreamContentsWithNodeTypesOnly(stream); 64*16467b97STreehugger Robot Assert.AreEqual(expected, actual); 65*16467b97STreehugger Robot 66*16467b97STreehugger Robot expected = " 101"; 67*16467b97STreehugger Robot actual = stream.ToString(); 68*16467b97STreehugger Robot Assert.AreEqual(expected, actual); 69*16467b97STreehugger Robot } 70*16467b97STreehugger Robot 71*16467b97STreehugger Robot [Test] 72*16467b97STreehugger Robot /// <summary> 73*16467b97STreehugger Robot /// Test a tree with four nodes - ^(101 ^(102 103) 104) 74*16467b97STreehugger Robot /// </summary> test4Nodes()75*16467b97STreehugger Robot public void test4Nodes() 76*16467b97STreehugger Robot { 77*16467b97STreehugger Robot ITree t = new CommonTree(new CommonToken(101)); 78*16467b97STreehugger Robot t.AddChild(new CommonTree(new CommonToken(102))); 79*16467b97STreehugger Robot t.GetChild(0).AddChild(new CommonTree(new CommonToken(103))); 80*16467b97STreehugger Robot t.AddChild(new CommonTree(new CommonToken(104))); 81*16467b97STreehugger Robot 82*16467b97STreehugger Robot ITreeNodeStream stream = CreateBufferedTreeNodeStream(t); 83*16467b97STreehugger Robot string expected = " 101 102 103 104"; 84*16467b97STreehugger Robot string actual = GetStringOfEntireStreamContentsWithNodeTypesOnly(stream); 85*16467b97STreehugger Robot Assert.AreEqual(expected, actual); 86*16467b97STreehugger Robot 87*16467b97STreehugger Robot expected = " 101 2 102 2 103 3 104 3"; 88*16467b97STreehugger Robot actual = stream.ToString(); 89*16467b97STreehugger Robot Assert.AreEqual(expected, actual); 90*16467b97STreehugger Robot } 91*16467b97STreehugger Robot 92*16467b97STreehugger Robot [Test] testList()93*16467b97STreehugger Robot public void testList() 94*16467b97STreehugger Robot { 95*16467b97STreehugger Robot ITree root = new CommonTree((IToken)null); 96*16467b97STreehugger Robot 97*16467b97STreehugger Robot ITree t = new CommonTree(new CommonToken(101)); 98*16467b97STreehugger Robot t.AddChild(new CommonTree(new CommonToken(102))); 99*16467b97STreehugger Robot t.GetChild(0).AddChild(new CommonTree(new CommonToken(103))); 100*16467b97STreehugger Robot t.AddChild(new CommonTree(new CommonToken(104))); 101*16467b97STreehugger Robot 102*16467b97STreehugger Robot ITree u = new CommonTree(new CommonToken(105)); 103*16467b97STreehugger Robot 104*16467b97STreehugger Robot root.AddChild(t); 105*16467b97STreehugger Robot root.AddChild(u); 106*16467b97STreehugger Robot 107*16467b97STreehugger Robot BufferedTreeNodeStream stream = new BufferedTreeNodeStream(root); 108*16467b97STreehugger Robot string expected = " 101 102 103 104 105"; 109*16467b97STreehugger Robot string actual = GetStringOfEntireStreamContentsWithNodeTypesOnly(stream); 110*16467b97STreehugger Robot Assert.AreEqual(expected, actual); 111*16467b97STreehugger Robot 112*16467b97STreehugger Robot expected = " 101 2 102 2 103 3 104 3 105"; 113*16467b97STreehugger Robot actual = stream.ToString(); 114*16467b97STreehugger Robot Assert.AreEqual(expected, actual); 115*16467b97STreehugger Robot } 116*16467b97STreehugger Robot 117*16467b97STreehugger Robot [Test] testFlatList()118*16467b97STreehugger Robot public void testFlatList() 119*16467b97STreehugger Robot { 120*16467b97STreehugger Robot ITree root = new CommonTree((IToken)null); 121*16467b97STreehugger Robot 122*16467b97STreehugger Robot root.AddChild(new CommonTree(new CommonToken(101))); 123*16467b97STreehugger Robot root.AddChild(new CommonTree(new CommonToken(102))); 124*16467b97STreehugger Robot root.AddChild(new CommonTree(new CommonToken(103))); 125*16467b97STreehugger Robot 126*16467b97STreehugger Robot BufferedTreeNodeStream stream = new BufferedTreeNodeStream(root); 127*16467b97STreehugger Robot string expected = " 101 102 103"; 128*16467b97STreehugger Robot string actual = GetStringOfEntireStreamContentsWithNodeTypesOnly(stream); 129*16467b97STreehugger Robot Assert.AreEqual(expected, actual); 130*16467b97STreehugger Robot 131*16467b97STreehugger Robot expected = " 101 102 103"; 132*16467b97STreehugger Robot actual = stream.ToString(); 133*16467b97STreehugger Robot Assert.AreEqual(expected, actual); 134*16467b97STreehugger Robot } 135*16467b97STreehugger Robot 136*16467b97STreehugger Robot [Test] testListWithOneNode()137*16467b97STreehugger Robot public void testListWithOneNode() 138*16467b97STreehugger Robot { 139*16467b97STreehugger Robot ITree root = new CommonTree((IToken)null); 140*16467b97STreehugger Robot 141*16467b97STreehugger Robot root.AddChild(new CommonTree(new CommonToken(101))); 142*16467b97STreehugger Robot 143*16467b97STreehugger Robot BufferedTreeNodeStream stream = new BufferedTreeNodeStream(root); 144*16467b97STreehugger Robot string expected = " 101"; 145*16467b97STreehugger Robot string actual = GetStringOfEntireStreamContentsWithNodeTypesOnly(stream); 146*16467b97STreehugger Robot Assert.AreEqual(expected, actual); 147*16467b97STreehugger Robot 148*16467b97STreehugger Robot expected = " 101"; 149*16467b97STreehugger Robot actual = stream.ToString(); 150*16467b97STreehugger Robot Assert.AreEqual(expected, actual); 151*16467b97STreehugger Robot } 152*16467b97STreehugger Robot 153*16467b97STreehugger Robot [Test] testAoverB()154*16467b97STreehugger Robot public void testAoverB() 155*16467b97STreehugger Robot { 156*16467b97STreehugger Robot ITree t = new CommonTree(new CommonToken(101)); 157*16467b97STreehugger Robot t.AddChild(new CommonTree(new CommonToken(102))); 158*16467b97STreehugger Robot 159*16467b97STreehugger Robot ITreeNodeStream stream = CreateBufferedTreeNodeStream(t); 160*16467b97STreehugger Robot string expected = " 101 102"; 161*16467b97STreehugger Robot string actual = GetStringOfEntireStreamContentsWithNodeTypesOnly(stream); 162*16467b97STreehugger Robot Assert.AreEqual(expected, actual); 163*16467b97STreehugger Robot 164*16467b97STreehugger Robot expected = " 101 2 102 3"; 165*16467b97STreehugger Robot actual = stream.ToString(); 166*16467b97STreehugger Robot Assert.AreEqual(expected, actual); 167*16467b97STreehugger Robot } 168*16467b97STreehugger Robot 169*16467b97STreehugger Robot [Test] testLT()170*16467b97STreehugger Robot public void testLT() 171*16467b97STreehugger Robot { 172*16467b97STreehugger Robot // ^(101 ^(102 103) 104) 173*16467b97STreehugger Robot ITree t = new CommonTree(new CommonToken(101)); 174*16467b97STreehugger Robot t.AddChild(new CommonTree(new CommonToken(102))); 175*16467b97STreehugger Robot t.GetChild(0).AddChild(new CommonTree(new CommonToken(103))); 176*16467b97STreehugger Robot t.AddChild(new CommonTree(new CommonToken(104))); 177*16467b97STreehugger Robot 178*16467b97STreehugger Robot ITreeNodeStream stream = CreateBufferedTreeNodeStream(t); 179*16467b97STreehugger Robot Assert.AreEqual(101, ((ITree)stream.LT(1)).Type); 180*16467b97STreehugger Robot Assert.AreEqual(Token.Down, ((ITree)stream.LT(2)).Type); 181*16467b97STreehugger Robot Assert.AreEqual(102, ((ITree)stream.LT(3)).Type); 182*16467b97STreehugger Robot Assert.AreEqual(Token.Down, ((ITree)stream.LT(4)).Type); 183*16467b97STreehugger Robot Assert.AreEqual(103, ((ITree)stream.LT(5)).Type); 184*16467b97STreehugger Robot Assert.AreEqual(Token.Up, ((ITree)stream.LT(6)).Type); 185*16467b97STreehugger Robot Assert.AreEqual(104, ((ITree)stream.LT(7)).Type); 186*16467b97STreehugger Robot Assert.AreEqual(Token.Up, ((ITree)stream.LT(8)).Type); 187*16467b97STreehugger Robot Assert.AreEqual(Token.EndOfFile, ((ITree)stream.LT(9)).Type); 188*16467b97STreehugger Robot // check way ahead 189*16467b97STreehugger Robot Assert.AreEqual(Token.EndOfFile, ((ITree)stream.LT(100)).Type); 190*16467b97STreehugger Robot } 191*16467b97STreehugger Robot 192*16467b97STreehugger Robot [Test] testMarkRewindEntire()193*16467b97STreehugger Robot public void testMarkRewindEntire() 194*16467b97STreehugger Robot { 195*16467b97STreehugger Robot // ^(101 ^(102 103 ^(106 107) ) 104 105) 196*16467b97STreehugger Robot // stream has 7 real + 6 nav nodes 197*16467b97STreehugger Robot // Sequence of types: 101 DN 102 DN 103 106 DN 107 Up Up 104 105 Up EndOfFile 198*16467b97STreehugger Robot ITree r0 = new CommonTree(new CommonToken(101)); 199*16467b97STreehugger Robot ITree r1 = new CommonTree(new CommonToken(102)); 200*16467b97STreehugger Robot r0.AddChild(r1); 201*16467b97STreehugger Robot r1.AddChild(new CommonTree(new CommonToken(103))); 202*16467b97STreehugger Robot ITree r2 = new CommonTree(new CommonToken(106)); 203*16467b97STreehugger Robot r2.AddChild(new CommonTree(new CommonToken(107))); 204*16467b97STreehugger Robot r1.AddChild(r2); 205*16467b97STreehugger Robot r0.AddChild(new CommonTree(new CommonToken(104))); 206*16467b97STreehugger Robot r0.AddChild(new CommonTree(new CommonToken(105))); 207*16467b97STreehugger Robot 208*16467b97STreehugger Robot BufferedTreeNodeStream stream = new BufferedTreeNodeStream(r0); 209*16467b97STreehugger Robot int m = stream.Mark(); // MARK 210*16467b97STreehugger Robot for (int k = 1; k <= 13; k++) 211*16467b97STreehugger Robot { // consume til end 212*16467b97STreehugger Robot stream.LT(1); 213*16467b97STreehugger Robot stream.Consume(); 214*16467b97STreehugger Robot } 215*16467b97STreehugger Robot Assert.AreEqual(Token.EndOfFile, ((ITree)stream.LT(1)).Type); 216*16467b97STreehugger Robot Assert.AreEqual(Token.Up, ((ITree)stream.LT(-1)).Type); 217*16467b97STreehugger Robot stream.Rewind(m); // REWIND 218*16467b97STreehugger Robot 219*16467b97STreehugger Robot // consume til end again :) 220*16467b97STreehugger Robot for (int k = 1; k <= 13; k++) 221*16467b97STreehugger Robot { // consume til end 222*16467b97STreehugger Robot stream.LT(1); 223*16467b97STreehugger Robot stream.Consume(); 224*16467b97STreehugger Robot } 225*16467b97STreehugger Robot Assert.AreEqual(Token.EndOfFile, ((ITree)stream.LT(1)).Type); 226*16467b97STreehugger Robot Assert.AreEqual(Token.Up, ((ITree)stream.LT(-1)).Type); 227*16467b97STreehugger Robot } 228*16467b97STreehugger Robot 229*16467b97STreehugger Robot [Test] testMarkRewindInMiddle()230*16467b97STreehugger Robot public void testMarkRewindInMiddle() 231*16467b97STreehugger Robot { 232*16467b97STreehugger Robot // ^(101 ^(102 103 ^(106 107) ) 104 105) 233*16467b97STreehugger Robot // stream has 7 real + 6 nav nodes 234*16467b97STreehugger Robot // Sequence of types: 101 DN 102 DN 103 106 DN 107 Up Up 104 105 Up EndOfFile 235*16467b97STreehugger Robot ITree r0 = new CommonTree(new CommonToken(101)); 236*16467b97STreehugger Robot ITree r1 = new CommonTree(new CommonToken(102)); 237*16467b97STreehugger Robot r0.AddChild(r1); 238*16467b97STreehugger Robot r1.AddChild(new CommonTree(new CommonToken(103))); 239*16467b97STreehugger Robot ITree r2 = new CommonTree(new CommonToken(106)); 240*16467b97STreehugger Robot r2.AddChild(new CommonTree(new CommonToken(107))); 241*16467b97STreehugger Robot r1.AddChild(r2); 242*16467b97STreehugger Robot r0.AddChild(new CommonTree(new CommonToken(104))); 243*16467b97STreehugger Robot r0.AddChild(new CommonTree(new CommonToken(105))); 244*16467b97STreehugger Robot 245*16467b97STreehugger Robot BufferedTreeNodeStream stream = new BufferedTreeNodeStream(r0); 246*16467b97STreehugger Robot for (int k = 1; k <= 7; k++) 247*16467b97STreehugger Robot { // consume til middle 248*16467b97STreehugger Robot //System.out.println(((ITree)stream.LT(1)).Type); 249*16467b97STreehugger Robot stream.Consume(); 250*16467b97STreehugger Robot } 251*16467b97STreehugger Robot Assert.AreEqual(107, ((ITree)stream.LT(1)).Type); 252*16467b97STreehugger Robot int m = stream.Mark(); // MARK 253*16467b97STreehugger Robot stream.Consume(); // consume 107 254*16467b97STreehugger Robot stream.Consume(); // consume Up 255*16467b97STreehugger Robot stream.Consume(); // consume Up 256*16467b97STreehugger Robot stream.Consume(); // consume 104 257*16467b97STreehugger Robot stream.Rewind(m); // REWIND 258*16467b97STreehugger Robot 259*16467b97STreehugger Robot Assert.AreEqual(107, ((ITree)stream.LT(1)).Type); 260*16467b97STreehugger Robot stream.Consume(); 261*16467b97STreehugger Robot Assert.AreEqual(Token.Up, ((ITree)stream.LT(1)).Type); 262*16467b97STreehugger Robot stream.Consume(); 263*16467b97STreehugger Robot Assert.AreEqual(Token.Up, ((ITree)stream.LT(1)).Type); 264*16467b97STreehugger Robot stream.Consume(); 265*16467b97STreehugger Robot Assert.AreEqual(104, ((ITree)stream.LT(1)).Type); 266*16467b97STreehugger Robot stream.Consume(); 267*16467b97STreehugger Robot // now we're past rewind position 268*16467b97STreehugger Robot Assert.AreEqual(105, ((ITree)stream.LT(1)).Type); 269*16467b97STreehugger Robot stream.Consume(); 270*16467b97STreehugger Robot Assert.AreEqual(Token.Up, ((ITree)stream.LT(1)).Type); 271*16467b97STreehugger Robot stream.Consume(); 272*16467b97STreehugger Robot Assert.AreEqual(Token.EndOfFile, ((ITree)stream.LT(1)).Type); 273*16467b97STreehugger Robot Assert.AreEqual(Token.Up, ((ITree)stream.LT(-1)).Type); 274*16467b97STreehugger Robot } 275*16467b97STreehugger Robot 276*16467b97STreehugger Robot [Test] testMarkRewindNested()277*16467b97STreehugger Robot public void testMarkRewindNested() 278*16467b97STreehugger Robot { 279*16467b97STreehugger Robot // ^(101 ^(102 103 ^(106 107) ) 104 105) 280*16467b97STreehugger Robot // stream has 7 real + 6 nav nodes 281*16467b97STreehugger Robot // Sequence of types: 101 DN 102 DN 103 106 DN 107 Up Up 104 105 Up EndOfFile 282*16467b97STreehugger Robot ITree r0 = new CommonTree(new CommonToken(101)); 283*16467b97STreehugger Robot ITree r1 = new CommonTree(new CommonToken(102)); 284*16467b97STreehugger Robot r0.AddChild(r1); 285*16467b97STreehugger Robot r1.AddChild(new CommonTree(new CommonToken(103))); 286*16467b97STreehugger Robot ITree r2 = new CommonTree(new CommonToken(106)); 287*16467b97STreehugger Robot r2.AddChild(new CommonTree(new CommonToken(107))); 288*16467b97STreehugger Robot r1.AddChild(r2); 289*16467b97STreehugger Robot r0.AddChild(new CommonTree(new CommonToken(104))); 290*16467b97STreehugger Robot r0.AddChild(new CommonTree(new CommonToken(105))); 291*16467b97STreehugger Robot 292*16467b97STreehugger Robot BufferedTreeNodeStream stream = new BufferedTreeNodeStream(r0); 293*16467b97STreehugger Robot int m = stream.Mark(); // MARK at start 294*16467b97STreehugger Robot stream.Consume(); // consume 101 295*16467b97STreehugger Robot stream.Consume(); // consume DN 296*16467b97STreehugger Robot int m2 = stream.Mark(); // MARK on 102 297*16467b97STreehugger Robot stream.Consume(); // consume 102 298*16467b97STreehugger Robot stream.Consume(); // consume DN 299*16467b97STreehugger Robot stream.Consume(); // consume 103 300*16467b97STreehugger Robot stream.Consume(); // consume 106 301*16467b97STreehugger Robot stream.Rewind(m2); // REWIND to 102 302*16467b97STreehugger Robot Assert.AreEqual(102, ((ITree)stream.LT(1)).Type); 303*16467b97STreehugger Robot stream.Consume(); 304*16467b97STreehugger Robot Assert.AreEqual(Token.Down, ((ITree)stream.LT(1)).Type); 305*16467b97STreehugger Robot stream.Consume(); 306*16467b97STreehugger Robot // stop at 103 and rewind to start 307*16467b97STreehugger Robot stream.Rewind(m); // REWIND to 101 308*16467b97STreehugger Robot Assert.AreEqual(101, ((ITree)stream.LT(1)).Type); 309*16467b97STreehugger Robot stream.Consume(); 310*16467b97STreehugger Robot Assert.AreEqual(Token.Down, ((ITree)stream.LT(1)).Type); 311*16467b97STreehugger Robot stream.Consume(); 312*16467b97STreehugger Robot Assert.AreEqual(102, ((ITree)stream.LT(1)).Type); 313*16467b97STreehugger Robot stream.Consume(); 314*16467b97STreehugger Robot Assert.AreEqual(Token.Down, ((ITree)stream.LT(1)).Type); 315*16467b97STreehugger Robot } 316*16467b97STreehugger Robot 317*16467b97STreehugger Robot [Test] testSeek()318*16467b97STreehugger Robot public void testSeek() 319*16467b97STreehugger Robot { 320*16467b97STreehugger Robot // ^(101 ^(102 103 ^(106 107) ) 104 105) 321*16467b97STreehugger Robot // stream has 7 real + 6 nav nodes 322*16467b97STreehugger Robot // Sequence of types: 101 DN 102 DN 103 106 DN 107 Up Up 104 105 Up EndOfFile 323*16467b97STreehugger Robot ITree r0 = new CommonTree(new CommonToken(101)); 324*16467b97STreehugger Robot ITree r1 = new CommonTree(new CommonToken(102)); 325*16467b97STreehugger Robot r0.AddChild(r1); 326*16467b97STreehugger Robot r1.AddChild(new CommonTree(new CommonToken(103))); 327*16467b97STreehugger Robot ITree r2 = new CommonTree(new CommonToken(106)); 328*16467b97STreehugger Robot r2.AddChild(new CommonTree(new CommonToken(107))); 329*16467b97STreehugger Robot r1.AddChild(r2); 330*16467b97STreehugger Robot r0.AddChild(new CommonTree(new CommonToken(104))); 331*16467b97STreehugger Robot r0.AddChild(new CommonTree(new CommonToken(105))); 332*16467b97STreehugger Robot 333*16467b97STreehugger Robot BufferedTreeNodeStream stream = new BufferedTreeNodeStream(r0); 334*16467b97STreehugger Robot stream.Consume(); // consume 101 335*16467b97STreehugger Robot stream.Consume(); // consume DN 336*16467b97STreehugger Robot stream.Consume(); // consume 102 337*16467b97STreehugger Robot stream.Seek(7); // seek to 107 338*16467b97STreehugger Robot Assert.AreEqual(107, ((ITree)stream.LT(1)).Type); 339*16467b97STreehugger Robot stream.Consume(); // consume 107 340*16467b97STreehugger Robot stream.Consume(); // consume Up 341*16467b97STreehugger Robot stream.Consume(); // consume Up 342*16467b97STreehugger Robot Assert.AreEqual(104, ((ITree)stream.LT(1)).Type); 343*16467b97STreehugger Robot } 344*16467b97STreehugger Robot 345*16467b97STreehugger Robot [Test] testSeekFromStart()346*16467b97STreehugger Robot public void testSeekFromStart() 347*16467b97STreehugger Robot { 348*16467b97STreehugger Robot // ^(101 ^(102 103 ^(106 107) ) 104 105) 349*16467b97STreehugger Robot // stream has 7 real + 6 nav nodes 350*16467b97STreehugger Robot // Sequence of types: 101 DN 102 DN 103 106 DN 107 Up Up 104 105 Up EndOfFile 351*16467b97STreehugger Robot ITree r0 = new CommonTree(new CommonToken(101)); 352*16467b97STreehugger Robot ITree r1 = new CommonTree(new CommonToken(102)); 353*16467b97STreehugger Robot r0.AddChild(r1); 354*16467b97STreehugger Robot r1.AddChild(new CommonTree(new CommonToken(103))); 355*16467b97STreehugger Robot ITree r2 = new CommonTree(new CommonToken(106)); 356*16467b97STreehugger Robot r2.AddChild(new CommonTree(new CommonToken(107))); 357*16467b97STreehugger Robot r1.AddChild(r2); 358*16467b97STreehugger Robot r0.AddChild(new CommonTree(new CommonToken(104))); 359*16467b97STreehugger Robot r0.AddChild(new CommonTree(new CommonToken(105))); 360*16467b97STreehugger Robot 361*16467b97STreehugger Robot BufferedTreeNodeStream stream = new BufferedTreeNodeStream(r0); 362*16467b97STreehugger Robot stream.Seek(7); // seek to 107 363*16467b97STreehugger Robot Assert.AreEqual(107, ((ITree)stream.LT(1)).Type); 364*16467b97STreehugger Robot stream.Consume(); // consume 107 365*16467b97STreehugger Robot stream.Consume(); // consume Up 366*16467b97STreehugger Robot stream.Consume(); // consume Up 367*16467b97STreehugger Robot Assert.AreEqual(104, ((ITree)stream.LT(1)).Type); 368*16467b97STreehugger Robot } 369*16467b97STreehugger Robot 370*16467b97STreehugger Robot [Test] testPushPop()371*16467b97STreehugger Robot public void testPushPop() 372*16467b97STreehugger Robot { 373*16467b97STreehugger Robot // ^(101 ^(102 103) ^(104 105) ^(106 107) 108 109) 374*16467b97STreehugger Robot // stream has 9 real + 8 nav nodes 375*16467b97STreehugger Robot // Sequence of types: 101 DN 102 DN 103 Up 104 DN 105 Up 106 DN 107 Up 108 109 Up 376*16467b97STreehugger Robot ITree r0 = new CommonTree(new CommonToken(101)); 377*16467b97STreehugger Robot ITree r1 = new CommonTree(new CommonToken(102)); 378*16467b97STreehugger Robot r1.AddChild(new CommonTree(new CommonToken(103))); 379*16467b97STreehugger Robot r0.AddChild(r1); 380*16467b97STreehugger Robot ITree r2 = new CommonTree(new CommonToken(104)); 381*16467b97STreehugger Robot r2.AddChild(new CommonTree(new CommonToken(105))); 382*16467b97STreehugger Robot r0.AddChild(r2); 383*16467b97STreehugger Robot ITree r3 = new CommonTree(new CommonToken(106)); 384*16467b97STreehugger Robot r3.AddChild(new CommonTree(new CommonToken(107))); 385*16467b97STreehugger Robot r0.AddChild(r3); 386*16467b97STreehugger Robot r0.AddChild(new CommonTree(new CommonToken(108))); 387*16467b97STreehugger Robot r0.AddChild(new CommonTree(new CommonToken(109))); 388*16467b97STreehugger Robot 389*16467b97STreehugger Robot BufferedTreeNodeStream stream = new BufferedTreeNodeStream(r0); 390*16467b97STreehugger Robot String expecting = " 101 2 102 2 103 3 104 2 105 3 106 2 107 3 108 109 3"; 391*16467b97STreehugger Robot String found = stream.ToString(); 392*16467b97STreehugger Robot Assert.AreEqual(expecting, found); 393*16467b97STreehugger Robot 394*16467b97STreehugger Robot // Assume we want to hit node 107 and then "call 102" then return 395*16467b97STreehugger Robot 396*16467b97STreehugger Robot int indexOf102 = 2; 397*16467b97STreehugger Robot int indexOf107 = 12; 398*16467b97STreehugger Robot for (int k = 1; k <= indexOf107; k++) 399*16467b97STreehugger Robot { // consume til 107 node 400*16467b97STreehugger Robot stream.Consume(); 401*16467b97STreehugger Robot } 402*16467b97STreehugger Robot // CALL 102 403*16467b97STreehugger Robot Assert.AreEqual(107, ((ITree)stream.LT(1)).Type); 404*16467b97STreehugger Robot stream.Push(indexOf102); 405*16467b97STreehugger Robot Assert.AreEqual(102, ((ITree)stream.LT(1)).Type); 406*16467b97STreehugger Robot stream.Consume(); // consume 102 407*16467b97STreehugger Robot Assert.AreEqual(Token.Down, ((ITree)stream.LT(1)).Type); 408*16467b97STreehugger Robot stream.Consume(); // consume DN 409*16467b97STreehugger Robot Assert.AreEqual(103, ((ITree)stream.LT(1)).Type); 410*16467b97STreehugger Robot stream.Consume(); // consume 103 411*16467b97STreehugger Robot Assert.AreEqual(Token.Up, ((ITree)stream.LT(1)).Type); 412*16467b97STreehugger Robot // RETURN 413*16467b97STreehugger Robot stream.Pop(); 414*16467b97STreehugger Robot Assert.AreEqual(107, ((ITree)stream.LT(1)).Type); 415*16467b97STreehugger Robot } 416*16467b97STreehugger Robot 417*16467b97STreehugger Robot [Test] testNestedPushPop()418*16467b97STreehugger Robot public void testNestedPushPop() 419*16467b97STreehugger Robot { 420*16467b97STreehugger Robot // ^(101 ^(102 103) ^(104 105) ^(106 107) 108 109) 421*16467b97STreehugger Robot // stream has 9 real + 8 nav nodes 422*16467b97STreehugger Robot // Sequence of types: 101 DN 102 DN 103 Up 104 DN 105 Up 106 DN 107 Up 108 109 Up 423*16467b97STreehugger Robot ITree r0 = new CommonTree(new CommonToken(101)); 424*16467b97STreehugger Robot ITree r1 = new CommonTree(new CommonToken(102)); 425*16467b97STreehugger Robot r1.AddChild(new CommonTree(new CommonToken(103))); 426*16467b97STreehugger Robot r0.AddChild(r1); 427*16467b97STreehugger Robot ITree r2 = new CommonTree(new CommonToken(104)); 428*16467b97STreehugger Robot r2.AddChild(new CommonTree(new CommonToken(105))); 429*16467b97STreehugger Robot r0.AddChild(r2); 430*16467b97STreehugger Robot ITree r3 = new CommonTree(new CommonToken(106)); 431*16467b97STreehugger Robot r3.AddChild(new CommonTree(new CommonToken(107))); 432*16467b97STreehugger Robot r0.AddChild(r3); 433*16467b97STreehugger Robot r0.AddChild(new CommonTree(new CommonToken(108))); 434*16467b97STreehugger Robot r0.AddChild(new CommonTree(new CommonToken(109))); 435*16467b97STreehugger Robot 436*16467b97STreehugger Robot BufferedTreeNodeStream stream = new BufferedTreeNodeStream(r0); 437*16467b97STreehugger Robot 438*16467b97STreehugger Robot // Assume we want to hit node 107 and then "call 102", which 439*16467b97STreehugger Robot // calls 104, then return 440*16467b97STreehugger Robot 441*16467b97STreehugger Robot int indexOf102 = 2; 442*16467b97STreehugger Robot int indexOf107 = 12; 443*16467b97STreehugger Robot for (int k = 1; k <= indexOf107; k++) 444*16467b97STreehugger Robot { // consume til 107 node 445*16467b97STreehugger Robot stream.Consume(); 446*16467b97STreehugger Robot } 447*16467b97STreehugger Robot Assert.AreEqual(107, ((ITree)stream.LT(1)).Type); 448*16467b97STreehugger Robot // CALL 102 449*16467b97STreehugger Robot stream.Push(indexOf102); 450*16467b97STreehugger Robot Assert.AreEqual(102, ((ITree)stream.LT(1)).Type); 451*16467b97STreehugger Robot stream.Consume(); // consume 102 452*16467b97STreehugger Robot Assert.AreEqual(Token.Down, ((ITree)stream.LT(1)).Type); 453*16467b97STreehugger Robot stream.Consume(); // consume DN 454*16467b97STreehugger Robot Assert.AreEqual(103, ((ITree)stream.LT(1)).Type); 455*16467b97STreehugger Robot stream.Consume(); // consume 103 456*16467b97STreehugger Robot 457*16467b97STreehugger Robot // CALL 104 458*16467b97STreehugger Robot int indexOf104 = 6; 459*16467b97STreehugger Robot stream.Push(indexOf104); 460*16467b97STreehugger Robot Assert.AreEqual(104, ((ITree)stream.LT(1)).Type); 461*16467b97STreehugger Robot stream.Consume(); // consume 102 462*16467b97STreehugger Robot Assert.AreEqual(Token.Down, ((ITree)stream.LT(1)).Type); 463*16467b97STreehugger Robot stream.Consume(); // consume DN 464*16467b97STreehugger Robot Assert.AreEqual(105, ((ITree)stream.LT(1)).Type); 465*16467b97STreehugger Robot stream.Consume(); // consume 103 466*16467b97STreehugger Robot Assert.AreEqual(Token.Up, ((ITree)stream.LT(1)).Type); 467*16467b97STreehugger Robot // RETURN (to Up node in 102 subtree) 468*16467b97STreehugger Robot stream.Pop(); 469*16467b97STreehugger Robot 470*16467b97STreehugger Robot Assert.AreEqual(Token.Up, ((ITree)stream.LT(1)).Type); 471*16467b97STreehugger Robot // RETURN (to empty stack) 472*16467b97STreehugger Robot stream.Pop(); 473*16467b97STreehugger Robot Assert.AreEqual(107, ((ITree)stream.LT(1)).Type); 474*16467b97STreehugger Robot } 475*16467b97STreehugger Robot 476*16467b97STreehugger Robot [Test] testPushPopFromEOF()477*16467b97STreehugger Robot public void testPushPopFromEOF() 478*16467b97STreehugger Robot { 479*16467b97STreehugger Robot // ^(101 ^(102 103) ^(104 105) ^(106 107) 108 109) 480*16467b97STreehugger Robot // stream has 9 real + 8 nav nodes 481*16467b97STreehugger Robot // Sequence of types: 101 DN 102 DN 103 Up 104 DN 105 Up 106 DN 107 Up 108 109 Up 482*16467b97STreehugger Robot ITree r0 = new CommonTree(new CommonToken(101)); 483*16467b97STreehugger Robot ITree r1 = new CommonTree(new CommonToken(102)); 484*16467b97STreehugger Robot r1.AddChild(new CommonTree(new CommonToken(103))); 485*16467b97STreehugger Robot r0.AddChild(r1); 486*16467b97STreehugger Robot ITree r2 = new CommonTree(new CommonToken(104)); 487*16467b97STreehugger Robot r2.AddChild(new CommonTree(new CommonToken(105))); 488*16467b97STreehugger Robot r0.AddChild(r2); 489*16467b97STreehugger Robot ITree r3 = new CommonTree(new CommonToken(106)); 490*16467b97STreehugger Robot r3.AddChild(new CommonTree(new CommonToken(107))); 491*16467b97STreehugger Robot r0.AddChild(r3); 492*16467b97STreehugger Robot r0.AddChild(new CommonTree(new CommonToken(108))); 493*16467b97STreehugger Robot r0.AddChild(new CommonTree(new CommonToken(109))); 494*16467b97STreehugger Robot 495*16467b97STreehugger Robot BufferedTreeNodeStream stream = new BufferedTreeNodeStream(r0); 496*16467b97STreehugger Robot 497*16467b97STreehugger Robot while (stream.LA(1) != Token.EndOfFile) 498*16467b97STreehugger Robot { 499*16467b97STreehugger Robot stream.Consume(); 500*16467b97STreehugger Robot } 501*16467b97STreehugger Robot int indexOf102 = 2; 502*16467b97STreehugger Robot int indexOf104 = 6; 503*16467b97STreehugger Robot Assert.AreEqual(Token.EndOfFile, ((ITree)stream.LT(1)).Type); 504*16467b97STreehugger Robot 505*16467b97STreehugger Robot // CALL 102 506*16467b97STreehugger Robot stream.Push(indexOf102); 507*16467b97STreehugger Robot Assert.AreEqual(102, ((ITree)stream.LT(1)).Type); 508*16467b97STreehugger Robot stream.Consume(); // consume 102 509*16467b97STreehugger Robot Assert.AreEqual(Token.Down, ((ITree)stream.LT(1)).Type); 510*16467b97STreehugger Robot stream.Consume(); // consume DN 511*16467b97STreehugger Robot Assert.AreEqual(103, ((ITree)stream.LT(1)).Type); 512*16467b97STreehugger Robot stream.Consume(); // consume 103 513*16467b97STreehugger Robot Assert.AreEqual(Token.Up, ((ITree)stream.LT(1)).Type); 514*16467b97STreehugger Robot // RETURN (to empty stack) 515*16467b97STreehugger Robot stream.Pop(); 516*16467b97STreehugger Robot Assert.AreEqual(Token.EndOfFile, ((ITree)stream.LT(1)).Type); 517*16467b97STreehugger Robot 518*16467b97STreehugger Robot // CALL 104 519*16467b97STreehugger Robot stream.Push(indexOf104); 520*16467b97STreehugger Robot Assert.AreEqual(104, ((ITree)stream.LT(1)).Type); 521*16467b97STreehugger Robot stream.Consume(); // consume 102 522*16467b97STreehugger Robot Assert.AreEqual(Token.Down, ((ITree)stream.LT(1)).Type); 523*16467b97STreehugger Robot stream.Consume(); // consume DN 524*16467b97STreehugger Robot Assert.AreEqual(105, ((ITree)stream.LT(1)).Type); 525*16467b97STreehugger Robot stream.Consume(); // consume 103 526*16467b97STreehugger Robot Assert.AreEqual(Token.Up, ((ITree)stream.LT(1)).Type); 527*16467b97STreehugger Robot // RETURN (to empty stack) 528*16467b97STreehugger Robot stream.Pop(); 529*16467b97STreehugger Robot Assert.AreEqual(Token.EndOfFile, ((ITree)stream.LT(1)).Type); 530*16467b97STreehugger Robot } 531*16467b97STreehugger Robot 532*16467b97STreehugger Robot [Test] testStackStretch()533*16467b97STreehugger Robot public void testStackStretch() 534*16467b97STreehugger Robot { 535*16467b97STreehugger Robot // make more than INITIAL_CALL_STACK_SIZE pushes 536*16467b97STreehugger Robot ITree r0 = new CommonTree(new CommonToken(101)); 537*16467b97STreehugger Robot BufferedTreeNodeStream stream = new BufferedTreeNodeStream(r0); 538*16467b97STreehugger Robot // go 1 over initial size 539*16467b97STreehugger Robot for (int i = 1; i <= BufferedTreeNodeStream.INITIAL_CALL_STACK_SIZE + 1; i++) 540*16467b97STreehugger Robot { 541*16467b97STreehugger Robot stream.Push(i); 542*16467b97STreehugger Robot } 543*16467b97STreehugger Robot Assert.AreEqual(10, stream.Pop()); 544*16467b97STreehugger Robot Assert.AreEqual(9, stream.Pop()); 545*16467b97STreehugger Robot } 546*16467b97STreehugger Robot 547*16467b97STreehugger Robot #endregion 548*16467b97STreehugger Robot 549*16467b97STreehugger Robot 550*16467b97STreehugger Robot #region CommonTreeNodeStream Tests 551*16467b97STreehugger Robot 552*16467b97STreehugger Robot [Test] testBufferOverflow()553*16467b97STreehugger Robot public void testBufferOverflow() 554*16467b97STreehugger Robot { 555*16467b97STreehugger Robot StringBuilder buf = new StringBuilder(); 556*16467b97STreehugger Robot StringBuilder buf2 = new StringBuilder(); 557*16467b97STreehugger Robot // make ^(101 102 ... n) 558*16467b97STreehugger Robot ITree t = new CommonTree(new CommonToken(101)); 559*16467b97STreehugger Robot buf.Append(" 101"); 560*16467b97STreehugger Robot buf2.Append(" 101"); 561*16467b97STreehugger Robot buf2.Append(" "); 562*16467b97STreehugger Robot buf2.Append(Token.Down); 563*16467b97STreehugger Robot for (int i = 0; i <= CommonTreeNodeStream.DEFAULT_INITIAL_BUFFER_SIZE + 10; i++) 564*16467b97STreehugger Robot { 565*16467b97STreehugger Robot t.AddChild(new CommonTree(new CommonToken(102 + i))); 566*16467b97STreehugger Robot buf.Append(" "); 567*16467b97STreehugger Robot buf.Append(102 + i); 568*16467b97STreehugger Robot buf2.Append(" "); 569*16467b97STreehugger Robot buf2.Append(102 + i); 570*16467b97STreehugger Robot } 571*16467b97STreehugger Robot buf2.Append(" "); 572*16467b97STreehugger Robot buf2.Append(Token.Up); 573*16467b97STreehugger Robot 574*16467b97STreehugger Robot ITreeNodeStream stream = CreateCommonTreeNodeStream(t); 575*16467b97STreehugger Robot String expecting = buf.ToString(); 576*16467b97STreehugger Robot String found = GetStringOfEntireStreamContentsWithNodeTypesOnly(stream); 577*16467b97STreehugger Robot Assert.AreEqual(expecting, found); 578*16467b97STreehugger Robot 579*16467b97STreehugger Robot expecting = buf2.ToString(); 580*16467b97STreehugger Robot found = stream.ToString(); 581*16467b97STreehugger Robot Assert.AreEqual(expecting, found); 582*16467b97STreehugger Robot } 583*16467b97STreehugger Robot 584*16467b97STreehugger Robot /// <summary> 585*16467b97STreehugger Robot /// Test what happens when tail hits the end of the buffer, but there 586*16467b97STreehugger Robot /// is more room left. 587*16467b97STreehugger Robot /// </summary> 588*16467b97STreehugger Robot /// <remarks> 589*16467b97STreehugger Robot /// Specifically that would mean that head is not at 0 but has 590*16467b97STreehugger Robot /// advanced somewhere to the middle of the lookahead buffer. 591*16467b97STreehugger Robot /// 592*16467b97STreehugger Robot /// Use Consume() to advance N nodes into lookahead. Then use LT() 593*16467b97STreehugger Robot /// to load at least INITIAL_LOOKAHEAD_BUFFER_SIZE-N nodes so the 594*16467b97STreehugger Robot /// buffer has to wrap. 595*16467b97STreehugger Robot /// </remarks> 596*16467b97STreehugger Robot [Test] testBufferWrap()597*16467b97STreehugger Robot public void testBufferWrap() 598*16467b97STreehugger Robot { 599*16467b97STreehugger Robot int N = 10; 600*16467b97STreehugger Robot // make tree with types: 1 2 ... INITIAL_LOOKAHEAD_BUFFER_SIZE+N 601*16467b97STreehugger Robot ITree t = new CommonTree((IToken)null); 602*16467b97STreehugger Robot for (int i = 0; i < CommonTreeNodeStream.DEFAULT_INITIAL_BUFFER_SIZE + N; i++) 603*16467b97STreehugger Robot { 604*16467b97STreehugger Robot t.AddChild(new CommonTree(new CommonToken(i + 1))); 605*16467b97STreehugger Robot } 606*16467b97STreehugger Robot 607*16467b97STreehugger Robot // move head to index N 608*16467b97STreehugger Robot ITreeNodeStream stream = CreateCommonTreeNodeStream(t); 609*16467b97STreehugger Robot for (int i = 1; i <= N; i++) 610*16467b97STreehugger Robot { // consume N 611*16467b97STreehugger Robot ITree node = (ITree)stream.LT(1); 612*16467b97STreehugger Robot Assert.AreEqual(i, node.Type); 613*16467b97STreehugger Robot stream.Consume(); 614*16467b97STreehugger Robot } 615*16467b97STreehugger Robot 616*16467b97STreehugger Robot // now use LT to lookahead past end of buffer 617*16467b97STreehugger Robot int remaining = CommonTreeNodeStream.DEFAULT_INITIAL_BUFFER_SIZE - N; 618*16467b97STreehugger Robot int wrapBy = 4; // wrap around by 4 nodes 619*16467b97STreehugger Robot Assert.IsTrue(wrapBy < N, "bad test code; wrapBy must be less than N"); 620*16467b97STreehugger Robot for (int i = 1; i <= remaining + wrapBy; i++) 621*16467b97STreehugger Robot { // wrap past end of buffer 622*16467b97STreehugger Robot ITree node = (ITree)stream.LT(i); // look ahead to ith token 623*16467b97STreehugger Robot Assert.AreEqual(N + i, node.Type); 624*16467b97STreehugger Robot } 625*16467b97STreehugger Robot } 626*16467b97STreehugger Robot 627*16467b97STreehugger Robot #endregion 628*16467b97STreehugger Robot 629*16467b97STreehugger Robot 630*16467b97STreehugger Robot #region Helper Methods 631*16467b97STreehugger Robot CreateBufferedTreeNodeStream(object t)632*16467b97STreehugger Robot protected ITreeNodeStream CreateBufferedTreeNodeStream(object t) 633*16467b97STreehugger Robot { 634*16467b97STreehugger Robot return new BufferedTreeNodeStream(t); 635*16467b97STreehugger Robot } 636*16467b97STreehugger Robot CreateCommonTreeNodeStream(object t)637*16467b97STreehugger Robot protected ITreeNodeStream CreateCommonTreeNodeStream(object t) 638*16467b97STreehugger Robot { 639*16467b97STreehugger Robot return new CommonTreeNodeStream(t); 640*16467b97STreehugger Robot } 641*16467b97STreehugger Robot GetStringOfEntireStreamContentsWithNodeTypesOnly(ITreeNodeStream nodes)642*16467b97STreehugger Robot public string GetStringOfEntireStreamContentsWithNodeTypesOnly(ITreeNodeStream nodes) 643*16467b97STreehugger Robot { 644*16467b97STreehugger Robot StringBuilder buf = new StringBuilder(); 645*16467b97STreehugger Robot for (int i = 0; i < nodes.Count; i++) 646*16467b97STreehugger Robot { 647*16467b97STreehugger Robot object t = nodes.LT(i + 1); 648*16467b97STreehugger Robot int type = nodes.TreeAdaptor.GetType(t); 649*16467b97STreehugger Robot if (!((type == Token.Down) || (type == Token.Up))) 650*16467b97STreehugger Robot { 651*16467b97STreehugger Robot buf.Append(" "); 652*16467b97STreehugger Robot buf.Append(type); 653*16467b97STreehugger Robot } 654*16467b97STreehugger Robot } 655*16467b97STreehugger Robot return buf.ToString(); 656*16467b97STreehugger Robot } 657*16467b97STreehugger Robot 658*16467b97STreehugger Robot #endregion 659*16467b97STreehugger Robot } 660*16467b97STreehugger Robot }