[PATCH 6 of 6 json-style] tests: add tests for json output from hgweb

Gregory Szorc gregory.szorc at gmail.com
Wed Dec 31 16:45:36 CST 2014


# HG changeset patch
# User Gregory Szorc <gregory.szorc at gmail.com>
# Date 1420065389 28800
#      Wed Dec 31 14:36:29 2014 -0800
# Node ID 375310e882793f02023305f1065f616b0b42ab88
# Parent  8a88b921f7b9b467046496ab6aa99d2589dd935c
tests: add tests for json output from hgweb

Now that we've added a json style, let's verify it works via hgweb.

The added test file contains either a basic test or a placeholder for a
test for every existing web command.

Tests have been excluded for cases where JSON output isn't sane. For
example, the "changeset" command invokes the templater multiple times.
This "inner expansion" of values leads to the "outer" template
encountering already-expanded JSON as a string, which it then proceeds
to escape. The output JSON is valid, but the extra escaping is wrong.

Upcoming patches will rework the templater to make this scenario work.
hgweb commands will be fixed to use the new API and tests will be added
to demonstrate they work as expected.

diff --git a/tests/test-hgweb-json.t b/tests/test-hgweb-json.t
new file mode 100644
--- /dev/null
+++ b/tests/test-hgweb-json.t
@@ -0,0 +1,152 @@
+#require serve
+
+  $ hg init test
+  $ cd test
+  $ mkdir da
+  $ echo foo > da/foo
+  $ echo foo > foo
+  $ hg -q ci -A -m initial
+  $ echo bar > foo
+  $ hg ci -m 'modify foo'
+  $ echo bar > da/foo
+  $ hg ci -m 'modify da/foo'
+  $ hg bookmark test-bookmark
+  $ hg mv foo foo-new
+  $ hg commit -m 'move foo'
+  $ hg tag -m 'create tag' test-tag
+  $ hg -q up -r 0
+  $ hg -q branch test-branch
+  $ echo branch > foo
+  $ hg commit -m 'create test branch'
+
+  $ hg log -G
+  @  changeset:   5:6ab967a8ab34
+  |  branch:      test-branch
+  |  tag:         tip
+  |  parent:      0:06e557f3edf6
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     create test branch
+  |
+  | o  changeset:   4:92d2ccb2a27b
+  | |  bookmark:    test-bookmark
+  | |  user:        test
+  | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  summary:     create tag
+  | |
+  | o  changeset:   3:78896eb0e102
+  | |  tag:         test-tag
+  | |  user:        test
+  | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  summary:     move foo
+  | |
+  | o  changeset:   2:8d7c456572ac
+  | |  user:        test
+  | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  summary:     modify da/foo
+  | |
+  | o  changeset:   1:f8bbb9024b10
+  |/   user:        test
+  |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    summary:     modify foo
+  |
+  o  changeset:   0:06e557f3edf6
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     initial
+  
+
+  $ hg serve -p $HGPORT -d --pid-file=hg.pid -A access.log -E error.log
+  $ cat hg.pid >> $DAEMON_PIDS
+
+(Try to keep these in roughly the order they are defined in webcommands.py)
+
+(log is handled by filelog/ and changelog/ - ignore it)
+
+(rawfile/ doesn't use templating - nothing to test)
+
+file/ with path returns a file revision
+
+  $ $TESTDIR/get-with-headers.py localhost:$HGPORT 'file/78896eb0e102/foo-new?style=json'
+  200 Script output follows
+  
+  {"author": "test", "branch": [], "child": [], "date": [0.0, 0], "desc": "move foo", "extra": {"branch": "default"}, "file": "foo-new", "node": "78896eb0e102174ce9278438a95e12543e4367a7", "parent": [{"branch": "default", "date": [0.0, 0], "description": "modify foo", "file": "foo", "node": "f8bbb9024b10f93cdbb8d940337398291d40dea8", "rev": 1, "user": "test"}], "path": "/", "permissions": "", "rename": [{"file": "foo", "node": "cebda196bdbe7661cec847739e7c5de89ec6e5a5"}], "rev": 3, "text": [{"line": "bar\n", "lineid": "l1", "linenumber": "     1", "parity": 0}]} (no-eol)
+
+TODO changelog/
+
+TODO shortlog/
+
+TODO changeset/
+
+manifest/ should display manifest listings
+
+  $ $TESTDIR/get-with-headers.py localhost:$HGPORT 'manifest?style=json'
+  200 Script output follows
+  
+  {"archives": [], "bookmarks": [], "branches": [{"name": "test-branch"}], "dentries": [{"basename": "da", "emptydirs": "", "parity": 1, "path": "/da"}], "fentries": [{"basename": "foo", "date": [0.0, 0], "file": "foo", "parity": 0, "permissions": "", "size": 7}], "inbranch": [], "node": "6ab967a8ab3489227a83f80e920faa039a71819f", "path": "/", "rev": 5, "tags": [{"name": "tip"}], "up": "/", "upparity": 0} (no-eol)
+
+tags/ should display tag info
+
+  $ $TESTDIR/get-with-headers.py localhost:$HGPORT 'tags?style=json'
+  200 Script output follows
+  
+  {"entries": [{"date": [0.0, 0], "node": "6ab967a8ab3489227a83f80e920faa039a71819f", "parity": 0, "tag": "tip"}, {"date": [0.0, 0], "node": "78896eb0e102174ce9278438a95e12543e4367a7", "parity": 1, "tag": "test-tag"}], "entriesnotip": [{"date": [0.0, 0], "node": "78896eb0e102174ce9278438a95e12543e4367a7", "parity": 0, "tag": "test-tag"}], "latestentry": [{"date": [0.0, 0], "node": "78896eb0e102174ce9278438a95e12543e4367a7", "parity": 1, "tag": "test-tag"}], "node": "6ab967a8ab3489227a83f80e920faa039a71819f"} (no-eol)
+
+bookmarks/ should display bookmarks info
+
+  $ $TESTDIR/get-with-headers.py localhost:$HGPORT 'bookmarks?style=json'
+  200 Script output follows
+  
+  {"entries": [{"bookmark": "test-bookmark", "date": [0.0, 0], "node": "92d2ccb2a27b6f75b6b0b70c98c19095735dad40", "parity": 0}], "latestentry": [{"bookmark": "test-bookmark", "date": [0.0, 0], "node": "92d2ccb2a27b6f75b6b0b70c98c19095735dad40", "parity": 1}], "node": "6ab967a8ab3489227a83f80e920faa039a71819f"} (no-eol)
+
+branches/ should display branches info
+
+  $ $TESTDIR/get-with-headers.py localhost:$HGPORT 'branches?style=json'
+  200 Script output follows
+  
+  {"entries": [{"branch": "test-branch", "date": [0.0, 0], "node": "6ab967a8ab3489227a83f80e920faa039a71819f", "parity": 0, "status": "open"}, {"branch": "default", "date": [0.0, 0], "node": "92d2ccb2a27b6f75b6b0b70c98c19095735dad40", "parity": 1, "status": "open"}], "latestentry": [{"branch": "test-branch", "date": [0.0, 0], "node": "6ab967a8ab3489227a83f80e920faa039a71819f", "parity": 0, "status": "open"}], "node": "6ab967a8ab3489227a83f80e920faa039a71819f"} (no-eol)
+
+TODO summary/
+
+TODO filediff/
+
+TODO comparison/
+
+annotate/ should display file annotations
+
+  $ $TESTDIR/get-with-headers.py localhost:$HGPORT 'annotate/tip/foo?style=json'
+  200 Script output follows
+  
+  {"annotate": [{"author": "test", "desc": "create test branch", "extra": {"branch": "test-branch"}, "file": "foo", "line": "branch\n", "lineid": "l1", "linenumber": "     1", "node": "6ab967a8ab3489227a83f80e920faa039a71819f", "parity": 0, "rev": 5, "revdate": [0.0, 0], "targetline": 1}], "author": "test", "branch": [{"name": "test-branch"}], "child": [], "date": [0.0, 0], "desc": "create test branch", "extra": {"branch": "test-branch"}, "file": "foo", "node": "6ab967a8ab3489227a83f80e920faa039a71819f", "parent": [{"branch": "default", "date": [0.0, 0], "description": "initial", "file": "foo", "node": "06e557f3edf66faa1ccaba5dd8c203c21cc79f1e", "rev": 0, "user": "test"}], "path": "/", "permissions": "", "rename": [], "rev": 5} (no-eol)
+
+filelog/ shows changes for a given file
+
+  $ $TESTDIR/get-with-headers.py localhost:$HGPORT 'filelog/tip/foo?style=json'
+  200 Script output follows
+  
+  {"entries": [{"author": "test", "bookmarks": [], "branch": [{"name": "test-branch"}], "branches": [{"name": "test-branch"}], "child": [], "date": [0.0, 0], "desc": "create test branch", "extra": {"branch": "test-branch"}, "file": "foo", "filerev": 2, "inbranch": [], "node": "6ab967a8ab3489227a83f80e920faa039a71819f", "parent": [{"branch": "default", "date": [0.0, 0], "description": "initial", "file": "foo", "node": "06e557f3edf66faa1ccaba5dd8c203c21cc79f1e", "rev": 0, "user": "test"}], "parity": 0, "rename": [], "tags": [{"name": "tip"}]}, {"author": "test", "bookmarks": [], "branch": [], "branches": [], "child": [], "date": [0.0, 0], "desc": "modify foo", "extra": {"branch": "default"}, "file": "foo", "filerev": 1, "inbranch": [], "node": "f8bbb9024b10f93cdbb8d940337398291d40dea8", "parent": [{"branch": "default", "date": [0.0, 0], "description": "initial", "file": "foo", "node": "06e557f3edf66faa1ccaba5dd8c203c21cc79f1e", "rev": 0, "user": "test"}], "parity": 1, "rename": [], "tags": []}, {"author": "test", "bookmarks": [], "branch": [], "branches": [], "child": [{"branch": "default", "date": [0.0, 0], "description": "modify foo", "file": "foo", "node": "f8bbb9024b10f93cdbb8d940337398291d40dea8", "rev": 1, "user": "test"}, {"branch": "test-branch", "date": [0.0, 0], "description": "create test branch", "file": "foo", "node": "6ab967a8ab3489227a83f80e920faa039a71819f", "rev": 5, "user": "test"}], "date": [0.0, 0], "desc": "initial", "extra": {"branch": "default"}, "file": "foo", "filerev": 0, "inbranch": [], "node": "06e557f3edf66faa1ccaba5dd8c203c21cc79f1e", "parent": [], "parity": 0, "rename": [], "tags": []}], "file": "foo", "latestentry": [{"author": "test", "bookmarks": [], "branch": [{"name": "test-branch"}], "branches": [{"name": "test-branch"}], "child": [], "date": [0.0, 0], "desc": "create test branch", "extra": {"branch": "test-branch"}, "file": "foo", "filerev": 2, "inbranch": [], "node": "6ab967a8ab3489227a83f80e920faa039a71819f", "parent": [], "parity": 0, "rename": [], "tags": [{"name": "tip"}]}], "lessvars": [{"name": "revcount", "separator": "?", "value": "30"}, {"name": "style", "separator": "&", "value": "json"}], "morevars": [{"name": "revcount", "separator": "?", "value": "120"}, {"name": "style", "separator": "&", "value": "json"}], "nav": [{"after": [{"label": "tip", "node": "tip"}], "before": [{"label": "(0)", "node": "06e557f3edf66faa1ccaba5dd8c203c21cc79f1e"}]}], "node": "6ab967a8ab3489227a83f80e920faa039a71819f", "revcount": 60} (no-eol)
+
+(archive/ doesn't use templating, so ignore it)
+
+(static/ doesn't use templating, so ignore it)
+
+graph/ should show info necessary to render a graph.
+
+  $ $TESTDIR/get-with-headers.py localhost:$HGPORT 'graph/tip?style=json'
+  200 Script output follows
+  
+  {"bg_height": 39, "canvasheight": 246, "canvaswidth": 78, "changenav": [{"after": [{"label": "tip", "node": "tip"}], "before": [{"label": "(0)", "node": "06e557f3edf66faa1ccaba5dd8c203c21cc79f1e"}]}], "cols": 1, "downrev": 0, "jsdata": [["6ab967a8ab34", [0, 1], [[0, 0, 1, -1, ""]], "create test branch", "test", "1970-01-01", ["test-branch", true], ["tip"], []], ["92d2ccb2a27b", [1, 2], [[0, 0, 1, -1, ""], [1, 1, 2, -1, ""]], "create tag", "test", "1970-01-01", ["default", true], [], ["test-bookmark"]], ["78896eb0e102", [1, 2], [[0, 0, 1, -1, ""], [1, 1, 2, -1, ""]], "move foo", "test", "1970-01-01", ["default", false], ["test-tag"], []], ["8d7c456572ac", [1, 2], [[0, 0, 1, -1, ""], [1, 1, 2, -1, ""]], "modify da/foo", "test", "1970-01-01", ["default", false], [], []], ["f8bbb9024b10", [1, 2], [[0, 0, 1, -1, ""], [1, 0, 2, -1, ""]], "modify foo", "test", "1970-01-01", ["default", false], [], []], ["06e557f3edf6", [0, 1], [], "initial", "test", "1970-01-01", ["default", false], [], []]], "lessvars": [{"name": "revcount", "separator": "?", "value": "30"}, {"name": "style", "separator": "&", "value": "json"}], "morevars": [{"name": "revcount", "separator": "?", "value": "120"}, {"name": "style", "separator": "&", "value": "json"}], "node": "6ab967a8ab3489227a83f80e920faa039a71819f", "nodes": [{"age": "1970-01-01", "bookmarks": [], "branches": [{"name": "test-branch"}], "col": 0, "color": 1, "desc": "create test branch", "edges": [{"bcolor": "", "col": 0, "color": 1, "nextcol": 0, "width": -1}], "inbranch": [], "nextrow": 1, "node": "6ab967a8ab34", "row": 0, "tags": [{"name": "tip"}], "user": "test"}, {"age": "1970-01-01", "bookmarks": [{"name": "test-bookmark"}], "branches": [{"name": "default"}], "col": 1, "color": 2, "desc": "create tag", "edges": [{"bcolor": "", "col": 0, "color": 1, "nextcol": 0, "width": -1}, {"bcolor": "", "col": 1, "color": 2, "nextcol": 1, "width": -1}], "inbranch": [], "nextrow": 2, "node": "92d2ccb2a27b", "row": 1, "tags": [], "user": "test"}, {"age": "1970-01-01", "bookmarks": [], "branches": [], "col": 1, "color": 2, "desc": "move foo", "edges": [{"bcolor": "", "col": 0, "color": 1, "nextcol": 0, "width": -1}, {"bcolor": "", "col": 1, "color": 2, "nextcol": 1, "width": -1}], "inbranch": [], "nextrow": 3, "node": "78896eb0e102", "row": 2, "tags": [{"name": "test-tag"}], "user": "test"}, {"age": "1970-01-01", "bookmarks": [], "branches": [], "col": 1, "color": 2, "desc": "modify da/foo", "edges": [{"bcolor": "", "col": 0, "color": 1, "nextcol": 0, "width": -1}, {"bcolor": "", "col": 1, "color": 2, "nextcol": 1, "width": -1}], "inbranch": [], "nextrow": 4, "node": "8d7c456572ac", "row": 3, "tags": [], "user": "test"}, {"age": "1970-01-01", "bookmarks": [], "branches": [], "col": 1, "color": 2, "desc": "modify foo", "edges": [{"bcolor": "", "col": 0, "color": 1, "nextcol": 0, "width": -1}, {"bcolor": "", "col": 1, "color": 2, "nextcol": 0, "width": -1}], "inbranch": [], "nextrow": 5, "node": "f8bbb9024b10", "row": 4, "tags": [], "user": "test"}, {"age": "1970-01-01", "bookmarks": [], "branches": [], "col": 0, "color": 1, "desc": "initial", "edges": [], "inbranch": [], "nextrow": 6, "node": "06e557f3edf6", "row": 5, "tags": [], "user": "test"}], "rev": 5, "revcount": 60, "rows": 6, "truecanvasheight": 234, "uprev": 5} (no-eol)
+
+help/ with no arguments should list help topics
+
+  $ $TESTDIR/get-with-headers.py localhost:$HGPORT 'help?style=json'
+  200 Script output follows
+  
+  {"earlycommands": [{"summary": "add the specified files on the next commit", "topic": "add"}, {"summary": "show changeset information by line for each file", "topic": "annotate"}, {"summary": "make a copy of an existing repository", "topic": "clone"}, {"summary": "commit the specified files or all outstanding changes", "topic": "commit"}, {"summary": "diff repository (or selected files)", "topic": "diff"}, {"summary": "dump the header and diffs for one or more changesets", "topic": "export"}, {"summary": "forget the specified files on the next commit", "topic": "forget"}, {"summary": "create a new repository in the given directory", "topic": "init"}, {"summary": "show revision history of entire repository or files", "topic": "log"}, {"summary": "merge another revision into working directory", "topic": "merge"}, {"summary": "pull changes from the specified source", "topic": "pull"}, {"summary": "push changes to the specified destination", "topic": "push"}, {"summary": "remove the specified files on the next commit", "topic": "remove"}, {"summary": "start stand-alone webserver", "topic": "serve"}, {"summary": "show changed files in the working directory", "topic": "status"}, {"summary": "summarize working directory state", "topic": "summary"}, {"summary": "update working directory (or switch revisions)", "topic": "update"}], "othercommands": [{"summary": "add all new files, delete all missing files", "topic": "addremove"}, {"summary": "create an unversioned archive of a repository revision", "topic": "archive"}, {"summary": "reverse effect of earlier changeset", "topic": "backout"}, {"summary": "subdivision search of changesets", "topic": "bisect"}, {"summary": "create a new bookmark or list existing bookmarks", "topic": "bookmarks"}, {"summary": "set or show the current branch name", "topic": "branch"}, {"summary": "list repository named branches", "topic": "branches"}, {"summary": "create a changegroup file", "topic": "bundle"}, {"summary": "output the current or given revision of files", "topic": "cat"}, {"summary": "show combined config settings from all hgrc files", "topic": "config"}, {"summary": "mark files as copied for the next commit", "topic": "copy"}, {"summary": "list tracked files", "topic": "files"}, {"summary": "copy changes from other branches onto the current branch", "topic": "graft"}, {"summary": "search for a pattern in specified files and revisions", "topic": "grep"}, {"summary": "show branch heads", "topic": "heads"}, {"summary": "show help for a given topic or a help overview", "topic": "help"}, {"summary": "identify the working copy or specified revision", "topic": "identify"}, {"summary": "import an ordered set of patches", "topic": "import"}, {"summary": "show new changesets found in source", "topic": "incoming"}, {"summary": "output the current or given revision of the project manifest", "topic": "manifest"}, {"summary": "show changesets not found in the destination", "topic": "outgoing"}, {"summary": "show aliases for remote repositories", "topic": "paths"}, {"summary": "set or show the current phase name", "topic": "phase"}, {"summary": "roll back an interrupted transaction", "topic": "recover"}, {"summary": "rename files; equivalent of copy + remove", "topic": "rename"}, {"summary": "redo merges or set/view the merge status of files", "topic": "resolve"}, {"summary": "restore files to their checkout state", "topic": "revert"}, {"summary": "print the root (top) of the current working directory", "topic": "root"}, {"summary": "add one or more tags for the current or given revision", "topic": "tag"}, {"summary": "list repository tags", "topic": "tags"}, {"summary": "apply one or more changegroup files", "topic": "unbundle"}, {"summary": "verify the integrity of the repository", "topic": "verify"}, {"summary": "output version and copyright information", "topic": "version"}], "title": "Index", "topics": [{"summary": "Configuration Files", "topic": "config"}, {"summary": "Date Formats", "topic": "dates"}, {"summary": "Diff Formats", "topic": "diffs"}, {"summary": "Environment Variables", "topic": "environment"}, {"summary": "Using Additional Features", "topic": "extensions"}, {"summary": "Specifying File Sets", "topic": "filesets"}, {"summary": "Glossary", "topic": "glossary"}, {"summary": "Syntax for Mercurial Ignore Files", "topic": "hgignore"}, {"summary": "Configuring hgweb", "topic": "hgweb"}, {"summary": "Merge Tools", "topic": "merge-tools"}, {"summary": "Specifying Multiple Revisions", "topic": "multirevs"}, {"summary": "File Name Patterns", "topic": "patterns"}, {"summary": "Working with Phases", "topic": "phases"}, {"summary": "Specifying Single Revisions", "topic": "revisions"}, {"summary": "Specifying Revision Sets", "topic": "revsets"}, {"summary": "Subrepositories", "topic": "subrepos"}, {"summary": "Template Usage", "topic": "templating"}, {"summary": "URL Paths", "topic": "urls"}]} (no-eol)
+
+help/ can return help for a specific topic
+
+  $ $TESTDIR/get-with-headers.py localhost:$HGPORT 'help?node=heads&style=json'
+  200 Script output follows
+  
+  {"doc": "hg heads [-ct] [-r STARTREV] [REV]...\n\nshow branch heads\n\n    With no arguments, show all open branch heads in the repository.\n    Branch heads are changesets that have no descendants on the\n    same branch. They are where development generally takes place and\n    are the usual targets for update and merge operations.\n\n    If one or more REVs are given, only open branch heads on the\n    branches associated with the specified changesets are shown. This\n    means that you can use :hg:`heads .` to see the heads on the\n    currently checked-out branch.\n\n    If -c/--closed is specified, also show branch heads marked closed\n    (see :hg:`commit --close-branch`).\n\n    If STARTREV is specified, only those heads that are descendants of\n    STARTREV will be displayed.\n\n    If -t/--topo is specified, named branch mechanics will be ignored and only\n    topological heads (changesets with no children) will be shown.\n\n    Returns 0 if matching heads are found, 1 if not.\n    \n\noptions:\n\n == =================== =================================================\n -r --rev STARTREV      show only heads which are descendants of STARTREV\n -t --topo              show topological heads only                      \n -a --active            show active branchheads only (DEPRECATED)        \n -c --closed            show normal and closed branch heads              \n    --style STYLE       display using template map file (DEPRECATED)     \n -T --template TEMPLATE display with template                            \n == =================== =================================================\n\nglobal options ([+] can be repeated):\n\n == =================== ==================================================================\n -R --repository REPO   repository root directory or name of overlay bundle file          \n    --cwd DIR           change working directory                                          \n -y --noninteractive    do not prompt, automatically pick the first choice for all prompts\n -q --quiet             suppress output                                                   \n -v --verbose           enable additional output                                          \n    --config CONFIG [+] set/override config option (use 'section.name=value')             \n    --debug             enable debugging output                                           \n    --debugger          start debugger                                                    \n    --encoding ENCODE   set the charset encoding (default: ascii)                         \n    --encodingmode MODE set the charset encoding mode (default: strict)                   \n    --traceback         always print a traceback on exception                             \n    --time              time how long the command takes                                   \n    --profile           print command execution profile                                   \n    --version           output version information and exit                               \n -h --help              display help and exit                                             \n    --hidden            consider hidden changesets                                        \n == =================== ==================================================================\n", "topic": "heads"} (no-eol)


More information about the Mercurial-devel mailing list