Merge topic 'vs-non-built-file-item-metadata'

0723e04f7a VS: Add documentation for VS_SETTINGS and VS_SOURCE_SETTINGS_<tool>.
2ca1102f83 VS: Test VS_SETTINGS and VS_SOURCE_SETTINGS_<tool> properties.
f00e1b816d VS: Add VS_SOURCE_SETTINGS_<tool> target property
2ce42f281f VS: Add VS_SETTINGS source file property
53116d3942 VS: Use unordered_map to write HLSL settings.

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !4498
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
index a2bbdcd..cbb2298 100644
--- a/Help/manual/cmake-properties.7.rst
+++ b/Help/manual/cmake-properties.7.rst
@@ -378,6 +378,7 @@
    /prop_tgt/VS_SCC_PROVIDER
    /prop_tgt/VS_SDK_REFERENCES
    /prop_tgt/VS_SOLUTION_DEPLOY
+   /prop_tgt/VS_SOURCE_SETTINGS_tool
    /prop_tgt/VS_USER_PROPS
    /prop_tgt/VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION
    /prop_tgt/VS_WINRT_COMPONENT
@@ -487,6 +488,7 @@
    /prop_sf/VS_DEPLOYMENT_LOCATION
    /prop_sf/VS_INCLUDE_IN_VSIX
    /prop_sf/VS_RESOURCE_GENERATOR
+   /prop_sf/VS_SETTINGS
    /prop_sf/VS_SHADER_DISABLE_OPTIMIZATIONS
    /prop_sf/VS_SHADER_ENABLE_DEBUG
    /prop_sf/VS_SHADER_ENTRYPOINT
diff --git a/Help/prop_sf/VS_SETTINGS.rst b/Help/prop_sf/VS_SETTINGS.rst
new file mode 100644
index 0000000..0719406
--- /dev/null
+++ b/Help/prop_sf/VS_SETTINGS.rst
@@ -0,0 +1,18 @@
+VS_SETTINGS
+-----------
+
+Set any item metadata on a non-built file.
+
+Takes a list of ``Key=Value`` pairs. Tells the Visual Studio generator to set
+``Key`` to ``Value`` as item metadata on the file.
+
+For example:
+
+.. code-block:: cmake
+
+  set_property(SOURCE file.hlsl PROPERTY VS_SETTINGS "Key=Value" "Key2=Value2")
+
+will set ``Key`` to ``Value`` and ``Key2`` to ``Value2`` on the
+``file.hlsl`` item as metadata.
+
+Generator expressions are supported.
diff --git a/Help/prop_tgt/VS_SOURCE_SETTINGS_tool.rst b/Help/prop_tgt/VS_SOURCE_SETTINGS_tool.rst
new file mode 100644
index 0000000..f706888
--- /dev/null
+++ b/Help/prop_tgt/VS_SOURCE_SETTINGS_tool.rst
@@ -0,0 +1,19 @@
+VS_SOURCE_SETTINGS_<tool>
+-------------------------
+
+Set any item metadata on all non-built files that use <tool>.
+
+Takes a list of ``Key=Value`` pairs. Tells the Visual Studio generator
+to set ``Key`` to ``Value`` as item metadata on all non-built files
+that use ``<tool>``.
+
+For example:
+
+.. code-block:: cmake
+
+  set_property(TARGET main PROPERTY VS_SOURCE_SETTINGS_FXCompile "Key=Value" "Key2=Value2")
+
+will set ``Key`` to ``Value`` and ``Key2`` to ``Value2`` for all
+non-built files that use ``FXCompile``.
+
+Generator expressions are supported.
diff --git a/Help/release/dev/vs-non-built-file-item-metadata.rst b/Help/release/dev/vs-non-built-file-item-metadata.rst
new file mode 100644
index 0000000..26cbad0
--- /dev/null
+++ b/Help/release/dev/vs-non-built-file-item-metadata.rst
@@ -0,0 +1,10 @@
+vs-non-built-file-item-metadata
+-------------------------------
+
+* The :prop_tgt:`VS_SOURCE_SETTINGS_<tool>` target property was added
+  to tell :ref:`Visual Studio Generators` for VS 2010 and above to add
+  metadata to non-built source files using ``<tool>``.
+
+* The :prop_sf:`VS_SETTINGS` source file property was added to tell
+  :ref:`Visual Studio Generators` for VS 2010 and above to add
+  metadata to a non-built source file.
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index 1273308..abc8b6f 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -1745,20 +1745,65 @@
   }
 }
 
