Introduce ExampleExtension for testing
Rob Mensching committed
Dec 1, 2017 at 01:09 UTC
720c4a0db1a2fb2aa3e08e5c99d5198873e448ba
15 files changed
+401
src/WixToolset.Core/ExtensibilityServices/ParseHelper.cs
+5
@@ -633,6 +633,11 @@ namespace WixToolset.Core.ExtensibilityServices
633
}
634
}
635
636
+ public SourceLineNumber GetSourceLineNumbers(XElement element)
637
+ {
638
+ return Preprocessor.GetSourceLineNumbers(element);
639
+ }
640
+
641
public string GetConditionInnerText(XElement element)
642
{
643
var value = Common.GetInnerText(element)?.Trim().Replace('\t', ' ').Replace('\r', ' ').Replace('\n', ' ');
src/WixToolset.Core/ExtensibilityServices/TupleDefinitionCreator.cs
+15
@@ -19,8 +19,16 @@ namespace WixToolset.Core.ExtensibilityServices
19
20
private IEnumerable<IExtensionData> ExtensionData { get; set; }
21
22
+ private Dictionary<string, IntermediateTupleDefinition> CustomDefinitionByName { get; } = new Dictionary<string, IntermediateTupleDefinition>();
23
+
24
+ public void AddCustomTupleDefinition(IntermediateTupleDefinition definition)
25
+ {
26
+ this.CustomDefinitionByName.Add(definition.Name, definition);
27
+ }
28
+
29
public bool TryGetTupleDefinitionByName(string name, out IntermediateTupleDefinition tupleDefinition)
30
{
31
+ // First, look in the built-ins.
32
tupleDefinition = TupleDefinitions.ByName(name);
33
34
if (tupleDefinition == null)
@@ -30,6 +38,7 @@ namespace WixToolset.Core.ExtensibilityServices
38
this.LoadExtensionData();
39
}
40
41
+ // Second, look in the extensions.
42
foreach (var data in this.ExtensionData)
43
{
44
if (data.TryGetTupleDefinitionByName(name, out tupleDefinition))
@@ -37,6 +46,12 @@ namespace WixToolset.Core.ExtensibilityServices
46
break;
47
}
48
}
49
+
50
+ // Finally, look in the custom tuple definitions provided during an intermediate load.
51
+ if (tupleDefinition == null)
52
+ {
53
+ this.CustomDefinitionByName.TryGetValue(name, out tupleDefinition);
54
+ }
55
}
56
57
return tupleDefinition != null;
src/test/Example.Extension/Example.Extension.csproj
new
+18
@@ -0,0 +1,18 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
+
4
+<Project Sdk="Microsoft.NET.Sdk">
5
+ <PropertyGroup>
6
+ <TargetFramework>netstandard2.0</TargetFramework>
7
+ <IsPackable>false</IsPackable>
8
+ </PropertyGroup>
9
+
10
+ <ItemGroup>
11
+ <ProjectReference Include="$(WixToolsetRootFolder)\Data\src\WixToolset.Data\WixToolset.Data.csproj" Condition=" '$(Configuration)' == 'Debug' And Exists('$(WixToolsetRootFolder)\Data\src\WixToolset.Data\WixToolset.Data.csproj') " />
12
+ <PackageReference Include="WixToolset.Data" Version="4.0.*" Condition=" '$(Configuration)' == 'Release' Or !Exists('$(WixToolsetRootFolder)\Data\src\WixToolset.Data\WixToolset.Data.csproj') " />
13
+
14
+ <ProjectReference Include="$(WixToolsetRootFolder)\Extensibility\src\WixToolset.Extensibility\WixToolset.Extensibility.csproj" Condition=" '$(Configuration)' == 'Debug' And Exists('$(WixToolsetRootFolder)\Extensibility\src\WixToolset.Extensibility\WixToolset.Extensibility.csproj') " />
15
+ <PackageReference Include="WixToolset.Extensibility" Version="4.0.*" Condition=" '$(Configuration)' == 'Release' Or !Exists('$(WixToolsetRootFolder)\Extensibility\src\WixToolset.Extensibility\WixToolset.Extensibility.csproj') " />
16
+ </ItemGroup>
17
+
18
+</Project>
src/test/Example.Extension/ExampleCompilerExtension.cs
new
+84
@@ -0,0 +1,84 @@
1
+// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
+
3
+namespace Example.Extension
4
+{
5
+ using System;
6
+ using System.Collections.Generic;
7
+ using System.Xml.Linq;
8
+ using WixToolset.Data;
9
+ using WixToolset.Extensibility;
10
+
11
+ internal class ExampleCompilerExtension : BaseCompilerExtension
12
+ {
13
+ public ExampleCompilerExtension()
14
+ {
15
+ this.Namespace = "http://www.example.com/scheams/v1/wxs";
16
+ }
17
+
18
+ public override void ParseElement(Intermediate intermediate, IntermediateSection section, XElement parentElement, XElement element, IDictionary<string, string> context)
19
+ {
20
+ var processed = false;
21
+
22
+ switch (parentElement.Name.LocalName)
23
+ {
24
+ case "Component":
25
+ switch (element.Name.LocalName)
26
+ {
27
+ case "Example":
28
+ this.ParseExampleElement(intermediate, section, element);
29
+ processed = true;
30
+ break;
31
+ }
32
+ break;
33
+ }
34
+
35
+ if (!processed)
36
+ {
37
+ base.ParseElement(intermediate, section, parentElement, element, context);
38
+ }
39
+ }
40
+
41
+ private void ParseExampleElement(Intermediate intermediate, IntermediateSection section, XElement element)
42
+ {
43
+ var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
44
+ Identifier id = null;
45
+ string value = null;
46
+
47
+ foreach (var attrib in element.Attributes())
48
+ {
49
+ if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
50
+ {
51
+ switch (attrib.Name.LocalName)
52
+ {
53
+ case "Id":
54
+ id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
55
+ break;
56
+
57
+ case "Value":
58
+ value = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
59
+ break;
60
+
61
+ default:
62
+ this.ParseHelper.UnexpectedAttribute(element, attrib);
63
+ break;
64
+ }
65
+ }
66
+ else
67
+ {
68
+ this.ParseAttribute(intermediate, section, element, attrib, null);
69
+ }
70
+ }
71
+
72
+ if (null == id)
73
+ {
74
+ //this.Messaging(WixErrors.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Id"));
75
+ }
76
+
77
+ if (!this.Messaging.EncounteredError)
78
+ {
79
+ var tuple = this.ParseHelper.CreateRow(section, sourceLineNumbers, "Example", id);
80
+ tuple.Set(1, value);
81
+ }
82
+ }
83
+ }
84
+}
src/test/Example.Extension/ExampleExtensionData.cs
new
+33
@@ -0,0 +1,33 @@
1
+// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
+
3
+namespace Example.Extension
4
+{
5
+ using WixToolset.Data;
6
+ using WixToolset.Extensibility;
7
+
8
+ internal class ExampleExtensionData : IExtensionData
9
+ {
10
+ public string DefaultCulture => null;
11
+
12
+ public Intermediate GetLibrary(ITupleDefinitionCreator tupleDefinitions)
13
+ {
14
+ return null;
15
+ }
16
+
17
+ public bool TryGetTupleDefinitionByName(string name, out IntermediateTupleDefinition tupleDefinition)
18
+ {
19
+ switch (name)
20
+ {
21
+ case "Example":
22
+ tupleDefinition = TupleDefinitions.Example;
23
+ break;
24
+
25
+ default:
26
+ tupleDefinition = null;
27
+ break;
28
+ }
29
+
30
+ return tupleDefinition != null;
31
+ }
32
+ }
33
+}
\ No newline at end of file
src/test/Example.Extension/ExampleExtensionFactory.cs
new
+32
@@ -0,0 +1,32 @@
1
+// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
+
3
+namespace Example.Extension
4
+{
5
+ using System;
6
+ using WixToolset.Extensibility;
7
+
8
+ public class ExampleExtensionFactory : IExtensionFactory
9
+ {
10
+ public bool TryCreateExtension(Type extensionType, out object extension)
11
+ {
12
+ if (extensionType == typeof(IPreprocessorExtension))
13
+ {
14
+ extension = new ExamplePreprocessorExtension();
15
+ }
16
+ else if (extensionType == typeof(ICompilerExtension))
17
+ {
18
+ extension = new ExampleCompilerExtension();
19
+ }
20
+ else if (extensionType == typeof(IExtensionData))
21
+ {
22
+ extension = new ExampleExtensionData();
23
+ }
24
+ else
25
+ {
26
+ extension = null;
27
+ }
28
+
29
+ return extension != null;
30
+ }
31
+ }
32
+}
src/test/Example.Extension/ExamplePreprocessorExtension.cs
new
+55
@@ -0,0 +1,55 @@
1
+// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
+
3
+namespace Example.Extension
4
+{
5
+ using System;
6
+ using System.Xml.Linq;
7
+ using WixToolset.Data;
8
+ using WixToolset.Extensibility;
9
+
10
+ internal class ExamplePreprocessorExtension : IPreprocessorExtension
11
+ {
12
+ public ExamplePreprocessorExtension()
13
+ {
14
+ }
15
+
16
+ public IPreprocessorCore Core { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
17
+
18
+ public string[] Prefixes => throw new NotImplementedException();
19
+
20
+ public string EvaluateFunction(string prefix, string function, string[] args)
21
+ {
22
+ throw new NotImplementedException();
23
+ }
24
+
25
+ public void Finish()
26
+ {
27
+ throw new NotImplementedException();
28
+ }
29
+
30
+ public string GetVariableValue(string prefix, string name)
31
+ {
32
+ throw new NotImplementedException();
33
+ }
34
+
35
+ public void Initialize()
36
+ {
37
+ throw new NotImplementedException();
38
+ }
39
+
40
+ public void PreprocessDocument(XDocument document)
41
+ {
42
+ throw new NotImplementedException();
43
+ }
44
+
45
+ public string PreprocessParameter(string name)
46
+ {
47
+ throw new NotImplementedException();
48
+ }
49
+
50
+ public bool ProcessPragma(SourceLineNumber sourceLineNumbers, string prefix, string pragma, string args, XContainer parent)
51
+ {
52
+ throw new NotImplementedException();
53
+ }
54
+ }
55
+}
\ No newline at end of file
src/test/Example.Extension/ExampleTuple.cs
new
+31
@@ -0,0 +1,31 @@
1
+// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
+
3
+namespace Example.Extension
4
+{
5
+ using WixToolset.Data;
6
+
7
+ public enum ExampleTupleFields
8
+ {
9
+ Example,
10
+ Value,
11
+ }
12
+
13
+ public class ExampleTuple : IntermediateTuple
14
+ {
15
+ public ExampleTuple() : base(TupleDefinitions.Example, null, null)
16
+ {
17
+ }
18
+
19
+ public ExampleTuple(SourceLineNumber sourceLineNumber, Identifier id = null) : base(TupleDefinitions.Example, sourceLineNumber, id)
20
+ {
21
+ }
22
+
23
+ public IntermediateField this[ExampleTupleFields index] => this.Fields[(int)index];
24
+
25
+ public string Value
26
+ {
27
+ get => this.Fields[(int)ExampleTupleFields.Value]?.AsString();
28
+ set => this.Set((int)ExampleTupleFields.Value, value);
29
+ }
30
+ }
31
+}
src/test/Example.Extension/TupleDefinitions.cs
new
+18
@@ -0,0 +1,18 @@
1
+// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
+
3
+namespace Example.Extension
4
+{
5
+ using WixToolset.Data;
6
+
7
+ public static class TupleDefinitions
8
+ {
9
+ public static readonly IntermediateTupleDefinition Example = new IntermediateTupleDefinition(
10
+ "Example",
11
+ new[]
12
+ {
13
+ new IntermediateFieldDefinition(nameof(ExampleTupleFields.Example), IntermediateFieldType.String),
14
+ new IntermediateFieldDefinition(nameof(ExampleTupleFields.Value), IntermediateFieldType.String),
15
+ },
16
+ typeof(ExampleTuple));
17
+ }
18
+}
src/test/WixToolsetTest.CoreIntegration/ExtensionFixture.cs
new
+60
@@ -0,0 +1,60 @@
1
+// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
+
3
+namespace WixToolsetTest.CoreIntegration
4
+{
5
+ using System;
6
+ using System.IO;
7
+ using System.Linq;
8
+ using Example.Extension;
9
+ using WixToolset.Core;
10
+ using WixToolset.Data;
11
+ using WixToolset.Data.Tuples;
12
+ using WixToolsetTest.CoreIntegration.Utility;
13
+ using Xunit;
14
+
15
+ public class ExtensionFixture
16
+ {
17
+ [Fact]
18
+ public void CanBuildWithExampleExtension()
19
+ {
20
+ var folder = TestData.Get(@"TestData\ExampleExtension");
21
+ var extensionPath = Path.GetFullPath(new Uri(typeof(ExampleExtensionFactory).Assembly.CodeBase).LocalPath);
22
+
23
+ using (var fs = new DisposableFileSystem())
24
+ {
25
+ var intermediateFolder = fs.GetFolder();
26
+
27
+ var program = new Program();
28
+ var result = program.Run(new WixToolsetServiceProvider(), new[]
29
+ {
30
+ "build",
31
+ Path.Combine(folder, "Package.wxs"),
32
+ Path.Combine(folder, "PackageComponents.wxs"),
33
+ "-loc", Path.Combine(folder, "Package.en-us.wxl"),
34
+ "-ext", extensionPath,
35
+ "-bindpath", Path.Combine(folder, "data"),
36
+ "-intermediateFolder", intermediateFolder,
37
+ "-o", Path.Combine(intermediateFolder, @"bin\extest.msi")
38
+ });
39
+
40
+ Assert.Equal(0, result);
41
+
42
+ Assert.True(File.Exists(Path.Combine(intermediateFolder, @"bin\extest.msi")));
43
+ Assert.True(File.Exists(Path.Combine(intermediateFolder, @"bin\extest.wixpdb")));
44
+ Assert.True(File.Exists(Path.Combine(intermediateFolder, @"bin\MsiPackage\example.txt")));
45
+
46
+ var intermediate = Intermediate.Load(Path.Combine(intermediateFolder, @"bin\extest.wir"));
47
+ Assert.Single(intermediate.Sections);
48
+
49
+ var wixFile = intermediate.Sections.SelectMany(s => s.Tuples).OfType<WixFileTuple>().Single();
50
+ Assert.Equal(Path.Combine(folder, @"data\example.txt"), wixFile[WixFileTupleFields.Source].AsPath().Path);
51
+ Assert.Equal(@"example.txt", wixFile[WixFileTupleFields.Source].PreviousValue.AsPath().Path);
52
+
53
+ var example = intermediate.Sections.SelectMany(s => s.Tuples).Where(t => t.Definition.Type == TupleDefinitionType.MustBeFromAnExtension).Single();
54
+ Assert.Equal("Foo", example.Id.Id);
55
+ Assert.Equal("Foo", example[0].AsString());
56
+ Assert.Equal("Bar", example[1].AsString());
57
+ }
58
+ }
59
+ }
60
+}
src/test/WixToolsetTest.CoreIntegration/TestData/ExampleExtension/Package.en-us.wxl
new
+11
@@ -0,0 +1,11 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+
3
+<!--
4
+This file contains the declaration of all the localizable strings.
5
+-->
6
+<WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="en-US">
7
+
8
+ <String Id="DowngradeError">A newer version of [ProductName] is already installed.</String>
9
+ <String Id="FeatureTitle">MsiPackage</String>
10
+
11
+</WixLocalization>
src/test/WixToolsetTest.CoreIntegration/TestData/ExampleExtension/Package.wxs
new
+21
@@ -0,0 +1,21 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3
+ <Product Id="*" Name="MsiPackage" Language="1033" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a">
4
+ <Package InstallerVersion="200" Compressed="no" InstallScope="perMachine" />
5
+
6
+ <MajorUpgrade DowngradeErrorMessage="!(loc.DowngradeError)" />
7
+ <MediaTemplate />
8
+
9
+ <Feature Id="ProductFeature" Title="!(loc.FeatureTitle)">
10
+ <ComponentGroupRef Id="ProductComponents" />
11
+ </Feature>
12
+ </Product>
13
+
14
+ <Fragment>
15
+ <Directory Id="TARGETDIR" Name="SourceDir">
16
+ <Directory Id="ProgramFilesFolder">
17
+ <Directory Id="INSTALLFOLDER" Name="MsiPackage" />
18
+ </Directory>
19
+ </Directory>
20
+ </Fragment>
21
+</Wix>
src/test/WixToolsetTest.CoreIntegration/TestData/ExampleExtension/PackageComponents.wxs
new
+12
@@ -0,0 +1,12 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"
3
+ xmlns:ex="http://www.example.com/scheams/v1/wxs">
4
+ <Fragment>
5
+ <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
6
+ <Component>
7
+ <File Source="example.txt" />
8
+ <ex:Example Id="Foo" Value="Bar" />
9
+ </Component>
10
+ </ComponentGroup>
11
+ </Fragment>
12
+</Wix>
src/test/WixToolsetTest.CoreIntegration/TestData/ExampleExtension/data/example.txt
new
+1
@@ -0,0 +1 @@
1
+This is example.txt.
\ No newline at end of file
src/test/WixToolsetTest.CoreIntegration/WixToolsetTest.CoreIntegration.csproj
+5
@@ -15,6 +15,10 @@
15
<Content Include="TestData\InstanceTransform\Package.en-us.wxl" CopyToOutputDirectory="PreserveNewest" />
16
<Content Include="TestData\InstanceTransform\Package.wxs" CopyToOutputDirectory="PreserveNewest" />
17
<Content Include="TestData\InstanceTransform\PackageComponents.wxs" CopyToOutputDirectory="PreserveNewest" />
18
+ <Content Include="TestData\ExampleExtension\data\example.txt" CopyToOutputDirectory="PreserveNewest" />
19
+ <Content Include="TestData\ExampleExtension\Package.en-us.wxl" CopyToOutputDirectory="PreserveNewest" />
20
+ <Content Include="TestData\ExampleExtension\Package.wxs" CopyToOutputDirectory="PreserveNewest" />
21
+ <Content Include="TestData\ExampleExtension\PackageComponents.wxs" CopyToOutputDirectory="PreserveNewest" />
22
<Content Include="TestData\SingleFile\data\test.txt" CopyToOutputDirectory="PreserveNewest" />
23
<Content Include="TestData\SingleFile\Package.en-us.wxl" CopyToOutputDirectory="PreserveNewest" />
24
<Content Include="TestData\SingleFile\Package.wxs" CopyToOutputDirectory="PreserveNewest" />
@@ -23,6 +27,7 @@
27
28
<ItemGroup>
29
<ProjectReference Include="..\..\wix\wix.csproj" />
30
+ <ProjectReference Include="..\Example.Extension\Example.Extension.csproj" />
31
</ItemGroup>
32
33
<ItemGroup>