Kirill Simonov avatar Kirill Simonov committed a86003d

Updated scan error messages.

Comments (0)

Files changed (13)

src/htsql/tr/error.py

 """
 
 
+from ..util import maybe
 from ..error import BadRequestError
 from ..mark import Mark
 
     Represents a translation error.
     """
 
-    def __init__(self, detail, mark):
+    def __init__(self, detail, mark, hint=None):
         assert isinstance(mark, Mark)
+        assert isinstance(hint, maybe(str))
         super(TranslateError, self).__init__(detail)
         self.mark = mark
+        self.hint = hint
 
     def __str__(self):
         lines = self.mark.excerpt()
         mark_detail = "\n".join("    "+line.encode('utf-8') for line in lines)
-        return "%s: %s:\n%s" % (self.kind, self.detail, mark_detail)
+        return "%s: %s:\n%s%s" % (self.kind, self.detail, mark_detail,
+                                  "\n(%s)" % self.hint
+                                    if self.hint is not None else "")
 
 
 class ScanError(TranslateError):

src/htsql/tr/scan.py

 from ..mark import Mark
 from ..util import maybe, listof
 import re
+import urllib2
 
 
 class TokenStream(object):
                 start = len(match.string[:start].decode('utf-8', 'ignore'))
                 end = len(match.string[:end].decode('utf-8', 'ignore'))
                 mark = Mark(input, start, end)
-                raise ScanError("invalid escape sequence", mark)
+                raise ScanError("expected two hexdecimal digits to follow"
+                                " symbol '%s'", mark)
             # Return the character corresponding to the escape sequence.
             return chr(int(code, 16))
 
             start = len(input[:exc.start].decode('utf-8', 'ignore'))
             end = len(input[:exc.end].decode('utf-8', 'ignore'))
             mark = Mark(input.decode('utf-8', 'replace'), start, end)
-            raise ScanError("cannot decode an UTF-8 character: %s"
-                            % exc.reason, mark)
+            raise ScanError("cannot convert a byte sequence %s to UTF-8: %s"
+                            % (urllib2.quote(exc.object[exc.start:exc.end]),
+                               exc.reason), mark)
 
         # The beginning of the next token (and the start of the mark slice).
         start = 0
             match = self.regexp.match(input, start)
             if match is None:
                 mark = Mark(input, start, start+1)
-                raise ScanError("unexpected character %r"
-                                % input[start].encode('utf-8'), mark)
+                # FIXME: generalize?
+                if input[start] == u"'":
+                    raise ScanError("cannot find a matching quote mark", mark)
+                else:
+                    raise ScanError("unexpected symbol %r"
+                                    % input[start].encode('utf-8'), mark)
 
             # Find the token class that matched the token.
             for token_class in self.tokens:

test/input/error.yaml

