001 // Copyright 2005 The Apache Software Foundation 002 // 003 // Licensed under the Apache License, Version 2.0 (the "License"); 004 // you may not use this file except in compliance with the License. 005 // You may obtain a copy of the License at 006 // 007 // http://www.apache.org/licenses/LICENSE-2.0 008 // 009 // Unless required by applicable law or agreed to in writing, software 010 // distributed under the License is distributed on an "AS IS" BASIS, 011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012 // See the License for the specific language governing permissions and 013 // limitations under the License. 014 015 package org.apache.tapestry.link; 016 017 import static org.easymock.EasyMock.expect; 018 019 import org.apache.hivemind.ApplicationRuntimeException; 020 import org.apache.hivemind.Location; 021 import org.apache.tapestry.BaseComponentTestCase; 022 import org.apache.tapestry.IMarkupWriter; 023 import org.apache.tapestry.IRequestCycle; 024 import org.apache.tapestry.NestedMarkupWriter; 025 import org.apache.tapestry.Tapestry; 026 import org.apache.tapestry.components.ILinkComponent; 027 import org.apache.tapestry.engine.ILink; 028 import org.testng.annotations.Test; 029 030 /** 031 * Tests for {@link org.apache.tapestry.link.DefaultLinkRenderer}. 032 * 033 * @author Howard M. Lewis Ship 034 * @since 4.0 035 */ 036 @Test 037 public class DefaultLinkRendererTest extends BaseComponentTestCase 038 { 039 class RendererFixture extends DefaultLinkRenderer 040 { 041 private IMarkupWriter _writer; 042 043 private IRequestCycle _cycle; 044 045 private ILinkComponent _component; 046 047 private String _element; 048 049 private boolean _hasBody; 050 051 private String _targetAttribute; 052 053 private String _urlAttribute; 054 055 public RendererFixture(IMarkupWriter writer, IRequestCycle cycle, ILinkComponent component, 056 String element, boolean body, String targetAttribute, String urlAttribute) 057 { 058 _writer = writer; 059 _cycle = cycle; 060 _component = component; 061 _element = element; 062 _hasBody = body; 063 _targetAttribute = targetAttribute; 064 _urlAttribute = urlAttribute; 065 } 066 067 @Override 068 protected void afterBodyRender(IMarkupWriter writer, IRequestCycle cycle, 069 ILinkComponent link) 070 { 071 assertSame(_writer, writer); 072 assertSame(_cycle, cycle); 073 assertSame(_component, link); 074 075 writer.print("AFTER-BODY-RENDER"); 076 } 077 078 @Override 079 protected void beforeBodyRender(IMarkupWriter writer, IRequestCycle cycle, 080 ILinkComponent link) 081 { 082 assertSame(_writer, writer); 083 assertSame(_cycle, cycle); 084 assertSame(_component, link); 085 086 writer.print("BEFORE-BODY-RENDER"); 087 } 088 089 @Override 090 protected String getElement() 091 { 092 return _element; 093 } 094 095 @Override 096 protected boolean getHasBody() 097 { 098 return _hasBody; 099 } 100 101 @Override 102 protected String getTargetAttribute() 103 { 104 105 return _targetAttribute; 106 } 107 108 @Override 109 protected String getUrlAttribute() 110 { 111 return _urlAttribute; 112 } 113 114 } 115 116 protected ILinkComponent newComponent() 117 { 118 return newMock(ILinkComponent.class); 119 } 120 121 public void testNoNesting() 122 { 123 IMarkupWriter writer = newWriter(); 124 IRequestCycle cycle = newCycle(); 125 ILinkComponent existing = newComponent(); 126 ILinkComponent active = newComponent(); 127 Location l = newLocation(); 128 129 trainGetAttribute(cycle, Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME, existing); 130 131 trainGetLocation(active, l); 132 133 replay(); 134 135 try 136 { 137 new DefaultLinkRenderer().renderLink(writer, cycle, active); 138 unreachable(); 139 } 140 catch (ApplicationRuntimeException ex) 141 { 142 assertEquals(LinkMessages.noNesting(), ex.getMessage()); 143 assertSame(active, ex.getComponent()); 144 assertSame(l, ex.getLocation()); 145 } 146 147 verify(); 148 } 149 150 public void testStandardNotDisabled() 151 { 152 IMarkupWriter writer = newWriter(); 153 NestedMarkupWriter nested = newNestedWriter(); 154 IRequestCycle cycle = newCycle(); 155 ILinkComponent component = newComponent(); 156 ILink link = newLink(); 157 158 trainGetAttribute(cycle, Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME, null); 159 cycle.setAttribute(Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME, component); 160 161 trainIsDisabled(component, false); 162 trainIsRewinding(cycle, false); 163 164 writer.begin("a"); 165 166 component.renderAdditionalAttributes(writer, cycle); 167 168 trainGetLink(component, cycle, link); 169 170 trainGetScheme(component, null); 171 trainGetPort(component, null); 172 trainGetAnchor(component, null); 173 174 trainGetURL(link, null, null, "/foo/bar.baz"); 175 176 writer.attribute("href", "/foo/bar.baz"); 177 178 trainGetTarget(component, null); 179 180 trainGetNestedWriter(writer, nested); 181 182 component.renderBody(nested, cycle); 183 184 nested.close(); 185 186 writer.end(); 187 188 cycle.removeAttribute(Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME); 189 190 replay(); 191 192 new DefaultLinkRenderer().renderLink(writer, cycle, component); 193 194 verify(); 195 } 196 197 protected void trainGetScheme(ILinkComponent component, String scheme) 198 { 199 expect(component.getScheme()).andReturn(scheme); 200 } 201 202 protected void trainGetPort(ILinkComponent component, Integer port) 203 { 204 expect(component.getPort()).andReturn(port); 205 } 206 207 public void testStandardWithSchemaAnchorAndTarget() 208 { 209 IMarkupWriter writer = newWriter(); 210 NestedMarkupWriter nested = newNestedWriter(); 211 IRequestCycle cycle = newCycle(); 212 ILinkComponent component = newComponent(); 213 ILink link = newLink(); 214 215 trainGetAttribute(cycle, Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME, null); 216 cycle.setAttribute(Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME, component); 217 218 trainIsDisabled(component, false); 219 trainIsRewinding(cycle, false); 220 221 writer.begin("a"); 222 223 component.renderAdditionalAttributes(writer, cycle); 224 225 trainGetLink(component, cycle, link); 226 227 trainGetScheme(component, "https"); 228 229 trainGetPort(component, null); 230 231 trainGetAnchor(component, "my-anchor"); 232 233 trainGetURL(link, "https", "my-anchor", "http://zap.com/foo/bar.baz#my-anchor"); 234 235 writer.attribute("href", "http://zap.com/foo/bar.baz#my-anchor"); 236 237 trainGetTarget(component, "some-target"); 238 239 writer.attribute("target", "some-target"); 240 241 trainGetNestedWriter(writer, nested); 242 243 component.renderBody(nested, cycle); 244 245 nested.close(); 246 247 writer.end(); 248 249 cycle.removeAttribute(Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME); 250 251 replay(); 252 253 new DefaultLinkRenderer().renderLink(writer, cycle, component); 254 255 verify(); 256 } 257 258 public void testDisabled() 259 { 260 IMarkupWriter writer = newWriter(); 261 IRequestCycle cycle = newCycle(); 262 ILinkComponent component = newComponent(); 263 264 trainGetAttribute(cycle, Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME, null); 265 cycle.setAttribute(Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME, component); 266 267 trainIsDisabled(component, true); 268 269 component.renderBody(writer, cycle); 270 271 cycle.removeAttribute(Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME); 272 273 replay(); 274 275 new DefaultLinkRenderer().renderLink(writer, cycle, component); 276 277 verify(); 278 } 279 280 public void testRewinding() 281 { 282 IMarkupWriter writer = newWriter(); 283 IRequestCycle cycle = newCycle(); 284 ILinkComponent component = newComponent(); 285 286 trainGetAttribute(cycle, Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME, null); 287 cycle.setAttribute(Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME, component); 288 289 trainIsDisabled(component, false); 290 trainIsRewinding(cycle, true); 291 292 component.renderBody(writer, cycle); 293 294 cycle.removeAttribute(Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME); 295 296 replay(); 297 298 new DefaultLinkRenderer().renderLink(writer, cycle, component); 299 300 verify(); 301 } 302 303 public void testWithSubclass() 304 { 305 IMarkupWriter writer = newWriter(); 306 NestedMarkupWriter nested = newNestedWriter(); 307 IRequestCycle cycle = newCycle(); 308 ILinkComponent component = newComponent(); 309 ILink link = newLink(); 310 311 trainGetAttribute(cycle, Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME, null); 312 cycle.setAttribute(Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME, component); 313 314 trainIsDisabled(component, false); 315 trainIsRewinding(cycle, false); 316 317 writer.begin("xlink"); 318 319 component.renderAdditionalAttributes(writer, cycle); 320 321 trainGetLink(component, cycle, link); 322 323 trainGetScheme(component, null); 324 325 trainGetPort(component, null); 326 327 trainGetAnchor(component, "my-anchor"); 328 329 trainGetURL(link, null, "my-anchor", "/foo/bar.baz#my-anchor"); 330 331 writer.attribute("xurl", "/foo/bar.baz#my-anchor"); 332 333 trainGetTarget(component, "some-target"); 334 335 writer.attribute("xtarget", "some-target"); 336 337 writer.print("BEFORE-BODY-RENDER"); 338 339 trainGetNestedWriter(writer, nested); 340 341 component.renderBody(nested, cycle); 342 343 writer.print("AFTER-BODY-RENDER"); 344 345 nested.close(); 346 347 writer.end(); 348 349 cycle.removeAttribute(Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME); 350 351 replay(); 352 353 new RendererFixture(writer, cycle, component, "xlink", true, "xtarget", "xurl").renderLink( 354 writer, 355 cycle, 356 component); 357 358 verify(); 359 } 360 361 public void testWithSubclassNoBody() 362 { 363 IMarkupWriter writer = newWriter(); 364 NestedMarkupWriter nested = newNestedWriter(); 365 366 IRequestCycle cycle = newCycle(); 367 ILinkComponent component = newComponent(); 368 ILink link = newLink(); 369 370 trainGetAttribute(cycle, Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME, null); 371 cycle.setAttribute(Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME, component); 372 373 trainIsDisabled(component, false); 374 trainIsRewinding(cycle, false); 375 376 writer.beginEmpty("xlink"); 377 378 component.renderAdditionalAttributes(writer, cycle); 379 380 trainGetLink(component, cycle, link); 381 382 trainGetScheme(component, null); 383 384 trainGetPort(component, null); 385 386 trainGetAnchor(component, "my-anchor"); 387 388 trainGetURL(link, null, "my-anchor", "/foo/bar.baz#my-anchor"); 389 390 writer.attribute("xurl", "/foo/bar.baz#my-anchor"); 391 392 trainGetTarget(component, "some-target"); 393 394 writer.attribute("xtarget", "some-target"); 395 396 writer.print("BEFORE-BODY-RENDER"); 397 398 trainGetNestedWriter(writer, nested); 399 400 writer.print("AFTER-BODY-RENDER"); 401 402 writer.closeTag(); 403 404 cycle.removeAttribute(Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME); 405 406 replay(); 407 408 new RendererFixture(writer, cycle, component, "xlink", false, "xtarget", "xurl") 409 .renderLink(writer, cycle, component); 410 411 verify(); 412 } 413 414 public void testWithSubclassDisabled() 415 { 416 IMarkupWriter writer = newWriter(); 417 IRequestCycle cycle = newCycle(); 418 ILinkComponent component = newComponent(); 419 420 trainGetAttribute(cycle, Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME, null); 421 cycle.setAttribute(Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME, component); 422 423 trainIsDisabled(component, true); 424 425 component.renderBody(writer, cycle); 426 427 cycle.removeAttribute(Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME); 428 429 replay(); 430 431 new RendererFixture(writer, cycle, component, "xlink", true, "xtarget", "xurl").renderLink( 432 writer, 433 cycle, 434 component); 435 436 verify(); 437 } 438 439 public void testWithSubclassDisabledNoBody() 440 { 441 IMarkupWriter writer = newWriter(); 442 IRequestCycle cycle = newCycle(); 443 ILinkComponent component = newComponent(); 444 445 trainGetAttribute(cycle, Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME, null); 446 cycle.setAttribute(Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME, component); 447 448 trainIsDisabled(component, true); 449 450 cycle.removeAttribute(Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME); 451 452 replay(); 453 454 new RendererFixture(writer, cycle, component, "xlink", false, "xtarget", "xurl") 455 .renderLink(writer, cycle, component); 456 457 verify(); 458 } 459 460 protected void trainGetAnchor(ILinkComponent component, String anchor) 461 { 462 expect(component.getAnchor()).andReturn(anchor); 463 } 464 465 protected void trainGetTarget(ILinkComponent component, String target) 466 { 467 expect(component.getTarget()).andReturn(target); 468 } 469 470 protected void trainIsDisabled(ILinkComponent component, boolean isDisabled) 471 { 472 expect(component.isDisabled()).andReturn(isDisabled); 473 } 474 }