package com.google.code.maven_replacer_plugin; import static java.util.Arrays.asList; import static junit.framework.Assert.assertSame; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.argThat; import static org.mockito.Matchers.eq; import static org.mockito.Matchers.isA; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.List; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.logging.Log; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import com.google.code.maven_replacer_plugin.file.FileUtils; import com.google.code.maven_replacer_plugin.include.FileSelector; @RunWith(MockitoJUnitRunner.class) public class ReplacerMojoTest { private static final String ENCODING = "encoding"; private static final String XPATH = "xpath"; private static final String REGEX_FLAG = "regex flag"; private static final String FILE = "file"; private static final boolean REGEX = true; private static final String OUTPUT_FILE = "output file"; private static final int REGEX_PATTERN_FLAGS = 999; private static final String BASE_DIR = "base dir"; private static final String TOKEN_VALUE_MAP = "token value map"; private static final String TOKEN_FILE = "token file"; private static final String VALUE_FILE = "value file"; private static final String TOKEN = "token"; private static final String VALUE = "value"; private static final String NO_ENCODING_SET = null; @Mock private FileUtils fileUtils; @Mock private ReplacementProcessor processor; @Mock private ReplacerFactory replacerFactory; @Mock private TokenValueMapFactory tokenValueMapFactory; @Mock private FileSelector fileSelector; @Mock private PatternFlagsFactory patternFlagsFactory; @Mock private Log log; @Mock private OutputFilenameBuilder outputFilenameBuilder; @Mock private SummaryBuilder summaryBuilder; private List<String> regexFlags; private ReplacerMojo mojo; @Before public void setUp() throws Exception { regexFlags = asList(REGEX_FLAG); when(patternFlagsFactory.buildFlags(regexFlags)).thenReturn(REGEX_PATTERN_FLAGS); mojo = new ReplacerMojo(fileUtils, processor, replacerFactory, tokenValueMapFactory, fileSelector, patternFlagsFactory, outputFilenameBuilder, summaryBuilder) { @Override public Log getLog() { return log; } }; when(outputFilenameBuilder.buildFrom(FILE, mojo)).thenReturn(OUTPUT_FILE); } @Test public void shouldReplaceContentsInReplacements() throws Exception { Replacement replacement = mock(Replacement.class); List<Replacement> replacements = asList(replacement); mojo.setRegexFlags(regexFlags); mojo.setRegex(REGEX); mojo.setReplacements(replacements); mojo.setFile(FILE); mojo.setIgnoreMissingFile(true); mojo.setOutputFile(OUTPUT_FILE); mojo.setBasedir(BASE_DIR); mojo.setEncoding(ENCODING); mojo.execute(); assertSame(FILE, mojo.getFile()); verify(processor).replace(replacements, REGEX, BASE_DIR + File.separator + FILE, OUTPUT_FILE, REGEX_PATTERN_FLAGS, ENCODING); verify(summaryBuilder).add(BASE_DIR + File.separator + FILE, OUTPUT_FILE, ENCODING, log); verify(summaryBuilder).print(log); } @Test public void shouldSkipAndDoNothing() throws Exception { mojo.setToken(TOKEN); mojo.setValue(VALUE); mojo.setFile(FILE); mojo.setSkip(true); mojo.execute(); verifyZeroInteractions(processor); verifyZeroInteractions(summaryBuilder); } @Test public void shouldIgnoreBaseDirWhenFileIsAbsolutePathed() throws Exception { Replacement replacement = mock(Replacement.class); List<Replacement> replacements = asList(replacement); when(fileUtils.isAbsolutePath(FILE)).thenReturn(true); mojo.setReplacements(replacements); mojo.setFile(FILE); mojo.execute(); verify(processor).replace(replacements, REGEX, FILE, OUTPUT_FILE, 0, null); verify(summaryBuilder).add(FILE, OUTPUT_FILE, null, log); verify(summaryBuilder).print(log); } @Test public void shouldLimitReplacementsToMaxReplacements() throws Exception { Replacement replacement1 = mock(Replacement.class); Replacement replacement2 = mock(Replacement.class); List<Replacement> replacements = asList(replacement1, replacement2); when(fileUtils.isAbsolutePath(FILE)).thenReturn(true); mojo.setReplacements(replacements); mojo.setMaxReplacements(1); mojo.setFile(FILE); mojo.execute(); verify(processor).replace(asList(replacement1), REGEX, FILE, OUTPUT_FILE, 0, null); verify(summaryBuilder).add(FILE, OUTPUT_FILE, null, log); verify(summaryBuilder).print(log); } @Test public void shouldReplaceContentsInLocalFile() throws Exception { Replacement replacement = mock(Replacement.class); List<Replacement> replacements = asList(replacement); mojo.setRegexFlags(regexFlags); mojo.setRegex(REGEX); mojo.setReplacements(replacements); mojo.setFile(FILE); mojo.setOutputFile(OUTPUT_FILE); mojo.setBasedir(null); mojo.execute(); assertSame(FILE, mojo.getFile()); verify(processor).replace(replacements, REGEX, FILE, OUTPUT_FILE, REGEX_PATTERN_FLAGS, NO_ENCODING_SET); verify(summaryBuilder).add(FILE, OUTPUT_FILE, NO_ENCODING_SET, log); verify(summaryBuilder).print(log); } @Test public void shouldReplaceContentsInReplacementsButNotPrintSummaryIfQuiet() throws Exception { Replacement replacement = mock(Replacement.class); List<Replacement> replacements = asList(replacement); mojo.setQuiet(true); mojo.setRegexFlags(regexFlags); mojo.setRegex(REGEX); mojo.setReplacements(replacements); mojo.setFile(FILE); mojo.setOutputFile(OUTPUT_FILE); mojo.setBasedir(BASE_DIR); mojo.execute(); verify(processor).replace(replacements, REGEX, BASE_DIR + File.separator + FILE, OUTPUT_FILE, REGEX_PATTERN_FLAGS, NO_ENCODING_SET); verify(summaryBuilder).add(BASE_DIR + File.separator + FILE, OUTPUT_FILE, NO_ENCODING_SET, log); verify(summaryBuilder, never()).print(log); } @Test public void shouldReplaceContentsInIncludeAndExcludes() throws Exception { List<String> includes = asList("include"); List<String> excludes = asList("exclude"); when(fileSelector.listIncludes(BASE_DIR, includes, excludes)).thenReturn(asList(FILE)); mojo.setIncludes(includes); mojo.setExcludes(excludes); mojo.setToken(TOKEN); mojo.setValue(VALUE); mojo.setBasedir(BASE_DIR); mojo.execute(); assertSame(mojo.getIncludes(), includes); assertSame(mojo.getExcludes(), excludes); verify(processor).replace(argThat(replacementOf(null, VALUE, false, TOKEN)), eq(REGEX), eq(BASE_DIR + File.separator + FILE), eq(OUTPUT_FILE), anyInt(), eq(NO_ENCODING_SET)); } @Test public void shouldReplaceContentsInFilesToIncludeAndExclude() throws Exception { String includes = "include1, include2"; String excludes = "exclude1, exclude2"; when(fileSelector.listIncludes(BASE_DIR, asList("include1", "include2"), asList("exclude1", "exclude2"))).thenReturn(asList(FILE)); mojo.setFilesToInclude(includes); mojo.setFilesToExclude(excludes); mojo.setToken(TOKEN); mojo.setValue(VALUE); mojo.setBasedir(BASE_DIR); mojo.execute(); assertSame(mojo.getFilesToInclude(), includes); assertSame(mojo.getFilesToExclude(), excludes); verify(processor).replace(argThat(replacementOf(null, VALUE, false, TOKEN)), eq(REGEX), eq(BASE_DIR + File.separator + FILE), eq(OUTPUT_FILE), anyInt(), eq(NO_ENCODING_SET)); } @Test public void shouldReplaceContentsWithTokenValuesInMapWithComments() throws Exception { Replacement replacement = mock(Replacement.class); List<Replacement> replacements = asList(replacement); when(tokenValueMapFactory.replacementsForFile(BASE_DIR + File.separator + TOKEN_VALUE_MAP, true, false, NO_ENCODING_SET)).thenReturn(replacements); mojo.setRegexFlags(regexFlags); mojo.setRegex(REGEX); mojo.setTokenValueMap(TOKEN_VALUE_MAP); mojo.setFile(FILE); mojo.setOutputFile(OUTPUT_FILE); mojo.setBasedir(BASE_DIR); mojo.execute(); verify(processor).replace(replacements, REGEX, BASE_DIR + File.separator + FILE, OUTPUT_FILE, REGEX_PATTERN_FLAGS, NO_ENCODING_SET); } @Test public void shouldReplaceContentsWithTokenValuesInMapWithoutComments() throws Exception { Replacement replacement = mock(Replacement.class); List<Replacement> replacements = asList(replacement); when(tokenValueMapFactory.replacementsForFile(BASE_DIR + File.separator + TOKEN_VALUE_MAP, false, false, ENCODING)).thenReturn(replacements); mojo.setRegexFlags(regexFlags); mojo.setRegex(REGEX); mojo.setTokenValueMap(TOKEN_VALUE_MAP); mojo.setFile(FILE); mojo.setOutputFile(OUTPUT_FILE); mojo.setBasedir(BASE_DIR); mojo.setCommentsEnabled(false); mojo.setEncoding(ENCODING); mojo.execute(); verify(processor).replace(replacements, REGEX, BASE_DIR + File.separator + FILE, OUTPUT_FILE, REGEX_PATTERN_FLAGS, ENCODING); } @Test public void shouldReplaceContentsWithTokenAndValueWithDelimiters() throws Exception { List<String> delimiters = asList("@", "${*}"); mojo.setRegexFlags(regexFlags); mojo.setRegex(REGEX); mojo.setFile(FILE); mojo.setToken(TOKEN); mojo.setValue(VALUE); mojo.setOutputFile(OUTPUT_FILE); mojo.setBasedir(BASE_DIR); mojo.setDelimiters(delimiters); mojo.execute(); assertThat(mojo.getDelimiters(), equalTo(delimiters)); verify(processor).replace(argThat(replacementOf(null, VALUE, false, "@" + TOKEN + "@", "${" + TOKEN + "}")), eq(REGEX), eq(BASE_DIR + File.separator + FILE), eq(OUTPUT_FILE), eq(REGEX_PATTERN_FLAGS), eq(NO_ENCODING_SET)); verify(summaryBuilder).add(BASE_DIR + File.separator + FILE, OUTPUT_FILE, NO_ENCODING_SET, log); verify(summaryBuilder).print(log); } @Test public void shouldReplaceContentsWithTokenAndValue() throws Exception { mojo.setRegexFlags(regexFlags); mojo.setRegex(REGEX); mojo.setFile(FILE); mojo.setToken(TOKEN); mojo.setValue(VALUE); mojo.setOutputFile(OUTPUT_FILE); mojo.setBasedir(BASE_DIR); mojo.setXpath(XPATH); mojo.execute(); verify(processor).replace(argThat(replacementOf(XPATH, VALUE, false, TOKEN)), eq(REGEX), eq(BASE_DIR + File.separator + FILE), eq(OUTPUT_FILE), eq(REGEX_PATTERN_FLAGS), eq(NO_ENCODING_SET)); verify(summaryBuilder).add(BASE_DIR + File.separator + FILE, OUTPUT_FILE, NO_ENCODING_SET, log); verify(summaryBuilder).print(log); } @Test public void shouldReplaceContentsWithTokenAndValueUnescaped() throws Exception { mojo.setRegexFlags(regexFlags); mojo.setRegex(REGEX); mojo.setFile(FILE); mojo.setToken(TOKEN); mojo.setValue(VALUE); mojo.setOutputFile(OUTPUT_FILE); mojo.setBasedir(BASE_DIR); mojo.setUnescape(true); mojo.execute(); assertTrue(mojo.isUnescape()); verify(processor).replace(argThat(replacementOf(null, VALUE, true, TOKEN)), eq(REGEX), eq(BASE_DIR + File.separator + FILE), eq(OUTPUT_FILE), eq(REGEX_PATTERN_FLAGS), eq(NO_ENCODING_SET)); verify(summaryBuilder).add(BASE_DIR + File.separator + FILE, OUTPUT_FILE, NO_ENCODING_SET, log); verify(summaryBuilder).print(log); } @Test public void shouldReplaceContentsWithTokenValuesInTokenAndValueFiles() throws Exception { when(fileUtils.readFile(TOKEN_FILE, ENCODING)).thenReturn(TOKEN); when(fileUtils.readFile(VALUE_FILE, ENCODING)).thenReturn(VALUE); mojo.setRegexFlags(regexFlags); mojo.setRegex(REGEX); mojo.setFile(FILE); mojo.setTokenFile(TOKEN_FILE); mojo.setValueFile(VALUE_FILE); mojo.setOutputFile(OUTPUT_FILE); mojo.setBasedir(BASE_DIR); mojo.setEncoding(ENCODING); mojo.execute(); verify(processor).replace(argThat(replacementOf(null, VALUE, false, TOKEN)), eq(REGEX), eq(BASE_DIR + File.separator + FILE), eq(OUTPUT_FILE), eq(REGEX_PATTERN_FLAGS), eq(ENCODING)); verify(fileUtils).readFile(TOKEN_FILE, ENCODING); verify(fileUtils).readFile(VALUE_FILE, ENCODING); verify(summaryBuilder).add(BASE_DIR + File.separator + FILE, OUTPUT_FILE, ENCODING, log); verify(summaryBuilder).print(log); } @Test public void shouldReplaceContentsInReplacementsInSameFileWhenNoOutputFile() throws Exception { Replacement replacement = mock(Replacement.class); List<Replacement> replacements = asList(replacement); mojo.setRegexFlags(regexFlags); mojo.setRegex(REGEX); mojo.setReplacements(replacements); mojo.setFile(FILE); mojo.setBasedir(BASE_DIR); mojo.execute(); verify(processor).replace(replacements, REGEX, BASE_DIR + File.separator + FILE, OUTPUT_FILE, REGEX_PATTERN_FLAGS, NO_ENCODING_SET); verify(summaryBuilder).add(BASE_DIR + File.separator + FILE, OUTPUT_FILE, NO_ENCODING_SET, log); verify(summaryBuilder).print(log); } @Test public void shouldReplaceContentsWithVariableTokenValueMap() throws Exception { Replacement replacement = mock(Replacement.class); List<Replacement> replacements = asList(replacement); when(tokenValueMapFactory.replacementsForVariable(TOKEN_VALUE_MAP, true, false, ENCODING)) .thenReturn(replacements); mojo.setVariableTokenValueMap(TOKEN_VALUE_MAP); mojo.setFile(FILE); mojo.setBasedir(BASE_DIR); mojo.setEncoding(ENCODING); mojo.execute(); assertThat(mojo.getVariableTokenValueMap(), equalTo(TOKEN_VALUE_MAP)); verify(processor).replace(replacements, true, BASE_DIR + File.separator + FILE, OUTPUT_FILE, 0, ENCODING); verify(summaryBuilder).add(BASE_DIR + File.separator + FILE, OUTPUT_FILE, ENCODING, log); verify(summaryBuilder).print(log); } @Test public void shouldNotReplaceIfIgnoringMissingFilesAndFileNotExists() throws Exception { when(fileUtils.fileNotExists(BASE_DIR + File.separator + FILE)).thenReturn(true); mojo.setFile(FILE); mojo.setBasedir(BASE_DIR); mojo.setIgnoreMissingFile(true); mojo.execute(); verifyZeroInteractions(replacerFactory); verify(log).info(anyString()); verify(summaryBuilder, never()).add(anyString(), anyString(), anyString(), isA(Log.class)); verify(summaryBuilder).print(log); } @Test public void shouldThrowExceptionWhenUsingIgnoreMissingFilesAndNoFileSpecified() throws Exception { mojo.setIgnoreMissingFile(true); try { mojo.execute(); fail("Should have thrown exception"); } catch (MojoExecutionException e) { verifyZeroInteractions(replacerFactory); verify(log, times(2)).error("<ignoreMissingFile> only useable with <file>"); verify(summaryBuilder, never()).add(anyString(), anyString(), anyString(), isA(Log.class)); verify(summaryBuilder).print(log); } } @Test public void shouldCreateNewInstancesOfDepenenciesOnConstructor() { new ReplacerMojo(); } @Test (expected = MojoExecutionException.class) public void shouldRethrowIOExceptionsAsMojoExceptions() throws Exception { when(fileUtils.readFile(anyString(), anyString())).thenThrow(new IOException()); mojo.setRegexFlags(regexFlags); mojo.setRegex(REGEX); mojo.setFile(FILE); mojo.setTokenFile(TOKEN_FILE); mojo.setValueFile(VALUE_FILE); mojo.setOutputFile(OUTPUT_FILE); mojo.setBasedir(BASE_DIR); mojo.execute(); } @Test public void shouldNotThrowExceptionWhenIgnoringErrors() throws Exception { when(fileUtils.readFile(anyString(), anyString())).thenThrow(new IOException()); mojo.setIgnoreErrors(true); mojo.setFile(FILE); mojo.setTokenFile(TOKEN_FILE); mojo.setValueFile(VALUE_FILE); mojo.setOutputFile(OUTPUT_FILE); mojo.execute(); } private BaseMatcher<List<Replacement>> replacementOf(final String xpath, final String value, final boolean unescape, final String... tokens) { return new BaseMatcher<List<Replacement>>() { @SuppressWarnings("unchecked") public boolean matches(Object arg0) { List<Replacement> replacements = (List<Replacement>) arg0; for (int i=0; i < tokens.length; i++) { Replacement replacement = replacements.get(i); EqualsBuilder equalsBuilder = new EqualsBuilder(); equalsBuilder.append(tokens[i], replacement.getToken()); equalsBuilder.append(value, replacement.getValue()); equalsBuilder.append(unescape, replacement.isUnescape()); equalsBuilder.append(xpath, replacement.getXpath()); boolean equals = equalsBuilder.isEquals(); if (!equals) { return false; } } return true; } public void describeTo(Description desc) { desc.appendText("tokens").appendValue(Arrays.asList(tokens)); desc.appendText("value").appendValue(value); desc.appendText("unescape").appendValue(unescape); } }; } }