+#
+# Copyright (c) 2006-2011, Prometheus Research, LLC
+# See `LICENSE` for license information, `AUTHORS` for the list of authors.
+#
+
+title: Error Reporting
+id: error
+tests:
+
+- title: Scan Errors
+  tests:
+  - uri: /'?%@$'
+    expect: 400
+  - uri: /'%FF'
+    expect: 400
+  - uri: /'Hello
+    expect: 400
+  - uri: /`Hello'
+    expect: 400
+
+

test/input/mssql.yaml

   - include: test/input/format.yaml
   # Extensions
   - include: test/input/addon.yaml
+  # Error Reporting
+  - include: test/input/error.yaml
 

test/input/mysql.yaml

   - include: test/input/format.yaml
   # Extensions
   - include: test/input/addon.yaml
+  # Error Reporting
+  - include: test/input/error.yaml
 

test/input/oracle.yaml

   - include: test/input/format.yaml
   # Extensions
   - include: test/input/addon.yaml
+  # Error Reporting
+  - include: test/input/error.yaml
 

test/input/pgsql.yaml

   - include: test/input/format.yaml
   # Extensions
   - include: test/input/addon.yaml
+  # Error Reporting
+  - include: test/input/error.yaml
 

test/input/sqlite.yaml

   - include: test/input/format.yaml
   # Extensions
   - include: test/input/addon.yaml
+  # Error Reporting
+  - include: test/input/error.yaml
 

test/output/mssql.yaml

              ORDER BY [addresses].[id] ASC
         - py: remove-module-path
           stdout: ''
+  - include: test/input/error.yaml
+    output:
+      id: error
+      tests:
+      - id: scan-errors
+        tests:
+        - uri: /'?%@$'
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            scan error: expected two hexdecimal digits to follow symbol '%s':
+                /%27?%@$'
+                     ^
+        - uri: /'%FF'
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: "scan error: cannot convert a byte sequence %FF to UTF-8: invalid
+            start byte:\n    /'\uFFFD'\n      ^\n"
+        - uri: /'Hello
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            scan error: cannot find a matching quote mark:
+                /'Hello
+                 ^
+        - uri: /`Hello'
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            scan error: unexpected symbol '`':
+                /`Hello'
+                 ^

test/output/mysql.yaml

              ORDER BY `addresses`.`id` ASC
         - py: remove-module-path
           stdout: ''
+  - include: test/input/error.yaml
+    output:
+      id: error
+      tests:
+      - id: scan-errors
+        tests:
+        - uri: /'?%@$'
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            scan error: expected two hexdecimal digits to follow symbol '%s':
+                /%27?%@$'
+                     ^
+        - uri: /'%FF'
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: "scan error: cannot convert a byte sequence %FF to UTF-8: invalid
+            start byte:\n    /'\uFFFD'\n      ^\n"
+        - uri: /'Hello
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            scan error: cannot find a matching quote mark:
+                /'Hello
+                 ^
+        - uri: /`Hello'
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            scan error: unexpected symbol '`':
+                /`Hello'
+                 ^

test/output/oracle.yaml

              ORDER BY "ADDRESSES"."ID" ASC
         - py: remove-module-path
           stdout: ''
+  - include: test/input/error.yaml
+    output:
+      id: error
+      tests:
+      - id: scan-errors
+        tests:
+        - uri: /'?%@$'
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            scan error: expected two hexdecimal digits to follow symbol '%s':
+                /%27?%@$'
+                     ^
+        - uri: /'%FF'
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: "scan error: cannot convert a byte sequence %FF to UTF-8: invalid
+            start byte:\n    /'\uFFFD'\n      ^\n"
+        - uri: /'Hello
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            scan error: cannot find a matching quote mark:
+                /'Hello
+                 ^
+        - uri: /`Hello'
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            scan error: unexpected symbol '`':
+                /`Hello'
+                 ^

test/output/pgsql.yaml

           body: |+
             engine failure: failed to execute a database query: canceling statement due to statement timeout
 
+  - include: test/input/error.yaml
+    output:
+      id: error
+      tests:
+      - id: scan-errors
+        tests:
+        - uri: /'?%@$'
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            scan error: expected two hexdecimal digits to follow symbol '%s':
+                /%27?%@$'
+                     ^
+        - uri: /'%FF'
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: "scan error: cannot convert a byte sequence %FF to UTF-8: invalid
+            start byte:\n    /'\uFFFD'\n      ^\n"
+        - uri: /'Hello
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            scan error: cannot find a matching quote mark:
+                /'Hello
+                 ^
+        - uri: /`Hello'
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            scan error: unexpected symbol '`':
+                /`Hello'
+                 ^

test/output/sqlite.yaml

              ORDER BY "addresses"."id" ASC
         - py: remove-module-path
           stdout: ''
+  - include: test/input/error.yaml
+    output:
+      id: error
+      tests:
+      - id: scan-errors
+        tests:
+        - uri: /'?%@$'
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            scan error: expected two hexdecimal digits to follow symbol '%s':
+                /%27?%@$'
+                     ^
+        - uri: /'%FF'
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: "scan error: cannot convert a byte sequence %FF to UTF-8: invalid
+            start byte:\n    /'\uFFFD'\n      ^\n"
+        - uri: /'Hello
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            scan error: cannot find a matching quote mark:
+                /'Hello
+                 ^
+        - uri: /`Hello'
+          status: 400 Bad Request
+          headers:
+          - [Content-Type, text/plain; charset=UTF-8]
+          body: |
+            scan error: unexpected symbol '`':
+                /`Hello'
+                 ^
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.