113f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann/*******************************************************************************
2b9d1b54e300318b470d9fedccc69d75187016444Evgeny Mandrikov * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
313f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann * All rights reserved. This program and the accompanying materials
413f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann * are made available under the terms of the Eclipse Public License v1.0
513f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann * which accompanies this distribution, and is available at
613f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann * http://www.eclipse.org/legal/epl-v10.html
713f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann *
813f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann * Contributors:
913f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann *    Marc R. Hoffmann - initial API and implementation
1013f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann *
1113f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann *******************************************************************************/
1213f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmannpackage org.jacoco.cli.internal.commands;
1313f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann
1413f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmannimport static org.junit.Assert.assertArrayEquals;
1513f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmannimport static org.junit.Assert.assertFalse;
1613f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmannimport static org.junit.Assert.assertTrue;
1713f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmannimport static org.junit.Assert.fail;
1813f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann
1913f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmannimport java.io.File;
2013f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmannimport java.io.FileInputStream;
2113f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmannimport java.io.FileOutputStream;
2213f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmannimport java.io.IOException;
2313f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmannimport java.io.InputStream;
2413f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmannimport java.io.OutputStream;
2513f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmannimport java.util.HashSet;
2613f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmannimport java.util.Set;
2713f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann
2813f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmannimport org.jacoco.cli.internal.CommandTestBase;
2913f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmannimport org.junit.Rule;
3013f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmannimport org.junit.Test;
3113f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmannimport org.junit.rules.TemporaryFolder;
3213f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmannimport org.objectweb.asm.ClassReader;
3313f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmannimport org.objectweb.asm.ClassVisitor;
3413f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmannimport org.objectweb.asm.FieldVisitor;
3513f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmannimport org.objectweb.asm.Opcodes;
3613f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann
3713f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann/**
3813f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann * Unit tests for {@link Instrument}.
3913f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann */
4013f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmannpublic class InstrumentTest extends CommandTestBase {
4113f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann
4213f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann	@Rule
4313f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann	public TemporaryFolder tmp = new TemporaryFolder();
4413f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann
4513f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann	@Test
4613f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann	public void should_print_usage_when_no_options_are_given()
4713f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann			throws Exception {
4813f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		execute("instrument");
4913f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		assertFailure();
5013f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		assertContains("Option \"--dest\" is required", err);
5113f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		assertContains(
5213f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann				"Usage: java -jar jacococli.jar instrument [<sourcefiles> ...]",
5313f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann				err);
5413f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann	}
5513f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann
5613f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann	@Test
572a2f161920d7608630ba1163d45a858803cfef2eMarc R. Hoffmann	public void should_instrument_class_files_and_copy_resources_when_folder_is_given()
5813f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann			throws Exception {
5913f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		File destdir = tmp.getRoot();
6013f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann
6113f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		execute("instrument", "--dest", destdir.getAbsolutePath(),
6213f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann				getClassPath());
6313f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann
6413f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		assertOk();
6513f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		assertContains("[INFO] 14 classes instrumented to "
6613f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann				+ destdir.getAbsolutePath(), out);
6713f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann
6813f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		// non class-file resources are copied:
6913f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		assertTrue(new File(destdir, "about.html").isFile());
7013f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann
7113f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		assertInstrumented(new File(destdir,
7213f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann				"org/jacoco/cli/internal/commands/InstrumentTest.class"));
7313f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann	}
7413f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann
7513f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann	@Test
762a2f161920d7608630ba1163d45a858803cfef2eMarc R. Hoffmann	public void should_instrument_class_files_to_dest_folder_when_class_files_are_given()
772a2f161920d7608630ba1163d45a858803cfef2eMarc R. Hoffmann			throws Exception {
782a2f161920d7608630ba1163d45a858803cfef2eMarc R. Hoffmann		File destdir = tmp.getRoot();
792a2f161920d7608630ba1163d45a858803cfef2eMarc R. Hoffmann
802a2f161920d7608630ba1163d45a858803cfef2eMarc R. Hoffmann		File src = new File(getClassPath(),
812a2f161920d7608630ba1163d45a858803cfef2eMarc R. Hoffmann				"org/jacoco/cli/internal/commands/InstrumentTest.class");
822a2f161920d7608630ba1163d45a858803cfef2eMarc R. Hoffmann
832a2f161920d7608630ba1163d45a858803cfef2eMarc R. Hoffmann		execute("instrument", "--dest", destdir.getAbsolutePath(),
842a2f161920d7608630ba1163d45a858803cfef2eMarc R. Hoffmann				src.getAbsolutePath());
852a2f161920d7608630ba1163d45a858803cfef2eMarc R. Hoffmann
862a2f161920d7608630ba1163d45a858803cfef2eMarc R. Hoffmann		assertOk();
872a2f161920d7608630ba1163d45a858803cfef2eMarc R. Hoffmann		assertContains(
882a2f161920d7608630ba1163d45a858803cfef2eMarc R. Hoffmann				"[INFO] 1 classes instrumented to " + destdir.getAbsolutePath(),
892a2f161920d7608630ba1163d45a858803cfef2eMarc R. Hoffmann				out);
902a2f161920d7608630ba1163d45a858803cfef2eMarc R. Hoffmann
912a2f161920d7608630ba1163d45a858803cfef2eMarc R. Hoffmann		assertInstrumented(new File(destdir, "InstrumentTest.class"));
922a2f161920d7608630ba1163d45a858803cfef2eMarc R. Hoffmann	}
932a2f161920d7608630ba1163d45a858803cfef2eMarc R. Hoffmann
942a2f161920d7608630ba1163d45a858803cfef2eMarc R. Hoffmann	@Test
9513f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann	public void should_not_instrument_anything_when_no_source_is_given()
9613f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann			throws Exception {
9713f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		File destdir = tmp.getRoot();
9813f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann
9913f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		execute("instrument", "--dest", destdir.getAbsolutePath());
10013f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann
10113f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		assertOk();
10213f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		assertArrayEquals(new String[0], destdir.list());
10313f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann	}
10413f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann
10513f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann	@Test
10613f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann	public void should_not_create_dest_file_when_source_class_is_broken()
10713f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann			throws Exception {
10813f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		File srcdir = new File(tmp.getRoot(), "src");
10913f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		srcdir.mkdir();
11013f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		File destdir = new File(tmp.getRoot(), "dest");
11113f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		destdir.mkdir();
11213f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann
11313f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		OutputStream out = new FileOutputStream(
11413f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann				new File(srcdir, "Broken.class"));
11513f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		out.write((byte) 0xca);
11613f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		out.write((byte) 0xfe);
11713f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		out.write((byte) 0xba);
11813f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		out.write((byte) 0xbe);
11913f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		out.write((byte) 0x00);
12013f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		out.write((byte) 0x00);
12113f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		out.write((byte) 0x00);
12213f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		out.write((byte) 50);
12313f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		out.close();
12413f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann
12513f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		try {
12613f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann			execute("instrument", "--dest", destdir.getAbsolutePath(),
12713f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann					srcdir.getAbsolutePath());
12813f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann			fail("exception expected");
12913f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		} catch (IOException expected) {
13013f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		}
13113f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann
13213f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		assertFalse(new File(destdir, "Broken.class").exists());
13313f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann	}
13413f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann
13513f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann	private void assertInstrumented(File classfile) throws IOException {
13613f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		InputStream in = new FileInputStream(classfile);
13713f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		ClassReader reader = new ClassReader(in);
13813f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		in.close();
13913f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		final Set<String> fields = new HashSet<String>();
140caa820ed62133f47bacba06ea931bf5d7c43dcd6Roberto Araujo		reader.accept(new ClassVisitor(Opcodes.ASM6) {
14113f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann			@Override
14213f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann			public FieldVisitor visitField(int access, String name, String desc,
14313f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann					String signature, Object value) {
14413f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann				fields.add(name);
14513f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann				return null;
14613f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann			}
14713f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		}, 0);
14813f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann		assertTrue(fields.contains("$jacocoData"));
14913f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann	}
15013f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann
15113f12d39db0b3c0ddc60124572e5d4f984be0255Marc R. Hoffmann}
152