+void cmVisualStudio10TargetGenerator::ParseSettingsProperty(
+  const char* settingsPropertyValue, ConfigToSettings& toolSettings)
+{
+  if (settingsPropertyValue) {
+    cmGeneratorExpression ge;
+
+    std::unique_ptr<cmCompiledGeneratorExpression> cge =
+      ge.Parse(settingsPropertyValue);
+
+    for (const std::string& config : this->Configurations) {
+      std::string evaluated = cge->Evaluate(this->LocalGenerator, config);
+
+      std::vector<std::string> settings = cmExpandedList(evaluated);
+      for (const std::string& setting : settings) {
+        const std::string::size_type assignment = setting.find('=');
+        if (assignment != std::string::npos) {
+          const std::string propName = setting.substr(0, assignment);
+          const std::string propValue = setting.substr(assignment + 1);
+
+          if (!propValue.empty()) {
+            toolSettings[config][propName] = propValue;
+          }
+        }
+      }
+    }
+  }
+}
+
+bool cmVisualStudio10TargetGenerator::PropertyIsSameInAllConfigs(
+  const ConfigToSettings& toolSettings, const std::string& propName)
+{
+  std::string firstPropValue = "";
+  for (const auto& configToSettings : toolSettings) {
+    const std::unordered_map<std::string, std::string>& settings =
+      configToSettings.second;
+
+    if (firstPropValue.empty()) {
+      if (settings.find(propName) != settings.end()) {
+        firstPropValue = settings.find(propName)->second;
+      }
+    }
+
+    if (settings.find(propName) == settings.end()) {
+      return false;
+    }
+
+    if (settings.find(propName)->second != firstPropValue) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
 void cmVisualStudio10TargetGenerator::WriteExtraSource(Elem& e1,
                                                        cmSourceFile const* sf)
 {
   bool toolHasSettings = false;
   const char* tool = "None";
-  std::string shaderType;
-  std::string shaderEntryPoint;
-  std::string shaderModel;
-  std::string shaderAdditionalFlags;
-  std::string shaderDisableOptimizations;
-  std::string shaderEnableDebug;
-  std::string shaderObjectFileName;
-  std::string outputHeaderFile;
-  std::string variableName;
   std::string settingsGenerator;
   std::string settingsLastGenOutput;
   std::string sourceLink;
@@ -1766,6 +1811,11 @@
   std::string copyToOutDir;
   std::string includeInVsix;
   std::string ext = cmSystemTools::LowerCase(sf->GetExtension());
+  ConfigToSettings toolSettings;
+  for (const auto& config : this->Configurations) {
+    toolSettings[config];
+  }
+
   if (this->ProjectType == csproj && !this->InSourceBuild) {
     toolHasSettings = true;
   }
@@ -1773,47 +1823,72 @@
     tool = "FXCompile";
     // Figure out the type of shader compiler to use.
     if (const char* st = sf->GetProperty("VS_SHADER_TYPE")) {
-      shaderType = st;
-      toolHasSettings = true;
+      for (const std::string& config : this->Configurations) {
+        toolSettings[config]["ShaderType"] = st;
+      }
     }
     // Figure out which entry point to use if any
     if (const char* se = sf->GetProperty("VS_SHADER_ENTRYPOINT")) {
-      shaderEntryPoint = se;
-      toolHasSettings = true;
+      for (const std::string& config : this->Configurations) {
+        toolSettings[config]["EntryPointName"] = se;
+      }
     }
     // Figure out which shader model to use if any
     if (const char* sm = sf->GetProperty("VS_SHADER_MODEL")) {
-      shaderModel = sm;
-      toolHasSettings = true;
+      for (const std::string& config : this->Configurations) {
+        toolSettings[config]["ShaderModel"] = sm;
+      }
     }
     // Figure out which output header file to use if any
     if (const char* ohf = sf->GetProperty("VS_SHADER_OUTPUT_HEADER_FILE")) {
-      outputHeaderFile = ohf;
-      toolHasSettings = true;
+      for (const std::string& config : this->Configurations) {
+        toolSettings[config]["HeaderFileOutput"] = ohf;
+      }
     }
     // Figure out which variable name to use if any
     if (const char* vn = sf->GetProperty("VS_SHADER_VARIABLE_NAME")) {
-      variableName = vn;
-      toolHasSettings = true;
+      for (const std::string& config : this->Configurations) {
+        toolSettings[config]["VariableName"] = vn;
+      }
     }
     // Figure out if there's any additional flags to use
     if (const char* saf = sf->GetProperty("VS_SHADER_FLAGS")) {
-      shaderAdditionalFlags = saf;
-      toolHasSettings = true;
+      for (const std::string& config : this->Configurations) {
+        toolSettings[config]["AdditionalOptions"] = saf;
+      }
     }
     // Figure out if debug information should be generated
     if (const char* sed = sf->GetProperty("VS_SHADER_ENABLE_DEBUG")) {
-      shaderEnableDebug = sed;
-      toolHasSettings = true;
+      cmGeneratorExpression ge;
+      std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(sed);
+
+      for (const std::string& config : this->Configurations) {
+        std::string evaluated = cge->Evaluate(this->LocalGenerator, config);
+
+        if (!evaluated.empty()) {
+          toolSettings[config]["EnableDebuggingInformation"] =
+            cmIsOn(evaluated) ? "true" : "false";
+        }
+      }
     }
     // Figure out if optimizations should be disabled
     if (const char* sdo = sf->GetProperty("VS_SHADER_DISABLE_OPTIMIZATIONS")) {
-      shaderDisableOptimizations = sdo;
-      toolHasSettings = true;
+      cmGeneratorExpression ge;
+      std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(sdo);
+
+      for (const std::string& config : this->Configurations) {
+        std::string evaluated = cge->Evaluate(this->LocalGenerator, config);
+
+        if (!evaluated.empty()) {
+          toolSettings[config]["DisableOptimizations"] =
+            cmIsOn(evaluated) ? "true" : "false";
+        }
+      }
     }
     if (const char* sofn = sf->GetProperty("VS_SHADER_OBJECT_FILE_NAME")) {
-      shaderObjectFileName = sofn;
-      toolHasSettings = true;
+      for (const std::string& config : this->Configurations) {
+        toolSettings[config]["ObjectFileOutput"] = sofn;
+      }
     }
   } else if (ext == "jpg" || ext == "png") {
     tool = "Image";
@@ -1883,11 +1958,55 @@
     }
   }
 
+  if (ParsedToolTargetSettings.find(tool) == ParsedToolTargetSettings.end()) {
+    const char* toolTargetProperty =
+      this->GeneratorTarget->Target->GetProperty("VS_SOURCE_SETTINGS_" +
+                                                 std::string(tool));
+    ConfigToSettings toolTargetSettings;
+    ParseSettingsProperty(toolTargetProperty, toolTargetSettings);
+
+    ParsedToolTargetSettings[tool] = toolTargetSettings;
+  }
+
+  for (const auto& configToSetting : ParsedToolTargetSettings[tool]) {
+    for (const auto& setting : configToSetting.second) {
+      toolSettings[configToSetting.first][setting.first] = setting.second;
+    }
+  }
+
+  ParseSettingsProperty(sf->GetProperty("VS_SETTINGS"), toolSettings);
+
+  if (!toolSettings.empty()) {
+    toolHasSettings = true;
+  }
+
   Elem e2(e1, tool);
   this->WriteSource(e2, sf);
   if (toolHasSettings) {
     e2.SetHasElements();
 
+    std::vector<std::string> writtenSettings;
+    for (const auto& configSettings : toolSettings) {
+      for (const auto& setting : configSettings.second) {
+
+        if (std::find(writtenSettings.begin(), writtenSettings.end(),
+                      setting.first) != writtenSettings.end()) {
+          continue;
+        }
+
+        if (PropertyIsSameInAllConfigs(toolSettings, setting.first)) {
+          e2.Element(setting.first, setting.second);
+          writtenSettings.push_back(setting.first);
+        } else {
+          e2.WritePlatformConfigTag(setting.first,
+                                    "'$(Configuration)|$(Platform)'=='" +
+                                      configSettings.first + "|" +
+                                      this->Platform + "'",
+                                    setting.second);
+        }
+      }
+    }
+
     if (!deployContent.empty()) {
       cmGeneratorExpression ge;
       std::unique_ptr<cmCompiledGeneratorExpression> cge =
@@ -1913,73 +2032,7 @@
         }
       }
     }
