From 9f1f7f666a6bd81bb6903c9e3f82072a18f0c60e Mon Sep 17 00:00:00 2001
From: Florian Angerer <florian.angerer@oracle.com>
Date: Wed, 21 Jun 2017 17:48:26 +0200
Subject: [PATCH] Added test for setBreakpoint; implemented test output filter
 "IgnoreDebugCallString"

---
 .../truffle/r/test/ExpectedTestOutput.test    | 31 +++++++++++-
 .../com/oracle/truffle/r/test/TestBase.java   | 48 ++++++++++++++++---
 .../library/utils/TestInteractiveDebug.java   | 22 +++++++++
 3 files changed, 92 insertions(+), 9 deletions(-)

diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
index 2b271d45b7..e6a226df83 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
@@ -131605,7 +131605,7 @@ NULL
 [external object]
 [1] 1 2 3
 
-##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testNamesForForeignObject#
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testNamesForForeignObject#Ignored.ImplementationError#
 #if (length(grep("FastR", R.Version()$version.string)) != 1) { NULL } else { cl <- .fastr.java.class('java.util.Collections'); em<-cl$EMPTY_MAP; names(em) }
 NULL
 
@@ -131629,7 +131629,7 @@ NULL
 #if (length(grep("FastR", R.Version()$version.string)) != 1) { c('field', 'method', 'staticField', 'staticMethod') } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestNamesClass'); t <- .fastr.interop.new(tc); sort(names(t)) }
 [1] "field"        "method"       "staticField"  "staticMethod"
 
-##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testNamesForForeignObject#
+##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testNamesForForeignObject#Ignored.ImplementationError#
 #if (length(grep("FastR", R.Version()$version.string)) != 1) { c('one', 'two') } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestNamesClassMap'); to <- .fastr.interop.new(tc); sort(names(to$m())) }
 [1] "one" "two"
 
@@ -145124,6 +145124,33 @@ debug at #1: cat(x)
 
 exiting from: fun(3)
 
+##com.oracle.truffle.r.test.library.utils.TestInteractiveDebug.testSetBreakpoint#Output.IgnoreDebugCallString#Output.IgnoreDebugPath#
+#source('tmptest/com.oracle.truffle.r.test.library.utils.rsrc/debug.r'); setBreakpoint('tmptest/com.oracle.truffle.r.test.library.utils.rsrc/debug.r', 4, verbose=F); fun(10)<<<NEWLINE>>><<<NEWLINE>>><<<NEWLINE>>><<<NEWLINE>>><<<NEWLINE>>><<<NEWLINE>>><<<NEWLINE>>><<<NEWLINE>>>
+debug.r#4
+Called from: fun(10)
+debug: print("Hello")
+[1] "Hello"
+debug at tmptest/com.oracle.truffle.r.test.library.utils.rsrc/debug.r#5: for (i in seq(3)) print(i)
+debug at tmptest/com.oracle.truffle.r.test.library.utils.rsrc/debug.r#5: print(i)
+[1] 1
+debug at tmptest/com.oracle.truffle.r.test.library.utils.rsrc/debug.r#5: print(i)
+[1] 2
+debug at tmptest/com.oracle.truffle.r.test.library.utils.rsrc/debug.r#5: print(i)
+[1] 3
+debug at tmptest/com.oracle.truffle.r.test.library.utils.rsrc/debug.r#6: bar("World")
+[1] "World"
+debug at tmptest/com.oracle.truffle.r.test.library.utils.rsrc/debug.r#7: print(x)
+[1] 10
+
+##com.oracle.truffle.r.test.library.utils.TestInteractiveDebug.testSetBreakpoint#
+#source('tmptest/com.oracle.truffle.r.test.library.utils.rsrc/debug.r'); setBreakpoint('tmptest/com.oracle.truffle.r.test.library.utils.rsrc/debug.r', 4, verbose=F); setBreakpoint('tmptest/com.oracle.truffle.r.test.library.utils.rsrc/debug.r', 4, verbose=F, clear=T); fun(10)<<<NEWLINE>>>
+[1] "Hello"
+[1] 1
+[1] 2
+[1] 3
+[1] "World"
+[1] 10
+
 ##com.oracle.truffle.r.test.library.utils.TestInteractiveDebug.testSimple#
 #f <- function(x) {<<<NEWLINE>>>  t <- x + 1<<<NEWLINE>>>  print(t)<<<NEWLINE>>>  t}<<<NEWLINE>>>debug(f)<<<NEWLINE>>>f(5)<<<NEWLINE>>>x<<<NEWLINE>>>n<<<NEWLINE>>>n<<<NEWLINE>>>t<<<NEWLINE>>>n<<<NEWLINE>>>n
 debugging in: f(5)
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestBase.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestBase.java
index 461c8efddb..1282949d21 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestBase.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestBase.java
@@ -12,8 +12,10 @@ package com.oracle.truffle.r.test;
 
 import static org.junit.Assert.fail;
 
+import java.io.BufferedReader;
 import java.io.File;
 import java.io.IOException;
