/* * Copyright (c) 2006 Rogério Liesenfeld * This file is subject to the terms of the MIT license (see LICENSE.txt). */ package mockit; import java.io.*; import java.net.*; import java.util.*; import java.util.jar.*; import java.util.jar.Attributes.Name; import java.util.zip.*; import static java.util.Arrays.*; import org.junit.*; import static org.junit.Assert.*; public final class ClassLoadingAndJREMocksTest { static class Foo {} @Test public void mockUpFile() { new MockUp<File>() { @Mock void $init(String name) {} // not necessary, except to verify non-occurrence of NPE @Mock boolean exists() { return true; } }; new Foo(); // causes a class load assertTrue(new File("filePath").exists()); } @Test public void mockFileSafelyUsingReentrantMockMethod() { new MockUp<File>() { @Mock boolean exists(Invocation inv) { File it = inv.getInvokedInstance(); return "testFile".equals(it.getName()) || inv.<Boolean>proceed(); } }; checkForTheExistenceOfSeveralFiles(); } void checkForTheExistenceOfSeveralFiles() { assertFalse(new File("someOtherFile").exists()); assertTrue(new File("testFile").exists()); assertFalse(new File("yet/another/file").exists()); assertTrue(new File("testFile").exists()); } @Test public void mockFileSafelyUsingProceed() { new MockUp<File>() { @Mock boolean exists(Invocation inv) { File it = inv.getInvokedInstance(); return "testFile".equals(it.getName()) || inv.<Boolean>proceed(); } }; checkForTheExistenceOfSeveralFiles(); } @Test public void mockFileSafelyUsingDynamicPartialMocking() { final File aFile = new File(""); new Expectations(File.class) {{ aFile.exists(); result = new Delegate() { @Mock boolean exists(Invocation inv) { File it = inv.getInvokedInstance(); return "testFile".equals(it.getName()); } }; }}; checkForTheExistenceOfSeveralFiles(); } @Test public void mockFileOutputStreamInstantiation() throws Exception { final String fileName = "test.txt"; new Expectations(FileOutputStream.class) {{ OutputStream os = new FileOutputStream(fileName); //noinspection ConstantConditions os.write((byte[]) any); os.close(); }}; FileOutputStream output = new FileOutputStream(fileName); output.write(new byte[] {123}); output.close(); assertFalse(new File(fileName).exists()); } @Test public void mockEntireAbstractListClass(@Mocked AbstractList<?> c) { assertNull(c.get(1)); } @Test public void attemptToMockNonMockableJREClass(@Mocked Integer mock) { assertNull(mock); } static class ClassWithVector { @SuppressWarnings("UseOfObsoleteCollectionType") final Collection<?> theVector = new Vector<Object>(); public int getVectorSize() { return theVector.size(); } } @Test public void useMockedVectorDuringClassLoading(@Mocked final Vector<?> mockedVector) { new Expectations() {{ mockedVector.size(); result = 2; }}; assertEquals(2, new ClassWithVector().getVectorSize()); } @Test public void mockHashtable(@Mocked final Properties mock) { Properties props = new Properties(); new Expectations() {{ mock.remove(anyString); result = 123; mock.getProperty("test"); result = "mock"; }}; assertEquals(123, props.remove("")); assertEquals("mock", props.getProperty("test")); } @Test public void mockURLAndURLConnection(@Mocked URL mockUrl, @Mocked URLConnection mockConnection) throws Exception { URLConnection conn = mockUrl.openConnection(); assertSame(mockConnection, conn); } @Test public void mockURLAndHttpURLConnection(@Mocked URL mockUrl, @Mocked HttpURLConnection mockConnection) throws Exception { HttpURLConnection conn = (HttpURLConnection) mockUrl.openConnection(); assertSame(mockConnection, conn); } @Test public void mockURLAndHttpURLConnectionWithDynamicMock(@Mocked final HttpURLConnection mockHttpConnection) throws Exception { final URL url = new URL("http://nowhere"); new Expectations(url) {{ url.openConnection(); result = mockHttpConnection; mockHttpConnection.getOutputStream(); result = new ByteArrayOutputStream(); }}; // Code under test: HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setDoOutput(true); conn.setRequestMethod("PUT"); OutputStream out = conn.getOutputStream(); assertNotNull(out); new Verifications() {{ mockHttpConnection.setDoOutput(true); mockHttpConnection.setRequestMethod("PUT"); }}; } String readResourceContents(String hostName, int port, String resourceId, int connectionTimeoutMillis) throws IOException { URL url = new URL("http", hostName, port, resourceId); URLConnection connection = url.openConnection(); connection.setConnectTimeout(connectionTimeoutMillis); connection.connect(); Object content = connection.getContent(); return content.toString(); } @Test public void cascadingMockedURLWithInjectableCascadedURLConnection( @Mocked URL anyUrl, @Injectable final URLConnection cascadedUrlConnection) throws Exception { final String testContents = "testing"; new Expectations() {{ cascadedUrlConnection.getContent(); result = testContents; }}; String contents = readResourceContents("remoteHost", 80, "aResource", 1000); assertEquals(testContents, contents); } @Test public void mockFileInputStream() throws Exception { new Expectations(FileInputStream.class) {{ new FileInputStream("").close(); result = new IOException(); }}; try { new FileInputStream("").close(); fail(); } catch (IOException ignore) { // OK } } @Test public void mockNonExistentZipFileSoItAppearsToExistWithTheContentsOfAnExistingFile() throws Exception { String existentZipFileName = getClass().getResource("test.zip").getPath(); final ZipFile testZip = new ZipFile(existentZipFileName); new Expectations(ZipFile.class) {{ new ZipFile("non-existent"); result = testZip; }}; assertEquals("test", readFromZipFile("non-existent")); try { new ZipFile("another-non-existent"); fail(); } catch (IOException ignore) {} assertEquals("test", readFromZipFile(existentZipFileName)); } private String readFromZipFile(String fileName) throws IOException { ZipFile zf = new ZipFile(fileName); ZipEntry firstEntry = zf.entries().nextElement(); InputStream content = zf.getInputStream(firstEntry); return new BufferedReader(new InputStreamReader(content)).readLine(); } @Test public void mockJarEntry(@Mocked final JarEntry mockEntry) { new Expectations() {{ mockEntry.getName(); result = "Test"; }}; assertEquals("Test", mockEntry.getName()); } String readMainClassAndFileNamesFromJar(File file, List<String> containedFileNames) throws IOException { JarFile jarFile = new JarFile(file); Manifest manifest = jarFile.getManifest(); Attributes mainAttributes = manifest.getMainAttributes(); String mainClassName = mainAttributes.getValue(Name.MAIN_CLASS); Enumeration<JarEntry> jarEntries = jarFile.entries(); while (jarEntries.hasMoreElements()) { JarEntry jarEntry = jarEntries.nextElement(); containedFileNames.add(jarEntry.getName()); } return mainClassName; } @Test public void mockJavaUtilJarClasses( @Mocked final JarFile mockFile, @Mocked final Manifest mockManifest, @Mocked final Attributes mockAttributes, @Mocked final Enumeration<JarEntry> mockEntries, @Mocked final JarEntry mockEntry) throws Exception { final File testFile = new File("test.jar"); final String mainClassName = "test.Main"; new StrictExpectations() {{ new JarFile(testFile); mockFile.getManifest(); result = mockManifest; mockManifest.getMainAttributes(); result = mockAttributes; mockAttributes.getValue(Name.MAIN_CLASS); result = mainClassName; mockFile.entries(); result = mockEntries; mockEntries.hasMoreElements(); result = true; mockEntries.nextElement(); result = mockEntry; mockEntry.getName(); result = "test/Main$Inner.class"; mockEntries.hasMoreElements(); result = true; mockEntries.nextElement(); result = mockEntry; mockEntry.getName(); result = "test/Main.class"; mockEntries.hasMoreElements(); result = false; }}; List<String> fileNames = new ArrayList<String>(); String mainClassFromJar = readMainClassAndFileNamesFromJar(testFile, fileNames); assertEquals(mainClassName, mainClassFromJar); assertEquals(asList("test/Main$Inner.class", "test/Main.class"), fileNames); } @Test(expected = IllegalArgumentException.class) public void attemptToMockJREClassThatIsNeverMockable(@Mocked Class<?> mockClass) { } @Test // StackOverflowError when run by itself, due to recursive class loading of initial classes public void mockSystemNanoTime() { new MockUp<System>() { @Mock long nanoTime() { return 123; } }; assertEquals(123, System.nanoTime()); } }