-    if (!shaderType.empty()) {
-      e2.Element("ShaderType", shaderType);
-    }
-    if (!shaderEntryPoint.empty()) {
-      e2.Element("EntryPointName", shaderEntryPoint);
-    }
-    if (!shaderModel.empty()) {
-      e2.Element("ShaderModel", shaderModel);
-    }
-    if (!outputHeaderFile.empty()) {
-      for (size_t i = 0; i != this->Configurations.size(); ++i) {
-        e2.WritePlatformConfigTag("HeaderFileOutput",
-                                  "'$(Configuration)|$(Platform)'=='" +
-                                    this->Configurations[i] + "|" +
-                                    this->Platform + "'",
-                                  outputHeaderFile);
-      }
-    }
-    if (!variableName.empty()) {
-      for (size_t i = 0; i != this->Configurations.size(); ++i) {
-        e2.WritePlatformConfigTag("VariableName",
-                                  "'$(Configuration)|$(Platform)'=='" +
-                                    this->Configurations[i] + "|" +
-                                    this->Platform + "'",
-                                  variableName);
-      }
-    }
-    if (!shaderEnableDebug.empty()) {
-      cmGeneratorExpression ge;
-      std::unique_ptr<cmCompiledGeneratorExpression> cge =
-        ge.Parse(shaderEnableDebug);
 
-      for (size_t i = 0; i != this->Configurations.size(); ++i) {
-        const std::string& enableDebug =
-          cge->Evaluate(this->LocalGenerator, this->Configurations[i]);
-        if (!enableDebug.empty()) {
-          e2.WritePlatformConfigTag("EnableDebuggingInformation",
-                                    "'$(Configuration)|$(Platform)'=='" +
-                                      this->Configurations[i] + "|" +
-                                      this->Platform + "'",
-                                    cmIsOn(enableDebug) ? "true" : "false");
-        }
-      }
-    }
-    if (!shaderDisableOptimizations.empty()) {
-      cmGeneratorExpression ge;
-      std::unique_ptr<cmCompiledGeneratorExpression> cge =
-        ge.Parse(shaderDisableOptimizations);
-
-      for (size_t i = 0; i != this->Configurations.size(); ++i) {
-        const std::string& disableOptimizations =
-          cge->Evaluate(this->LocalGenerator, this->Configurations[i]);
-        if (!disableOptimizations.empty()) {
-          e2.WritePlatformConfigTag(
-            "DisableOptimizations",
-            "'$(Configuration)|$(Platform)'=='" + this->Configurations[i] +
-              "|" + this->Platform + "'",
-            (cmIsOn(disableOptimizations) ? "true" : "false"));
-        }
-      }
-    }
-    if (!shaderObjectFileName.empty()) {
-      e2.Element("ObjectFileOutput", shaderObjectFileName);
-    }
-    if (!shaderAdditionalFlags.empty()) {
-      e2.Element("AdditionalOptions", shaderAdditionalFlags);
-    }
     if (!settingsGenerator.empty()) {
       e2.Element("Generator", settingsGenerator);
     }
diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h
index 25b3d02..e588de8 100644
--- a/Source/cmVisualStudio10TargetGenerator.h
+++ b/Source/cmVisualStudio10TargetGenerator.h
@@ -10,6 +10,7 @@
 #include <memory>
 #include <set>
 #include <string>
+#include <unordered_map>
 #include <vector>
 
 class cmComputeLinkInformation;
@@ -234,6 +235,15 @@
 
   using ToolSourceMap = std::map<std::string, ToolSources>;
   ToolSourceMap Tools;
+
+  using ConfigToSettings =
+    std::unordered_map<std::string,
+                       std::unordered_map<std::string, std::string>>;
+  std::unordered_map<std::string, ConfigToSettings> ParsedToolTargetSettings;
+  bool PropertyIsSameInAllConfigs(const ConfigToSettings& toolSettings,
+                                  const std::string& propName);
+  void ParseSettingsProperty(const char* settingsPropertyValue,
+                             ConfigToSettings& toolSettings);
   std::string GetCMakeFilePath(const char* name) const;
 };
 
diff --git a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
index 3ca7cc0..5ccca01 100644
--- a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
+++ b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
@@ -31,6 +31,8 @@
 run_cmake(VsPrecompileHeaders)
 run_cmake(VsPrecompileHeadersReuseFromCompilePDBName)
 run_cmake(VsDeployEnabled)
+run_cmake(VsSettings)
+run_cmake(VsSourceSettingsTool)
 
 run_cmake(VsWinRTByDefault)
 
