Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@
<localInspection implementationClass="cz.jiripudil.intellij.nette.tester.inspections.TestFileNameInspection" groupName="Nette Tester" displayName="Test case files have correct names" enabledByDefault="true" level="ERROR"/>
<localInspection implementationClass="cz.jiripudil.intellij.nette.tester.inspections.TestCaseAnnotationInspection" groupName="Nette Tester" displayName="Test case has @testCase annotation" enabledByDefault="true" level="WARNING"/>
<localInspection implementationClass="cz.jiripudil.intellij.nette.tester.inspections.TestCaseIsRunInspection" groupName="Nette Tester" displayName="Test case is run" enabledByDefault="true" level="ERROR"/>

<consoleInputFilterProvider implementation="cz.jiripudil.intellij.nette.tester.console.InputFilterProvider"/>
<consoleFilterProvider implementation="cz.jiripudil.intellij.nette.tester.console.FilterProvider"/>
</extensions>

<actions>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package cz.jiripudil.intellij.nette.tester.console;

import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.Nullable;

import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class ActualExpectedPathDetector {
/**
* @see <a href="https://github.com/nette/tester/blob/c126385e/src/Framework/Dumper.php#L307">diff line</a>
* @see <a href="https://github.com/nette/tester/blob/c126385e/src/Framework/Helpers.php#L82">argument escaping</a>
*/
private final static Pattern DIFF_LINE_REGEX;

static {
String unixArg = "'(?:[^']|'\\\\'')+'";
String winArg = "\"[^\"]+\"";
String unquotedArg = "[a-z0-9._=/:-]+";
String arg = "(" + unixArg + "|" + winArg + "|" + unquotedArg + ")";
DIFF_LINE_REGEX = Pattern.compile("^diff " + arg + " " + arg + "$");
}

@Nullable
public static Pair<String, String> detectPaths(final String diffLine) {
Matcher matcher = DIFF_LINE_REGEX.matcher(diffLine);
if (matcher.find()) {
return Pair.create(unquoteArg(matcher.group(1)), unquoteArg(matcher.group(2)));
}
return null;
}

private static String unquoteArg(String arg) {
if (arg.startsWith("'")) {
return StringUtil.unquoteString(arg).replace("'\\''", "'");
}

if (arg.startsWith("\"")) {
return StringUtil.unquoteString(arg);
}

return arg;
}
}
18 changes: 18 additions & 0 deletions src/cz/jiripudil/intellij/nette/tester/console/FilterProvider.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package cz.jiripudil.intellij.nette.tester.console;

import com.intellij.execution.filters.ConsoleFilterProvider;
import com.intellij.execution.filters.Filter;
import com.intellij.openapi.project.Project;
import cz.jiripudil.intellij.nette.tester.console.filters.MakeDiffLinkTextClickableFilter;
import org.jetbrains.annotations.NotNull;


