Fix WebBluetooth generator to distinguish between different methods.

This change allows tests to be created that exercise both
characteristic.readValue/writeValue and descriptor.readValue/writeValue.
script-tests's name determine what feature they are testing.  For example, a
test that wants to tests gatt operations on a descriptor can be named:

bluetooth/script-tests/descriptor/<>

then in bluetooth/descriptor/<>/ each of the gatt calls will be generated.

In addition and prep for this change, we are moving files around.  The
structure now is the following:

device
    gattserverdisconnected-event

service
   getCharacteristic
   getCharacteristics

server
    getPrimaryService
    getPrimaryServices
    connect
    disconnect

characterisitic
   startNotifications
   stopNotifications
   readValue
   writeValue
   getDescriptor
   getDescriptors
   notifications

BUG=668836
R=ortuno

Review-Url: https://codereview.chromium.org/2544513004
Cr-Commit-Position: refs/heads/master@{#436173}
diff --git a/third_party/WebKit/LayoutTests/bluetooth/generate.py b/third_party/WebKit/LayoutTests/bluetooth/generate.py
index bf13888a..127d3e4 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/generate.py
+++ b/third_party/WebKit/LayoutTests/bluetooth/generate.py
@@ -24,34 +24,33 @@
 
 // script-tests/example.js
 promise_test(() => {
-  return navigator.bluetooth.requestDevice(...)
-    .then(device => device.gatt.CALLS([
-      getPrimaryService('heart_rate')|
-      getPrimaryServices('heart_rate')[UUID]]))
-    .then(device => device.gatt.PREVIOUS_CALL);
+    return navigator.bluetooth.requestDevice(...)
+        .then(device => device.gatt.CALLS([
+            getPrimaryService('heart_rate')|
+            getPrimaryServices('heart_rate')[UUID]]))
+        .then(device => device.gatt.PREVIOUS_CALL);
 }, 'example test for FUNCTION_NAME');
 
 this script will generate:
 
 // getPrimaryService/example.html
 promise_test(() => {
-  return navigator.bluetooth.requestDevice(...)
-    .then(device => device.gatt.getPrimaryService('heart_rate'))
-    .then(device => device.gatt.getPrimaryService('heart_rate'));
+    return navigator.bluetooth.requestDevice(...)
+        .then(device => device.gatt.getPrimaryService('heart_rate'))
+        .then(device => device.gatt.getPrimaryService('heart_rate'));
 }, 'example test for getPrimaryService');
 
 // getPrimaryServices/example-with-uuid.html
 promise_test(() => {
-  return navigator.bluetooth.requestDevice(...)
-    .then(device => device.gatt.getPrimaryServices('heart_rate'))
-    .then(device => device.gatt.getPrimaryServices('heart_rate'));
+    return navigator.bluetooth.requestDevice(...)
+        .then(device => device.gatt.getPrimaryServices('heart_rate'))
+        .then(device => device.gatt.getPrimaryServices('heart_rate'));
 }, 'example test for getPrimaryServices');
 
 Run
 $ python //third_party/WebKit/LayoutTests/bluetooth/generate.py
 and commit the generated files.
 """
-import glob
 import os
 import re
 import sys
@@ -61,87 +60,89 @@
 
 class GeneratedTest:
 
-  def __init__(self, data, path, template):
-    self.data = data
-    self.path = path
-    self.template = template
+    def __init__(self, data, path, template):
+        self.data = data
+        self.path = path
+        self.template = template
 
 
 def GetGeneratedTests():
-  """Yields a GeneratedTest for each call in templates in script-tests."""
-  current_path = os.path.dirname(os.path.realpath(__file__))
+    """Yields a GeneratedTest for each call in templates in script-tests."""
+    bluetooth_tests_dir = os.path.dirname(os.path.realpath(__file__))
 
-  # Read Base Test Template.
-  base_template_file_handle = open(
-      os.path.join(current_path, TEMPLATES_DIR, 'base_test_template.html'))
-  base_template_file_data = base_template_file_handle.read().decode('utf-8')
-  base_template_file_handle.close()
+    # Read Base Test Template.
+    base_template_file_handle = open(
+        os.path.join(bluetooth_tests_dir, TEMPLATES_DIR, 'base_test_template.html'))
+    base_template_file_data = base_template_file_handle.read().decode('utf-8')
+    base_template_file_handle.close()
 
-  # Get Templates.
-  available_templates = glob.glob(
-      os.path.join(current_path, TEMPLATES_DIR, '*.js'))
+    # Get Templates.
 
-  # Generate Test Files
-  for template in available_templates:
-    # Read template
-    template_file_handle = open(template)
-    template_file_data = template_file_handle.read().decode('utf-8')
-    template_file_handle.close()
+    template_path = os.path.join(bluetooth_tests_dir, TEMPLATES_DIR)
 
-    template_name = os.path.splitext(os.path.basename(template))[0]
+    available_templates = []
+    for root, _, files in os.walk(template_path):
+        for template in files:
+            if template.endswith('.js'):
+                available_templates.append(os.path.join(root, template))
 
-    result = re.search(r'CALLS\(\[(.*?)\]\)', template_file_data, re.MULTILINE
-                       | re.DOTALL)
+    # Generate Test Files
+    for template in available_templates:
+        # Read template
+        template_file_handle = open(template)
+        template_file_data = template_file_handle.read().decode('utf-8')
+        template_file_handle.close()
 
-    if result is None:
-      raise Exception('Template must contain \'CALLS\' tokens')
+        template_name = os.path.splitext(os.path.basename(template))[0]
 
-    new_test_file_data = base_template_file_data.replace('TEST',
-                                                         template_file_data)
-    # Replace CALLS([...]) with CALLS so that we don't have to replace the
-    # CALLS([...]) for every new test file.
-    new_test_file_data = new_test_file_data.replace(result.group(), 'CALLS')
+        result = re.search(r'CALLS\(\[(.*?)\]\)', template_file_data, re.MULTILINE
+            | re.DOTALL)
 
-    # Replace 'PREVIOUS_CALL' with 'CALLS' so that we can replace it while
-    # replacing CALLS.
-    new_test_file_data = new_test_file_data.replace('PREVIOUS_CALL', 'CALLS')
+        if result is None:
+            raise Exception('Template must contain \'CALLS\' tokens')
 
-    calls = result.group(1)
-    calls = ''.join(calls.split())  # Removes whitespace.
-    calls = calls.split('|')
+        new_test_file_data = base_template_file_data.replace('TEST',
+            template_file_data)
+        # Replace CALLS([...]) with CALLS so that we don't have to replace the
+        # CALLS([...]) for every new test file.
+        new_test_file_data = new_test_file_data.replace(result.group(), 'CALLS')
 
-    for call in calls:
-      # Parse call
-      name, args, uuid_suffix = re.search(r'(.*?)\((.*?)\)(\[UUID\])?',
-                                          call).groups()
+        # Replace 'PREVIOUS_CALL' with 'CALLS' so that we can replace it while
+        # replacing CALLS.
+        new_test_file_data = new_test_file_data.replace('PREVIOUS_CALL', 'CALLS')
 
-      # Replace template tokens
-      call_test_file_data = new_test_file_data
+        calls = result.group(1)
+        calls = ''.join(calls.split())    # Removes whitespace.
+        calls = calls.split('|')
 
-      call_test_file_data = call_test_file_data.replace(
-          'CALLS', '{}({})'.format(name, args))
+        for call in calls:
+            # Parse call
+            function_name, args, uuid_suffix = re.search(r'(.*?)\((.*?)\)(\[UUID\])?', call).groups()
 
-      call_test_file_data = call_test_file_data.replace('FUNCTION_NAME', name)
+            # Replace template tokens
+            call_test_file_data = new_test_file_data
+            call_test_file_data = call_test_file_data.replace('CALLS', '{}({})'.format(function_name, args))
+            call_test_file_data = call_test_file_data.replace('FUNCTION_NAME', function_name)
 
-      # Get test file name
-      call_test_file_name = 'gen-{}{}.html'.format(template_name, '-with-uuid'
-                                                   if uuid_suffix else '')
-      call_test_file_path = os.path.join(current_path, name,
-                                         call_test_file_name)
+            # Get test file name
+            group_dir = os.path.basename(os.path.abspath(os.path.join(template, os.pardir)))
 
-      yield GeneratedTest(call_test_file_data, call_test_file_path, template)
+            call_test_file_name = 'gen-{}{}.html'.format(template_name, '-with-uuid' if uuid_suffix else '')
+            call_test_file_path = os.path.join(bluetooth_tests_dir, group_dir, function_name, call_test_file_name)
+
+            yield GeneratedTest(call_test_file_data, call_test_file_path, template)
 
 
 def main():
 
-  for generated_test in GetGeneratedTests():
-    # Create or open test file
-    test_file_handle = open(generated_test.path, 'wb')
+    for generated_test in GetGeneratedTests():
+        # Create or open test file
+        test_file_handle = open(generated_test.path, 'wb')
 
-    # Write contents
-    test_file_handle.write(generated_test.data.encode('utf-8'))
-    test_file_handle.close()
+        # Write contents
+        test_file_handle.write(generated_test.data.encode('utf-8'))
+        test_file_handle.close()
 
 
 if __name__ == '__main__':
-  sys.exit(main())
+    sys.exit(main())