@Test public void testCreateSessionAndPassivate() throws IOException, LifecycleException, ClassNotFoundException { // Setup Tomcat instance Tomcat tomcat = getTomcatInstance(); // No file system docBase required StandardContext ctx = (StandardContext) tomcat.addContext("", null); ctx.setDistributable(true); Tomcat.addServlet(ctx, "DummyServlet", new DummyServlet()); ctx.addServletMapping("/dummy", "DummyServlet"); PersistentManager manager = new PersistentManager(); TesterStore store = new TesterStore(); manager.setStore(store); manager.setMaxIdleBackup(0); ctx.setManager(manager); ctx.addValve(new PersistentValve()); tomcat.start(); Assert.assertEquals("No active sessions", manager.getActiveSessions(), 0); Assert.assertTrue("No sessions managed", manager.getSessionIdsFull().isEmpty()); String sessionId = getUrl( "http://localhost:" + getPort() + "/dummy?no_create_session=false").toString(); Assert.assertNotNull("Session is stored", store.load(sessionId)); Assert.assertEquals("All sessions are passivated", manager.getActiveSessions(), 0); Assert.assertTrue("One session was created", !manager.getSessionIdsFull().isEmpty()); }
private void doRequest() throws Exception { Tomcat tomcat = getTomcatInstance(); Context root = tomcat.addContext("", TEMP_DIR); Tomcat.addServlet(root, "Simple", new SimpleServlet()); root.addServletMapping("/test", "Simple"); tomcat.start(); // Open connection setPort(tomcat.getConnector().getLocalPort()); connect(); String[] request = new String[1]; request[0] = "GET /test HTTP/1.0" + CRLF + "Cookie: " + COOKIE_WITH_SEPS + CRLF + CRLF; setRequest(request); processRequest(true); // blocks until response has been read String response = getResponseBody(); // Close the connection disconnect(); reset(); tomcat.stop(); assertEquals(COOKIE_WITH_SEPS, response); }
@Test public void testBug36923() throws Exception { Tomcat tomcat = getTomcatInstance(); File appDir = new File("test/webapp-3.0"); // app dir is relative to server home tomcat.addWebapp(null, "/test", appDir.getAbsolutePath()); tomcat.start(); ByteChunk res = getUrl("http://localhost:" + getPort() + "/test/bug36923.jsp"); String result = res.toString(); assertEcho(result, "00-${hello world}"); }
@Test public void testBug56147() throws Exception { Tomcat tomcat = getTomcatInstance(); File appDir = new File("test/webapp-3.0"); // app dir is relative to server home StandardContext ctx = (StandardContext) tomcat.addWebapp( null, "/test", appDir.getAbsolutePath()); // This test needs the JSTL libraries File lib = new File("webapps/examples/WEB-INF/lib"); ctx.setAliases("/WEB-INF/lib=" + lib.getCanonicalPath()); tomcat.start(); ByteChunk res = getUrl("http://localhost:" + getPort() + "/test/bug5nnnn/bug56147.jsp"); String result = res.toString(); assertEcho(result, "00-OK"); }
@Test void mbeansAvailableBeforeBinder() throws LifecycleException { Tomcat server = new Tomcat(); try { StandardHost host = new StandardHost(); host.setName("localhost"); server.setHost(host); server.setPort(61000); server.start(); TomcatMetrics.monitor(registry, null); assertThat(registry.find("tomcat.global.received").functionCounter()).isNotNull(); } finally { server.stop(); server.destroy(); } }
@Test public void testBug44994() throws Exception { Tomcat tomcat = getTomcatInstance(); File appDir = new File("test/webapp-3.0"); // app dir is relative to server home tomcat.addWebapp(null, "/test", appDir.getAbsolutePath()); tomcat.start(); ByteChunk res = getUrl("http://localhost:" + getPort() + "/test/bug44994.jsp"); String result = res.toString(); assertEcho(result, "00-none"); assertEcho(result, "01-one"); assertEcho(result, "02-many"); }
@Test public void testBug49297MultiplePageEncoding2() throws Exception { Tomcat tomcat = getTomcatInstance(); File appDir = new File("test/webapp-3.0"); // app dir is relative to server home tomcat.addWebapp(null, "/test", appDir.getAbsolutePath()); tomcat.start(); ByteChunk res = new ByteChunk(); int sc = getUrl("http://localhost:" + getPort() + "/test/bug49nnn/bug49297MultiplePageEncoding2.jsp", res, new HashMap<String,List<String>>()); assertEquals(500, sc); }
@Test public void testParameterImmutability() throws Exception { Tomcat tomcat = getTomcatInstance(); // No file system docBase required Context ctx = tomcat.addContext("", null); Tomcat.addServlet(ctx, "forward", new ForwardServlet("/modify")); ctx.addServletMapping("/forward", "forward"); Tomcat.addServlet(ctx, "modify", new ModifyParameterServlet()); ctx.addServletMapping("/modify", "modify"); tomcat.start(); ByteChunk response = new ByteChunk(); StringBuilder target = new StringBuilder("http://localhost:"); target.append(getPort()); target.append("/forward"); int rc = getUrl(target.toString(), response, null); Assert.assertEquals(200, rc); Assert.assertEquals("OK", response.toString()); }
private void setupHeadersTest(Tomcat tomcat) { Context ctx = tomcat.addContext("", getTemporaryDirectory() .getAbsolutePath()); Tomcat.addServlet(ctx, "servlet", new HttpServlet() { private static final long serialVersionUID = 1L; @Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { res.setContentType("text/plain; charset=ISO-8859-1"); res.getWriter().write("OK"); } }); ctx.addServletMapping("/", "servlet"); alv = new HeaderCountLogValve(); tomcat.getHost().getPipeline().addValve(alv); }
@Test public void bug54241a() throws Exception { Tomcat tomcat = getTomcatInstance(); File appDir = new File("test/webapp-3.0"); tomcat.addWebapp(null, "/test", appDir.getAbsolutePath()); tomcat.start(); ByteChunk res = new ByteChunk(); int rc = getUrl("http://localhost:" + getPort() + "/test/bug5nnnn/bug54241a.jsp", res, null); Assert.assertEquals(HttpServletResponse.SC_OK, rc); String body = res.toString(); Assert.assertTrue(body.contains("01: null")); Assert.assertTrue(body.contains("02: null")); }
@Test public void testBug49297DuplicateAttr() throws Exception { Tomcat tomcat = getTomcatInstance(); File appDir = new File("test/webapp-3.0"); // app dir is relative to server home tomcat.addWebapp(null, "/test", appDir.getAbsolutePath()); tomcat.start(); int sc = getUrl("http://localhost:" + getPort() + "/test/bug49nnn/bug49297DuplicateAttr.jsp", new ByteChunk(), new HashMap<String,List<String>>()); assertEquals(500, sc); }
@Test public void testServlet24NoEL() throws Exception { Tomcat tomcat = getTomcatInstance(); File appDir = new File("test/webapp-2.4"); // app dir is relative to server home tomcat.addWebapp(null, "/test", appDir.getAbsolutePath()); tomcat.start(); ByteChunk res = getUrl("http://localhost:" + getPort() + "/test/el-as-literal.jsp"); String result = res.toString(); assertTrue(result.indexOf("<p>00-hello world</p>") > 0); assertTrue(result.indexOf("<p>01-#{'hello world'}</p>") > 0); }
@Test public void testBug52577() throws Exception { Tomcat tomcat = getTomcatInstance(); // No file system docBase required Context root = tomcat.addContext("", null); Bug52577Servlet bug52577 = new Bug52577Servlet(); Tomcat.addServlet(root, "bug52577", bug52577); root.addServletMapping("/", "bug52577"); tomcat.start(); ByteChunk bc = new ByteChunk(); int rc = getUrl("http://localhost:" + getPort() + "/", bc, null, null); assertEquals(HttpServletResponse.SC_OK, rc); assertEquals("OK", bc.toString()); }
private void doTestUriDecoding(String path, String encoding, String expectedPathInfo) throws Exception{ // Setup Tomcat instance Tomcat tomcat = getTomcatInstance(); tomcat.getConnector().setURIEncoding(encoding); // No file system docBase required Context ctx = tomcat.addContext("", null); PathInfoServlet servlet = new PathInfoServlet(); Tomcat.addServlet(ctx, "servlet", servlet); ctx.addServletMapping("/*", "servlet"); tomcat.start(); int rc = getUrl("http://localhost:" + getPort() + path, new ByteChunk(), null); Assert.assertEquals(HttpServletResponse.SC_OK, rc); Assert.assertEquals(expectedPathInfo, servlet.getPathInfo()); }
private DefaultInstanceManager doClassUnloadingPrep() throws Exception { Tomcat tomcat = getTomcatInstance(); // Create the context (don't use addWebapp as we want to modify the // JSP Servlet settings). File appDir = new File("test/webapp-3.0"); StandardContext ctxt = (StandardContext) tomcat.addContext( null, "/test", appDir.getAbsolutePath()); // Configure the defaults and then tweak the JSP servlet settings // Note: Min value for maxLoadedJsps is 2 Tomcat.initWebappDefaults(ctxt); Wrapper w = (Wrapper) ctxt.findChild("jsp"); w.addInitParameter("maxLoadedJsps", "2"); tomcat.start(); return (DefaultInstanceManager) ctxt.getInstanceManager(); }
@Test public void testBug46596() throws Exception { Tomcat tomcat = getTomcatInstance(); File appDir = new File("test/webapp-3.0"); // app dir is relative to server home tomcat.addWebapp(null, "/test", appDir.getAbsolutePath()); tomcat.start(); ByteChunk res = getUrl("http://localhost:" + getPort() + "/test/bug46596.jsp"); String result = res.toString(); assertEcho(result, "{OK}"); }
@Test public void testSecurityAnnotationsNoWebXmlConstraints() throws Exception { // Setup Tomcat instance Tomcat tomcat = getTomcatInstance(); File appDir = new File("test/webapp-3.0-servletsecurity"); tomcat.addWebapp(null, "", appDir.getAbsolutePath()); tomcat.start(); ByteChunk bc = new ByteChunk(); int rc; rc = getUrl("http://localhost:" + getPort() + "/", bc, null, null); assertTrue(bc.getLength() > 0); assertEquals(403, rc); }
protected void startTomcat() throws Exception { tomcat = new Tomcat(); File base = new File(System.getProperty("java.io.tmpdir")); org.apache.catalina.Context ctx = tomcat.addContext("/foo",base.getAbsolutePath()); FilterDef fd = new FilterDef(); fd.setFilterClass(TestFilter.class.getName()); fd.setFilterName("TestFilter"); FilterMap fm = new FilterMap(); fm.setFilterName("TestFilter"); fm.addURLPattern("/*"); fm.addServletName("/bar"); ctx.addFilterDef(fd); ctx.addFilterMap(fm); tomcat.addServlet(ctx, "/bar", TestServlet.class.getName()); ctx.addServletMapping("/bar", "/bar"); host = "localhost"; port = getLocalPort(); tomcat.setHostname(host); tomcat.setPort(port); tomcat.start(); }
/** * Additional test following on from SPR-7350 above to check files that * contain JNDI reserved characters can be served when caching is disabled. */ @Test public void testReservedJNDIFileNamesNoCache() throws Exception { Tomcat tomcat = getTomcatInstance(); File appDir = new File("test/webapp-3.0-fragments"); // app dir is relative to server home StandardContext ctxt = (StandardContext) tomcat.addWebapp( null, "/test", appDir.getAbsolutePath()); ctxt.setCachingAllowed(false); tomcat.start(); // Should be found in resources.jar ByteChunk bc = getUrl("http://localhost:" + getPort() + "/test/'singlequote.jsp"); assertEquals("<p>'singlequote.jsp in resources.jar</p>", bc.toString()); // Should be found in file system bc = getUrl("http://localhost:" + getPort() + "/test/'singlequote2.jsp"); assertEquals("<p>'singlequote2.jsp in file system</p>", bc.toString()); }
private void doBug56501(String deployPath, String requestPath, String expected) throws Exception { // Setup Tomcat instance Tomcat tomcat = getTomcatInstance(); // No file system docBase required Context ctx = tomcat.addContext(deployPath, null); Tomcat.addServlet(ctx, "servlet", new Bug56501Servelet()); ctx.addServletMapping("/*", "servlet"); tomcat.start(); ByteChunk res = getUrl("http://localhost:" + getPort() + requestPath); String resultPath = res.toString(); if (resultPath == null) { resultPath = ""; } assertEquals(expected, resultPath); }
@Test(expected=javax.websocket.DeploymentException.class) public void testConnectToServerEndpointInvalidScheme() throws Exception { Tomcat tomcat = getTomcatInstance(); // No file system docBase required Context ctx = tomcat.addContext("", null); ctx.addApplicationListener(TesterEchoServer.Config.class.getName()); tomcat.start(); WebSocketContainer wsContainer = ContainerProvider.getWebSocketContainer(); wsContainer.connectToServer(TesterProgrammaticEndpoint.class, ClientEndpointConfig.Builder.create().build(), new URI("ftp://" + getHostName() + ":" + getPort() + TesterEchoServer.Config.PATH_ASYNC)); }
private void doTestBug51744(boolean exceptionOnFailedWrite) throws Exception { Tomcat tomcat = getTomcatInstance(); tomcat.enableNaming(); // No file system docBase required StandardContext ctx = (StandardContext) tomcat.addContext("", null); ctx.setJndiExceptionOnFailedWrite(exceptionOnFailedWrite); // Map the test Servlet Bug51744Servlet bug51744Servlet = new Bug51744Servlet(); Tomcat.addServlet(ctx, "bug51744Servlet", bug51744Servlet); ctx.addServletMapping("/", "bug51744Servlet"); tomcat.start(); ByteChunk bc = new ByteChunk(); int rc = getUrl("http://localhost:" + getPort() + "/", bc, null); assertEquals(200, rc); assertTrue(bc.toString().contains(Bug51744Servlet.EXPECTED)); if (exceptionOnFailedWrite) { assertTrue(bc.toString().contains(Bug51744Servlet.ERROR_MESSAGE)); } }
@Test public void testBug49297NoSpaceStrict() throws Exception { Tomcat tomcat = getTomcatInstance(); File appDir = new File("test/webapp-3.0"); // app dir is relative to server home tomcat.addWebapp(null, "/test", appDir.getAbsolutePath()); tomcat.start(); int sc = getUrl("http://localhost:" + getPort() + "/test/bug49nnn/bug49297NoSpace.jsp", new ByteChunk(), new HashMap<String,List<String>>()); assertEquals(500, sc); }
@Test public void testBug48668b() throws Exception { Tomcat tomcat = getTomcatInstance(); File appDir = new File("test/webapp-3.0"); // app dir is relative to server home tomcat.addWebapp(null, "/test", appDir.getAbsolutePath()); tomcat.start(); ByteChunk res = getUrl("http://localhost:" + getPort() + "/test/bug48nnn/bug48668b.jsp"); String result = res.toString(); assertEcho(result, "00-Hello world</p>#{foo.bar}"); assertEcho(result, "01-Hello world</p>#{foo2"); }
/** * Test JNDI is available to ServletContextListeners. */ @Test public void testBug49132() throws Exception { Tomcat tomcat = getTomcatInstance(); // No file system docBase required org.apache.catalina.Context ctx = tomcat.addContext("", null); // Enable JNDI - it is disabled by default tomcat.enableNaming(); ContextEnvironment environment = new ContextEnvironment(); environment.setType(BUG49132_VALUE.getClass().getName()); environment.setName(BUG49132_NAME); environment.setValue(BUG49132_VALUE); ctx.getNamingResources().addEnvironment(environment); ctx.addApplicationListener(Bug49132Listener.class.getName()); tomcat.start(); assertEquals(LifecycleState.STARTED, ctx.getState()); }
/** * Custom error/status codes should not result in a blank response. */ @Test public void testBug54536() throws Exception { Tomcat tomcat = getTomcatInstance(); // No file system docBase required Context ctx = tomcat.addContext("", null); Tomcat.addServlet(ctx, "bug54536", new Bug54536Servlet()); ctx.addServletMapping("/", "bug54536"); tomcat.start(); ByteChunk res = new ByteChunk(); int rc = getUrl("http://localhost:" + getPort(), res, null); Assert.assertEquals(Bug54536Servlet.ERROR_STATUS, rc); String body = res.toString(); Assert.assertNotNull(body); Assert.assertTrue(body, body.contains(Bug54536Servlet.ERROR_MESSAGE)); }
@Test public void testBug42390() throws Exception { Tomcat tomcat = getTomcatInstance(); File appDir = new File("test/webapp-3.0"); // app dir is relative to server home tomcat.addWebapp(null, "/test", appDir.getAbsolutePath()); tomcat.start(); Exception e = null; try { getUrl("http://localhost:" + getPort() + "/test/bug42390.jsp"); } catch (IOException ioe) { e = ioe; } // Should not fail assertNull(e); }
@Test public void testBug49555() throws Exception { Tomcat tomcat = getTomcatInstance(); File appDir = new File("test/webapp-3.0"); // app dir is relative to server home tomcat.addWebapp(null, "/test", appDir.getAbsolutePath()); tomcat.start(); ByteChunk res = getUrl("http://localhost:" + getPort() + "/test/bug49nnn/bug49555.jsp"); String result = res.toString(); assertEcho(result, "00-" + TesterFunctions.Inner$Class.RETVAL); }
@Test public void testBug56612() throws Exception { Tomcat tomcat = getTomcatInstance(); File appDir = new File("test/webapp-3.0"); // app dir is relative to server home tomcat.addWebapp(null, "/test", appDir.getAbsolutePath()); tomcat.start(); ByteChunk res = getUrl("http://localhost:" + getPort() + "/test/bug5nnnn/bug56612.jsp"); String result = res.toString(); Assert.assertTrue(result.contains("00-''")); }
@Test public void testBug49726b() throws Exception { Tomcat tomcat = getTomcatInstance(); File appDir = new File("test/webapp-3.0"); tomcat.addWebapp(null, "/test", appDir.getAbsolutePath()); tomcat.start(); ByteChunk res = new ByteChunk(); Map<String,List<String>> headers = new HashMap<String,List<String>>(); getUrl("http://localhost:" + getPort() + "/test/bug49nnn/bug49726b.jsp", res, headers); // Check request completed String result = res.toString(); assertEcho(result, "OK"); // Check content type assertTrue(headers.get("Content-Type").get(0).startsWith("text/plain")); }
@Test public void bug54241b() throws Exception { Tomcat tomcat = getTomcatInstance(); File appDir = new File("test/webapp-3.0"); tomcat.addWebapp(null, "/test", appDir.getAbsolutePath()); tomcat.start(); ByteChunk res = new ByteChunk(); int rc = getUrl("http://localhost:" + getPort() + "/test/bug5nnnn/bug54241b.jsp", res, null); Assert.assertEquals(res.toString(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR, rc); }
@Test public void testBug51544() throws Exception { Tomcat tomcat = getTomcatInstance(); File appDir = new File("test/webapp-3.0"); // app dir is relative to server home tomcat.addWebapp(null, "/test", appDir.getAbsolutePath()); tomcat.start(); ByteChunk res = getUrl("http://localhost:" + getPort() + "/test/bug5nnnn/bug51544.jsp"); String result = res.toString(); assertEcho(result, "Empty list: true"); }
public static void main(String[] args) throws Exception { ApplicationContext context = new AnnotationConfigApplicationContext(Application.class); // (1) Tomcat tomcatServer = context.getBean(Tomcat.class); tomcatServer.start(); System.out.println("Press ENTER to exit."); System.in.read(); }
@Test public void testCustomSslImplementation() throws Exception { TesterSupport.configureClientSsl(); Tomcat tomcat = getTomcatInstance(); Connector connector = tomcat.getConnector(); Assume.assumeFalse("This test is only for JSSE based SSL connectors", connector.getProtocolHandlerClassName().contains("Apr")); connector.setProperty("sslImplementationName", "org.apache.tomcat.util.net.jsse.TesterBug50640SslImpl"); connector.setProperty(TesterBug50640SslImpl.PROPERTY_NAME, TesterBug50640SslImpl.PROPERTY_VALUE); connector.setProperty("sslProtocol", "tls"); File keystoreFile = new File("test/org/apache/tomcat/util/net/localhost.jks"); connector.setAttribute( "keystoreFile", keystoreFile.getAbsolutePath()); connector.setSecure(true); connector.setProperty("SSLEnabled", "true"); File appDir = new File(getBuildDirectory(), "webapps/examples"); tomcat.addWebapp(null, "/examples", appDir.getAbsolutePath()); tomcat.start(); ByteChunk res = getUrl("https://localhost:" + getPort() + "/examples/servlets/servlet/HelloWorldExample"); assertTrue(res.toString().indexOf("<a href=\"../helloworld.html\">") > 0); }
@Test public void testTimerThreadLeak() throws Exception { Tomcat tomcat = getTomcatInstance(); // No file system docBase required Context ctx = tomcat.addContext("", null); if (ctx instanceof StandardContext) { ((StandardContext) ctx).setClearReferencesStopTimerThreads(true); } Tomcat.addServlet(ctx, "taskServlet", new TaskServlet()); ctx.addServletMapping("/", "taskServlet"); tomcat.start(); // This will trigger the timer & thread creation getUrl("http://localhost:" + getPort() + "/"); // Stop the context ctx.stop(); Thread[] threads = getThreads(); for (Thread thread : threads) { if (thread != null && thread.isAlive() && TaskServlet.TIMER_THREAD_NAME.equals(thread.getName())) { thread.join(5000); if (thread.isAlive()) { fail("Timer thread still running"); } } } }
/** * Test attempting to access special paths (WEB-INF/META-INF) using * DefaultServlet. */ @Test public void testGetSpecials() throws Exception { Tomcat tomcat = getTomcatInstance(); String contextPath = "/examples"; File appDir = new File(getBuildDirectory(), "webapps" + contextPath); // app dir is relative to server home tomcat.addWebapp(null, "/examples", appDir.getAbsolutePath()); tomcat.start(); final ByteChunk res = new ByteChunk(); int rc =getUrl("http://localhost:" + getPort() + contextPath + "/WEB-INF/web.xml", res, null); assertEquals(HttpServletResponse.SC_NOT_FOUND, rc); rc =getUrl("http://localhost:" + getPort() + contextPath + "/WEB-INF/doesntexistanywhere", res, null); assertEquals(HttpServletResponse.SC_NOT_FOUND, rc); rc =getUrl("http://localhost:" + getPort() + contextPath + "/WEB-INF/", res, null); assertEquals(HttpServletResponse.SC_NOT_FOUND, rc); rc =getUrl("http://localhost:" + getPort() + contextPath + "/META-INF/MANIFEST.MF", res, null); assertEquals(HttpServletResponse.SC_NOT_FOUND, rc); rc =getUrl("http://localhost:" + getPort() + contextPath + "/META-INF/doesntexistanywhere", res, null); assertEquals(HttpServletResponse.SC_NOT_FOUND, rc); }
@Test public void testBug53257f() throws Exception { Tomcat tomcat = getTomcatInstance(); File appDir = new File("test/webapp-3.0"); tomcat.addWebapp(null, "/test", appDir.getAbsolutePath()); tomcat.start(); ByteChunk res = getUrl("http://localhost:" + getPort() + "/test/bug53257/foo%20bar.jsp"); // Check request completed String result = res.toString(); assertEcho(result, "OK"); }
private Tomcat startServer( final Class<? extends WsContextListener> configClass) throws LifecycleException { Tomcat tomcat = getTomcatInstance(); // No file system docBase required Context ctx = tomcat.addContext("", null); ctx.addApplicationListener(configClass.getName()); Tomcat.addServlet(ctx, "default", new DefaultServlet()); ctx.addServletMapping("/", "default"); tomcat.start(); return tomcat; }
@Test public void testBug45427() throws Exception { Tomcat tomcat = getTomcatInstance(); File appDir = new File("test/webapp-3.0"); // app dir is relative to server home tomcat.addWebapp(null, "/test", appDir.getAbsolutePath()); tomcat.start(); ByteChunk res = getUrl("http://localhost:" + getPort() + "/test/bug45nnn/bug45427.jsp"); String result = res.toString(); // Warning: JSP attribute escaping != Java String escaping assertEcho(result, "00-hello world"); assertEcho(result, "01-hello 'world"); assertEcho(result, "02-hello \"world"); assertEcho(result, "03-hello \"world"); assertEcho(result, "04-hello world"); assertEcho(result, "05-hello 'world"); assertEcho(result, "06-hello 'world"); assertEcho(result, "07-hello \"world"); assertEcho(result, "08-hello world"); assertEcho(result, "09-hello 'world"); assertEcho(result, "10-hello \"world"); assertEcho(result, "11-hello \"world"); assertEcho(result, "12-hello world"); assertEcho(result, "13-hello 'world"); assertEcho(result, "14-hello 'world"); assertEcho(result, "15-hello \"world"); }