+import java.io.StringReader;
 import java.net.URL;
 import java.nio.file.FileVisitResult;
 import java.nio.file.Files;
@@ -29,6 +31,7 @@ import java.util.Map.Entry;
 import java.util.SortedMap;
 import java.util.TreeMap;
 import java.util.TreeSet;
+import java.util.function.Predicate;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -92,7 +95,8 @@ public class TestBase {
         IgnoreWhitespace, // removes all whitespace from the whole output
         IgnoreCase, // ignores upper/lower case differences
         IgnoreDebugPath, // ignores <path> in debug output like "debug at <path> #..."
-        IgnoreDebugDepth; // ignores call depth printed by the debugger ("Browse[<call depth>]")
+        IgnoreDebugDepth, // ignores call depth printed by the debugger ("Browse[<call depth>]")
+        IgnoreDebugCallString; // ignores the caller string like "debugging in:" or "Called from:"
 
         @Override
         public String getName() {
@@ -596,22 +600,26 @@ public class TestBase {
         }
 
         String preprocessOutput(String out) {
+            String s = out;
             if (output.contains(Output.IgnoreWhitespace)) {
-                return out.replaceAll("\\s+", "");
+                return s.replaceAll("\\s+", "");
             }
             if (output.contains(Output.IgnoreCase)) {
-                return out.toLowerCase();
+                return s.toLowerCase();
             }
             if (output.contains(Output.ContainsReferences)) {
-                return convertReferencesInOutput(out);
+                return convertReferencesInOutput(s);
             }
             if (output.contains(Output.IgnoreDebugPath)) {
-                return convertDebugOutput(out);
+                s = convertDebugOutput(s);
             }
             if (output.contains(Output.IgnoreDebugDepth)) {
-                return removeDebugCallDepth(out);
+                s = removeDebugCallDepth(s);
             }
-            return out;
+            if (output.contains(Output.IgnoreDebugCallString)) {
+                s = removeDebugCallString(s);
+            }
+            return s;
         }
     }
 
@@ -802,6 +810,10 @@ public class TestBase {
         return removeAllOccurrencesBetween(out, prefix, prefix.length(), "]", 0);
     }
 
+    private static String removeDebugCallString(String out) {
+        return removeLines(out, line -> line.startsWith("debugging in:") || line.startsWith("Called from:"));
+    }
+
     private static String removeAllOccurrencesBetween(String out, String prefix, int prefixOffset, String suffix, int suffixOffset) {
         StringBuilder sb = new StringBuilder(out);
 
@@ -815,6 +827,28 @@ public class TestBase {
         return sb.toString();
     }
 
+    /**
+     * Removes the lines from the test output string matching the provided predicate.
+     */
+    private static String removeLines(String out, Predicate<String> pred) {
+        StringBuilder sb = new StringBuilder();
+
+        BufferedReader r = new BufferedReader(new StringReader(out));
+        String line;
+        try {
+            while ((line = r.readLine()) != null) {
+                if (!pred.test(line)) {
+                    sb.append(line);
+                    sb.append(System.lineSeparator());
+                }
+            }
+        } catch (IOException e) {
+            // won't happen
+        }
+
+        return sb.toString();
+    }
+
     private boolean searchWhiteLists(WhiteList[] whiteLists, String input, String expected, String result, TestTraitsSet testTraits) {
         if (whiteLists == null) {
             return false;
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/utils/TestInteractiveDebug.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/utils/TestInteractiveDebug.java
index d6ae8bf0c9..c9b996f590 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/utils/TestInteractiveDebug.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/utils/TestInteractiveDebug.java
@@ -22,6 +22,12 @@
  */
 package com.oracle.truffle.r.test.library.utils;
 
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+
+import org.junit.BeforeClass;
 import org.junit.Test;
 
 import com.oracle.truffle.r.test.TestBase;
@@ -96,4 +102,20 @@ public class TestInteractiveDebug extends TestBase {
         assertEval("browser()\nwhere\nc\n");
         assertEval("options(error=browser); prod('a')\nwhere\nc\n");
     }
+
+    private static Path debugFile;
+
+    @BeforeClass
+    public static void setup() throws IOException {
+        Path testDir = TestBase.createTestDir("com.oracle.truffle.r.test.library.utils.rsrc");
+        String content = "bar <- function(x) print(x)\n\nfun <- function(x) {\nprint('Hello')\nfor(i in seq(3)) print(i)\nbar('World')\nprint(x)\n}";
+        debugFile = testDir.resolve("debug.r");
+        Files.write(debugFile, content.getBytes(), StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
+    }
+
+    @Test
+    public void testSetBreakpoint() {
+        assertEval(Output.IgnoreDebugCallString, Output.IgnoreDebugPath, String.format("source('%s'); setBreakpoint('%s', 4, verbose=F); fun(10)\n\n\n\n\n\n\n\n", debugFile, debugFile));
+        assertEval(String.format("source('%s'); setBreakpoint('%s', 4, verbose=F); setBreakpoint('%s', 4, verbose=F, clear=T); fun(10)\n", debugFile, debugFile, debugFile));
+    }
 }
-- 
GitLab