diff --git a/Tests/RunCMake/VS10Project/VsSettings-check.cmake b/Tests/RunCMake/VS10Project/VsSettings-check.cmake
new file mode 100644
index 0000000..0f8b26c
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsSettings-check.cmake
@@ -0,0 +1,23 @@
+macro(ensure_props_set projectFile)
+  if(NOT EXISTS "${projectFile}")
+    set(RunCMake_TEST_FAILED "Project file ${projectFile} does not exist.")
+    return()
+  endif()
+
+  set(SettingFound FALSE)
+
+  file(STRINGS "${projectFile}" lines)
+  foreach(line IN LISTS lines)
+    if(line MATCHES "<SourceProperty1.*Debug.*>SourceProperty1Value</SourceProperty1>")
+      message("SourceProperty1 setting found")
+      set(SettingFound TRUE)
+    endif()
+  endforeach()
+
+  if (NOT SettingFound)
+    set(RunCMake_TEST_FAILED "SourceProperty1 setting was not found")
+    return()
+  endif()
+endmacro()
+
+ensure_props_set("${RunCMake_TEST_BINARY_DIR}/foo.vcxproj")
diff --git a/Tests/RunCMake/VS10Project/VsSettings.cmake b/Tests/RunCMake/VS10Project/VsSettings.cmake
new file mode 100644
index 0000000..a4b321b
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsSettings.cmake
@@ -0,0 +1,5 @@
+enable_language(CXX)
+
+add_library(foo foo.cpp shader.hlsl)
+set_property(SOURCE shader.hlsl PROPERTY VS_SETTINGS
+  "$<$<CONFIG:DEBUG>:SourceProperty1=SourceProperty1Value>")
diff --git a/Tests/RunCMake/VS10Project/VsSourceSettingsTool-check.cmake b/Tests/RunCMake/VS10Project/VsSourceSettingsTool-check.cmake
new file mode 100644
index 0000000..29a89c3
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsSourceSettingsTool-check.cmake
@@ -0,0 +1,34 @@
+macro(ensure_props_set projectFile)
+  if(NOT EXISTS "${projectFile}")
+    set(RunCMake_TEST_FAILED "Project file ${projectFile} does not exist.")
+    return()
+  endif()
+
+  set(FirstSettingFound FALSE)
+  set(SecondSettingFound FALSE)
+
+  file(STRINGS "${projectFile}" lines)
+  foreach(line IN LISTS lines)
+    if(line MATCHES "<TargetProperty1.*Debug.*>TargetProperty1ValueDebug</TargetProperty1>")
+      if (FirstSettingFound)
+        message("TargetProperty1 setting found twice")
+        set(SecondSettingFound TRUE)
+      else()
+        message("TargetProperty1 setting found once")
+        set(FirstSettingFound TRUE)
+      endif()
+    endif()
+  endforeach()
+
+  if (NOT FirstSettingFound)
+    set(RunCMake_TEST_FAILED "TargetProperty1 setting not found at all")
+    return()
+  endif()
+
+  if (NOT SecondSettingFound)
+    set(RunCMake_TEST_FAILED "TargetProperty1 setting found once when it should be found twice")
+    return()
+  endif()
+endmacro()
+
+ensure_props_set("${RunCMake_TEST_BINARY_DIR}/foo.vcxproj")
diff --git a/Tests/RunCMake/VS10Project/VsSourceSettingsTool.cmake b/Tests/RunCMake/VS10Project/VsSourceSettingsTool.cmake
new file mode 100644
index 0000000..498962f
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsSourceSettingsTool.cmake
@@ -0,0 +1,5 @@
+enable_language(CXX)
+
+add_library(foo foo.cpp shader.hlsl shader2.hlsl)
+set_property(TARGET foo PROPERTY VS_SOURCE_SETTINGS_FXCompile
+  "$<$<CONFIG:DEBUG>:TargetProperty1=TargetProperty1ValueDebug>")
diff --git a/Tests/RunCMake/VS10Project/shader.hlsl b/Tests/RunCMake/VS10Project/shader.hlsl
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/shader.hlsl
@@ -0,0 +1 @@
+
diff --git a/Tests/RunCMake/VS10Project/shader2.hlsl b/Tests/RunCMake/VS10Project/shader2.hlsl
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/shader2.hlsl
@@ -0,0 +1 @@
+
diff --git a/Tests/VSWinStorePhone/CMakeLists.txt b/Tests/VSWinStorePhone/CMakeLists.txt
index b8e157d..558d5de 100644
--- a/Tests/VSWinStorePhone/CMakeLists.txt
+++ b/Tests/VSWinStorePhone/CMakeLists.txt
@@ -127,7 +127,7 @@
 set_property(SOURCE ${VERTEXSHADER_FILES} PROPERTY VS_SHADER_MODEL 4.0_level_9_3)
 set_property(SOURCE ${VERTEXSHADER_FILES} PROPERTY VS_SHADER_FLAGS "/DFLAGS_ADDED")
 set_property(SOURCE ${VERTEXSHADER_FILES} PROPERTY VS_SHADER_OUTPUT_HEADER_FILE "$(OutDir)%(Filename).h")
