Tests: Add test for toolchains-v1 File API object
diff --git a/Help/manual/cmake-file-api.7.rst b/Help/manual/cmake-file-api.7.rst
index f608d61..89739b7 100644
--- a/Help/manual/cmake-file-api.7.rst
+++ b/Help/manual/cmake-file-api.7.rst
@@ -1195,19 +1195,10 @@
               "/lib"
             ],
             "linkFrameworkDirectories": [],
-            "linkLibraries": [
-              "gcc",
-              "gcc_s",
-              "c",
-              "gcc",
-              "gcc_s"
-            ]
+            "linkLibraries": [ "gcc", "gcc_s", "c", "gcc", "gcc_s" ]
           }
         },
-        "sourceFileExtensions": [
-          "c",
-          "m"
-        ]
+        "sourceFileExtensions": [ "c", "m" ]
       },
       {
         "language": "CXX",
@@ -1234,25 +1225,12 @@
             ],
             "linkFrameworkDirectories": [],
             "linkLibraries": [
-              "stdc++",
-              "m",
-              "gcc_s",
-              "gcc",
-              "c",
-              "gcc_s",
-              "gcc"
+              "stdc++", "m", "gcc_s", "gcc", "c", "gcc_s", "gcc"
             ]
           }
         },
         "sourceFileExtensions": [
-          "C",
-          "M",
-          "c++",
-          "cc",
-          "cpp",
-          "cxx",
-          "mm",
-          "CPP"
+          "C", "M", "c++", "cc", "cpp", "cxx", "mm", "CPP"
         ]
       }
     ]
@@ -1265,7 +1243,7 @@
   associated with a particular language. The members of each entry are:
 
   ``language``
-    A string specifying the toolchain language, like C or CXX. Language
+    A JSON string specifying the toolchain language, like C or CXX. Language
     names are the same as langauge names that can be passed to the
     :command:`project` command. Because CMake only supports a single toolchain
     per language, this field can be used as a key.
@@ -1274,49 +1252,62 @@
     A JSON object containing members:
 
     ``path``
-      Optional member that has the same value as
-      :variable:`CMAKE_<LANG>_COMPILER` if it is defined for the current
-      language.
+      Optional member that is present when the
+      :variable:`CMAKE_<LANG>_COMPILER` variable is defined for the current
+      language. Its value is a JSON string holding the path to the compiler.
 
     ``id``
-      Optional member that has the same value as
-      :variable:`CMAKE_<LANG>_COMPILER_ID` if it is defined for the current
-      language.
+      Optional member that is present when the
+      :variable:`CMAKE_<LANG>_COMPILER_ID` variable is defined for the current
+      language. Its value is a JSON string holding the ID (GNU, MSVC, etc.) of
+      the compiler.
 
     ``version``
-      Optional member that has the same value as
-      :variable:`CMAKE_<LANG>_COMPILER_VERSION` if it is defined for the
-      current language.
+      Optional member that is present when the
+      :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable is defined for the
+      current language. Its value is a JSON string holding the version of the
+      compiler.
 
     ``target``
-      Optional member that has the same value as
-      :variable:`CMAKE_<LANG>_COMPILER_TARGET` if it is defined for the
-      current language.
+      Optional member that is present when the
+      :variable:`CMAKE_<LANG>_COMPILER_TARGET` variable is defined for the
+      current language. Its value is a JSON string holding the cross-compiling
+      target of the compiler.
 
     ``implicit``
       A JSON object containing members:
 
       ``includeDirectories``
-        Optional JSON array that has the same value as
-        :variable:`CMAKE_<LANG>_IMPLICIT_INCLUDE_DIRECTORIES` if it is defined
-        for the current language.
+        Optional member that is present when the
+        :variable:`CMAKE_<LANG>_IMPLICIT_INCLUDE_DIRECTORIES` variable is
+        defined for the current language. Its value is a JSON array of JSON
+        strings where each string holds a path to an implicit include
+        directory for the compiler.
 
       ``linkDirectories``
-        Optional JSON array that has the same value as
-        :variable:`CMAKE_<LANG>_IMPLICIT_LINK_DIRECTORIES` if it is defined
-        for the current language.
+        Optional member that is present when the
+        :variable:`CMAKE_<LANG>_IMPLICIT_LINK_DIRECTORIES` variable is
+        defined for the current language. Its value is a JSON array of JSON
+        strings where each string holds a path to an implicit link directory
+        for the compiler.
 
       ``linkFrameworkDirectories``
-        Optional JSON array that has the same value as
-        :variable:`CMAKE_<LANG>_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES` if it is
-        defined for the current language.
+        Optional member that is present when the
+        :variable:`CMAKE_<LANG>_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES` variable
+        is defined for the current language. Its value is a JSON array of JSON
+        strings where each string holds a path to an implicit link framework
+        directory for the compiler.
 
       ``linkLibraries``