public class FilterProvider implements ConsoleFilterProvider {
@NotNull
@Override
public Filter[] getDefaultFilters(@NotNull Project project) {
return new Filter[]{
new MakeDiffLinkTextClickableFilter(),
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package cz.jiripudil.intellij.nette.tester.console;

import com.intellij.execution.filters.ConsoleInputFilterProvider;
import com.intellij.execution.filters.InputFilter;
import com.intellij.openapi.project.Project;
import cz.jiripudil.intellij.nette.tester.console.filters.InsertDiffLinkTextInputFilter;
import org.jetbrains.annotations.NotNull;


public class InputFilterProvider implements ConsoleInputFilterProvider {
@NotNull
@Override
public InputFilter[] getDefaultFilters(@NotNull Project project) {
return new InputFilter[]{
new InsertDiffLinkTextInputFilter(),
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package cz.jiripudil.intellij.nette.tester.console.filters;

import com.intellij.execution.ExecutionBundle;
import com.intellij.execution.filters.InputFilter;
import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.openapi.util.Pair;
import cz.jiripudil.intellij.nette.tester.console.ActualExpectedPathDetector;
import org.jetbrains.annotations.Nullable;

import java.util.Collections;
import java.util.List;

/**
* Adds text {@link InsertDiffLinkTextInputFilter#DIFF_LINK_TEXT} after a line with
* diff shell command (see: {@link ActualExpectedPathDetector#DIFF_LINE_REGEX}).
*/
public class InsertDiffLinkTextInputFilter implements InputFilter {
final static String DIFF_LINK_TEXT = ExecutionBundle.message("junit.click.to.see.diff.link");

@Nullable
@Override
public List<Pair<String, ConsoleViewContentType>> applyFilter(String text, ConsoleViewContentType contentType) {
if (ActualExpectedPathDetector.detectPaths(text) != null) {
return Collections.singletonList(Pair.create(text + DIFF_LINK_TEXT + "\n", contentType));
}
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package cz.jiripudil.intellij.nette.tester.console.filters;

import com.intellij.execution.filters.Filter;
import com.intellij.execution.filters.HyperlinkInfo;
import com.intellij.execution.testframework.stacktrace.DiffHyperlink;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.FileUtil;
import cz.jiripudil.intellij.nette.tester.console.ActualExpectedPathDetector;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.File;
import java.io.IOException;

/**
* Catches text {@link InsertDiffLinkTextInputFilter#DIFF_LINK_TEXT} and makes
* it clickable if previous line contains diff shell command (see: {@link ActualExpectedPathDetector#DIFF_LINE_REGEX}).
*/
public class MakeDiffLinkTextClickableFilter implements Filter {
private String expectedPath;
private String actualPath;

@Nullable
@Override
public Result applyFilter(String line, int endPoint) {
if (line.equals(InsertDiffLinkTextInputFilter.DIFF_LINK_TEXT + "\n")) {
if (expectedPath != null && actualPath != null) {
Result result = new Result(endPoint - line.length(), endPoint, new LazyDiffHyperlinkInfo(expectedPath, actualPath));
expectedPath = actualPath = null;
return result;
}
return null;
}

Pair<String, String> paths = ActualExpectedPathDetector.detectPaths(line);
if (paths != null) {
expectedPath = paths.first;
actualPath = paths.second;
}

return null;
}

private static class LazyDiffHyperlinkInfo implements HyperlinkInfo {
private String expectedPath;
private String actualPath;
private DiffHyperlink.DiffHyperlinkInfo link;

LazyDiffHyperlinkInfo(@NotNull String expectedPath, @NotNull String actualPath) {
this.expectedPath = expectedPath;
this.actualPath = actualPath;
}

@Override
public void navigate(Project project) {
if (link == null) {
String expected, actual;
try {
expected = FileUtil.loadFile(new File(expectedPath));
actual = FileUtil.loadFile(new File(actualPath));
} catch (IOException e) {
return;
}
link = new DiffHyperlink(expected, actual, expectedPath, actualPath, false).new DiffHyperlinkInfo();
}

link.navigate(project);
}
}
}
33 changes: 33 additions & 0 deletions test/diff-link-integration-test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

// Taken from Tester\Helpers
function escapeArg($s) {
if (preg_match('#^[a-z0-9._=/:-]+\z#i', $s)) {
return $s;
}
return defined('PHP_WINDOWS_VERSION_BUILD')
? '"' . str_replace('"', '""', $s) . '"'
: escapeshellarg($s);
}

$tmpDir = sys_get_temp_dir() . '/intellij-nette-tester';
@mkdir($tmpDir);
array_map('unlink', glob("$tmpDir/*"));

$fileNames = [
'foo-bar',
'foo bar baz',
'foo\' bar',
'foo" bar',
'foo \'bar\' baz"',
'foo "bar" baz',
];

foreach ($fileNames as $name) {
$expected = $tmpDir . '/' . $name . '.expected';
$actual = $tmpDir . '/' . $name . '.actual';
if (!@file_put_contents($expected, 'foo expected') || !@file_put_contents($actual, 'foo actual')) {
echo "Can not create: $name\n\n"; // char " is not allowed as filename in Windows
}
echo 'diff ' . escapeArg($expected ) . ' ' . escapeArg($actual) . "\n\n";
}