-
+set_property(SOURCE ${VERTEXSHADER_FILES} PROPERTY VS_SETTINGS "$<$<CONFIG:DEBUG>:SourceProperty1=SourceProperty1Value>")
 
 source_group("Source Files" FILES ${SOURCE_FILES})
 source_group("Header Files" FILES ${HEADER_FILES})
@@ -135,6 +135,11 @@
 
 add_executable(${EXE_NAME} WIN32 ${SOURCE_FILES} ${HEADER_FILES} ${RESOURCE_FILES})
 set_property(TARGET ${EXE_NAME} PROPERTY VS_WINRT_COMPONENT TRUE)
+set_property(TARGET ${EXE_NAME} PROPERTY VS_SOURCE_SETTINGS_FXCompile
+  "TargetProperty1=$<$<CONFIG:DEBUG>:TargetProperty1ValueDebug>$<$<CONFIG:RELEASE>:TargetProperty1ValueRelease>")
+
+add_custom_command(TARGET ${EXE_NAME} POST_BUILD
+  COMMAND ${CMAKE_COMMAND} -Dvcxproj="${CMAKE_CURRENT_BINARY_DIR}/${EXE_NAME}.vcxproj" -P "${CMAKE_CURRENT_SOURCE_DIR}/EnsurePropertiesSet.cmake")
 
 string(SUBSTRING "${CMAKE_SYSTEM_VERSION}" 0, 4, SHORT_VERSION)
 
diff --git a/Tests/VSWinStorePhone/EnsurePropertiesSet.cmake b/Tests/VSWinStorePhone/EnsurePropertiesSet.cmake
new file mode 100644
index 0000000..528c46f
--- /dev/null
+++ b/Tests/VSWinStorePhone/EnsurePropertiesSet.cmake
@@ -0,0 +1,45 @@
+macro(ensure_props_set projectFile)
+  if(NOT EXISTS "${projectFile}")
+    message(FATAL_ERROR "Project file ${projectFile} does not exist.")
+    return()
+  endif()
+
+  set(SourcePropertyFound FALSE)
+  set(DebugTargetPropertyFound FALSE)
+  set(ReleaseTargetPropertyFound FALSE)
+
+  file(STRINGS "${projectFile}" lines)
+  foreach(line IN LISTS lines)
+    if(line MATCHES "<SourceProperty1.*Debug.*>SourceProperty1Value</SourceProperty1>")
+      message("SourceProperty1 setting found")
+      set(SourcePropertyFound TRUE)
+    endif()
+
+    if(line MATCHES "<TargetProperty1.*Debug.*>TargetProperty1ValueDebug</TargetProperty1>")
+      message("Debug TargetProperty1 setting found")
+      set(DebugTargetPropertyFound TRUE)
+    endif()
+
+    if(line MATCHES "<TargetProperty1.*Release.*>TargetProperty1ValueRelease</TargetProperty1>")
+      message("Release TargetProperty1 setting found")
+      set(ReleaseTargetPropertyFound TRUE)
+    endif()
+  endforeach()
+
+  if (NOT SourcePropertyFound)
+    message(FATAL_ERROR "SourceProperty1 setting not found")
+    return()
+  endif()
+
+  if (NOT DebugTargetPropertyFound)
+    message(FATAL_ERROR "Debug TargetProperty1 setting not found")
+    return()
+  endif()
+
+  if (NOT ReleaseTargetPropertyFound)
+    message(FATAL_ERROR "Release TargetProperty1 setting not found")
+    return()
+  endif()
+endmacro()
+
+ensure_props_set("${vcxproj}")