Relaxing no-streams presubmit check (streams are allowed in tests).

It is actually fine to use streams in testonly code. This CL relaxes
the presubmit check in order allow streams usage in tests.

Bug: webrtc:8982
Change-Id: I18bbf079e804815956cd94ac761cc13022c0761e
No-Try: True
Reviewed-on: https://webrtc-review.googlesource.com/61701
Commit-Queue: Mirko Bonadei <mbonadei@webrtc.org>
Reviewed-by: Patrik Höglund <phoglund@webrtc.org>
Reviewed-by: Sebastian Jansson <srte@webrtc.org>
Reviewed-by: Tomas Gunnarsson <tommi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#22482}
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index e533507..96cdbf1 100755
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -410,6 +410,10 @@
 def CheckNoStreamUsageIsAdded(input_api, output_api,
                               error_formatter=_ReportErrorFileAndLineNumber):
   """Make sure that no more dependencies on stringstream are added."""
+  with _AddToPath(input_api.os_path.join(
+      input_api.PresubmitLocalPath(), 'tools_webrtc', 'presubmit_checks_lib')):
+    from gn_refs import DefaultGnProject, BelongsToTestTarget
+
   error_msg = ('Usage of <sstream>, <istream> and <ostream> in WebRTC is '
                'deprecated.\n'
                'This includes the following types:\n'
@@ -433,13 +437,15 @@
   usage_re = input_api.re.compile(r'std::(w|i|o|io|wi|wo|wio)(string)*stream')
   no_presubmit_re = input_api.re.compile(
       r'  // no-presubmit-check TODO\(webrtc:8982\)')
-  for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
-    if f.LocalPath() == 'PRESUBMIT.py':
-      continue
-    for line_num, line in f.ChangedContents():
-      if ((include_re.search(line) or usage_re.search(line))
-          and not no_presubmit_re.search(line)):
-        errors.append(error_formatter(f.LocalPath(), line_num))
+  is_cpp_file = lambda f: f.LocalPath().endswith(('.cc', '.h'))
+  with DefaultGnProject() as out_dir:
+    for f in input_api.AffectedFiles(file_filter=is_cpp_file):
+      if BelongsToTestTarget(f.LocalPath(), out_dir):
+        continue
+      for line_num, line in f.ChangedContents():
+        if ((include_re.search(line) or usage_re.search(line))
+            and not no_presubmit_re.search(line)):
+          errors.append(error_formatter(f.LocalPath(), line_num))
   if errors:
     return [output_api.PresubmitError(error_msg, errors)]
   return []
diff --git a/tools_webrtc/presubmit_checks_lib/gn_refs.py b/tools_webrtc/presubmit_checks_lib/gn_refs.py
new file mode 100644
index 0000000..3f062eb
--- /dev/null
+++ b/tools_webrtc/presubmit_checks_lib/gn_refs.py
@@ -0,0 +1,70 @@
+# Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS.  All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+
+import os
+import shutil
+import subprocess
+import sys
+import tempfile
+from contextlib import contextmanager
+
+
+# The module find_depot_tools lives into the ./build directory.
+SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
+SRC_DIR = os.path.normpath(os.path.join(SCRIPT_DIR, os.pardir, os.pardir))
+sys.path.append(os.path.join(SRC_DIR, 'build'))
+import find_depot_tools
+
+
+@contextmanager
+def DefaultGnProject():
+  """Generates a GN projects with defaul args and returns the path to it."""
+  out_dir = tempfile.mkdtemp('gn')
+  gen_command = [
+    sys.executable,
+    os.path.join(find_depot_tools.DEPOT_TOOLS_PATH, 'gn.py'),
+    'gen',
+    out_dir,
+  ]
+  subprocess.check_output(gen_command)
+  try:
+    yield out_dir
+  finally:
+    shutil.rmtree(out_dir, ignore_errors=True)
+
+
+def BelongsToTestTarget(file_path, out_dir):
+  """Returns True if file_path is part of a testonly build target.
+
+  This function relies on 'gn refs'. It actually runs:
+  $ gn refs <out_dir> file_path --testonly=true`
+
+  Which returns a list of build targets containing file_path (well, only
+  one build target should own a file, but that is not a strict rule).
+
+  If the list is empty, it means the file is owned by a non-testonly build
+  target and the function will return False. Otherwise it will return True.
+
+  Args:
+    file_path: string with the local path of the file to analyze.
+    out_dir: the path to the GN out directory to analyze.
+
+  Returns:
+    boolean: True if the file belongs to a testonly build target.
+  """
+  refs_command = [
+    sys.executable,
+    os.path.join(find_depot_tools.DEPOT_TOOLS_PATH, 'gn.py'),
+    'refs',
+    out_dir,
+    file_path,
+    '--testonly=true'
+  ]
+  output = subprocess.check_output(refs_command)
+  # If file_path belongs to a test target, output will contain a list of them.
+  return output != ''