-        Optional JSON array that has the same value as
-        :variable:`CMAKE_<LANG>_IMPLICIT_LINK_LIBRARIES` if it is defined for
-        the current language.
+        Optional member that is present when the
+        :variable:`CMAKE_<LANG>_IMPLICIT_LINK_LIBRARIES` variable is defined
+        for the current language. Its value is a JSON array of JSON strings
+        where each string holds a path to an implicit link library for the
+        compiler.
 
   ``sourceFileExtensions``
-    Optional JSON array that has the same value as
-    :variable:`CMAKE_<LANG>_SOURCE_FILE_EXTENSIONS` if it is defined for the
-    current language.
+    Optional member that is present when the
+    :variable:`CMAKE_<LANG>_SOURCE_FILE_EXTENSIONS` variable is defined for
+    the current language. Its value is a JSON array of JSON strings where each
+    each string holds a file extension (without the leading dot) for the
+    language.
diff --git a/Tests/RunCMake/FileAPI/RunCMakeTest.cmake b/Tests/RunCMake/FileAPI/RunCMakeTest.cmake
index 2bb2765..ae3d179 100644
--- a/Tests/RunCMake/FileAPI/RunCMakeTest.cmake
+++ b/Tests/RunCMake/FileAPI/RunCMakeTest.cmake
@@ -24,6 +24,7 @@
   file(GLOB index ${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/reply/index-*.json)
   execute_process(
     COMMAND ${PYTHON_EXECUTABLE} "${RunCMake_SOURCE_DIR}/${case}-check.py" "${index}" "${CMAKE_CXX_COMPILER_ID}"
+      "${RunCMake_TEST_BINARY_DIR}"
     RESULT_VARIABLE result
     OUTPUT_VARIABLE output
     ERROR_VARIABLE output
@@ -62,3 +63,4 @@
 run_object(codemodel-v2)
 run_object(cache-v2)
 run_object(cmakeFiles-v1)
+run_object(toolchains-v1)
diff --git a/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateful-check.cmake b/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateful-check.cmake
new file mode 100644
index 0000000..ce38461
--- /dev/null
+++ b/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateful-check.cmake
@@ -0,0 +1,11 @@
+set(expect
+  query
+  query/client-foo
+  query/client-foo/query.json
+  reply
+  reply/index-[0-9.T-]+.json
+  reply/toolchains-v1-[0-9a-f]+.json
+  )
+check_api("^${expect}$")
+
+check_python(toolchains-v1)
diff --git a/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateful-prep.cmake b/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateful-prep.cmake
new file mode 100644
index 0000000..ca62edf
--- /dev/null
+++ b/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateful-prep.cmake
@@ -0,0 +1,4 @@
+file(REMOVE_RECURSE ${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query)
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query/client-foo/query.json" [[
+{ "requests": [ { "kind": "toolchains", "version" : 1 } ] }
+]])
diff --git a/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateless-check.cmake b/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateless-check.cmake
new file mode 100644
index 0000000..4676dd8
--- /dev/null
+++ b/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateless-check.cmake
@@ -0,0 +1,11 @@
+set(expect
+  query
+  query/client-foo
+  query/client-foo/toolchains-v1
+  reply
+  reply/index-[0-9.T-]+.json
+  reply/toolchains-v1-[0-9a-f]+.json
+  )
+check_api("^${expect}$")
+
+check_python(toolchains-v1)
diff --git a/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateless-prep.cmake b/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateless-prep.cmake
new file mode 100644
index 0000000..7edff93
--- /dev/null
+++ b/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateless-prep.cmake
@@ -0,0 +1,2 @@
+file(REMOVE_RECURSE ${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query)
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query/client-foo/toolchains-v1" "")
diff --git a/Tests/RunCMake/FileAPI/toolchains-v1-SharedStateless-check.cmake b/Tests/RunCMake/FileAPI/toolchains-v1-SharedStateless-check.cmake
new file mode 100644
index 0000000..8e83758
--- /dev/null
+++ b/Tests/RunCMake/FileAPI/toolchains-v1-SharedStateless-check.cmake
@@ -0,0 +1,10 @@
+set(expect
+  query
+  query/toolchains-v1
+  reply
+  reply/index-[0-9.T-]+.json
+  reply/toolchains-v1-[0-9a-f]+.json
+  )
+check_api("^${expect}$")
+
+check_python(toolchains-v1)
diff --git a/Tests/RunCMake/FileAPI/toolchains-v1-SharedStateless-prep.cmake b/Tests/RunCMake/FileAPI/toolchains-v1-SharedStateless-prep.cmake
new file mode 100644
index 0000000..2db73a1
--- /dev/null
+++ b/Tests/RunCMake/FileAPI/toolchains-v1-SharedStateless-prep.cmake
@@ -0,0 +1,2 @@
+file(REMOVE_RECURSE ${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query)
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query/toolchains-v1" "")
diff --git a/Tests/RunCMake/FileAPI/toolchains-v1-check.py b/Tests/RunCMake/FileAPI/toolchains-v1-check.py
new file mode 100644
index 0000000..a0e50c2
--- /dev/null
+++ b/Tests/RunCMake/FileAPI/toolchains-v1-check.py
@@ -0,0 +1,86 @@
+from check_index import *
+import os
+
+class ExpectedVar(object):
+    def __init__(self, name):
+        self.name = name
+
+class ExpectedList(object):
+    def __init__(self, name):
+        self.name = name
+
+EXPECTED_TOOLCHAIN = {
+    "language": "CXX",
+    "compiler": {
+        "path": ExpectedVar("CMAKE_CXX_COMPILER"),
+        "id": ExpectedVar("CMAKE_CXX_COMPILER_ID"),
+        "version": ExpectedVar("CMAKE_CXX_COMPILER_VERSION"),
+        "target": ExpectedVar("CMAKE_CXX_COMPILER_TARGET"),
+        "implicit": {
+            "includeDirectories": \
+                ExpectedList("CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES"),
+            "linkDirectories": \
+                ExpectedList("CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES"),
+            "linkFrameworkDirectories": \
+                ExpectedList(
+                    "CMAKE_CXX_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES"),
+            "linkLibraries": \
+                ExpectedList("CMAKE_CXX_IMPLICIT_LINK_LIBRARIES"),
+        }
+    },
+    "sourceFileExtensions": \
+        ExpectedList("CMAKE_CXX_SOURCE_FILE_EXTENSIONS"),
+}
+
+def check_objects(o):
+    assert is_list(o)
+    assert len(o) == 1
+    check_index_object(o[0], "toolchains", 1, 0, check_object_toolchains)
+
+def check_object_toolchains(o):
+    assert sorted(o.keys()) == ["kind", "toolchains", "version"]
+    # The "kind" and "version" members are handled by check_index_object.
+    toolchains = o["toolchains"]
+    assert is_list(toolchains)
+
+    # Other platform-specific toolchains may exist (like RC on Windows).
+    has_cxx_toolchain = False
+    for toolchain in toolchains:
+        assert is_dict(toolchain)
+        assert "language" in toolchain
+        if toolchain["language"] == "CXX":
+            check_object_toolchain(toolchain, EXPECTED_TOOLCHAIN)
+            has_cxx_toolchain = True
+
+    assert has_cxx_toolchain
+
+def check_object_toolchain(o, expected):
+    expected_keys = [
+        key for (key, value) in expected.items()
+        if is_string(value) or is_dict(value)
+            or (type(value) in (ExpectedVar, ExpectedList)
+                and variables[value.name]["defined"])]
+    assert sorted(o.keys()) == sorted(expected_keys)
+
+    for key in expected_keys:
+        value = expected[key]
+        if is_string(value):
+            assert o[key] == value
+        elif is_dict(value):
+            check_object_toolchain(o[key], value)
+        elif type(value) == ExpectedVar:
+            assert o[key] == variables[value.name]["value"]
+        elif type(value) == ExpectedList:
+            expected_items = filter(
+                None, variables[value.name]["value"].split(";"))
+            check_list_match(lambda a, b: a == b, o[key], expected_items)
+        else:
+            assert False
+
+with open(os.path.join(sys.argv[3], "toolchain_variables.json")) as f:
+    variables = json.load(f)
+
+assert is_dict(variables)
+assert is_dict(index)
+assert sorted(index.keys()) == ["cmake", "objects", "reply"]
+check_objects(index["objects"])
diff --git a/Tests/RunCMake/FileAPI/toolchains-v1.cmake b/Tests/RunCMake/FileAPI/toolchains-v1.cmake
new file mode 100644
index 0000000..367aade
--- /dev/null
+++ b/Tests/RunCMake/FileAPI/toolchains-v1.cmake
@@ -0,0 +1,22 @@
+enable_language(CXX)
+
+set(variable_suffixes
+  COMPILER COMPILER_ID COMPILER_VERSION COMPILER_TARGET
+  IMPLICIT_INCLUDE_DIRECTORIES IMPLICIT_LINK_DIRECTORIES
+  IMPLICIT_LINK_FRAMEWORK_DIRECTORIES IMPLICIT_LINK_LIBRARIES
+  SOURCE_FILE_EXTENSIONS)
+set(language CXX)
+set(json "{}")
+
+foreach(variable_suffix ${variable_suffixes})
+  set(variable "CMAKE_${language}_${variable_suffix}")
+  string(JSON json SET "${json}" "${variable}" "{}")
+  if(DEFINED "${variable}")
+    string(JSON json SET "${json}" "${variable}" "defined" "true")
+    string(JSON json SET "${json}" "${variable}" "value" "\"${${variable}}\"")
+  else()
+    string(JSON json SET "${json}" "${variable}" "defined" "false")
+  endif()
+endforeach()
+
+file(WRITE ${CMAKE_BINARY_DIR}/toolchain_variables.json "${json}")