* Expression.cs (ExpressionOptions): New.
Introduce a ExpressionOptions argument to all ConvertTo*
methods. Implement the rule: in evaluation phase, expand
all items completely, but dont expand item refs in properties.
At other times, expand the item refs in the properties.
See comments in Expression.cs, for a full explanation.
* BuildItem.cs: Track api changes.
* BuildItemGroup.cs: Likewise.
* BuildProperty.cs: Track api changes. Handle self-references.
* BuildTask.cs: Track api changes.
* IReference.cs: Add ExpressionOptions param.
* ItemReference.cs: Track api changes.
* PropertyReference.cs: Likewise.
* MetadataReference.cs: Likewise.
* ExpressionCollection.cs: Track api changes. Add support for
converting all primitive types and DateTime, instead of a fixed
few.
* Project.cs (GetMetadataBatched): Use the evaluated metadata.
* TaskBatchingImpl.cs: Handle the case when batching is required,
but no items are available.
* TaskEngine.cs: Throw on unsupported types. Correctly handle
properties in case of empty values.
In class/Microsoft.Build.Engine/Test/Microsoft.Build.BuildEngine:
* BuildItemTest.cs (TestSetMetadata5a): New.
* ProjectTest.cs: Add tests for different property types
with required attribute. Also, check the values - null or
empty array.
* TestTasks.cs: Add new tasks for above.
In class/Microsoft.Build.Engine/Test/resources:
* TestTasks.cs: Add new tasks for different property types
with required attribute. Also, emit whether the value was
null or a zero length array.
In class/Microsoft.Build.Engine/Test/various:
* Items.cs: Add tests for property/item evaluation.
svn path=/trunk/mcs/; revision=140911
if (parent_item_group != null) {
Expression e = new Expression ();
e.Parse (value, true);
- evaluatedMetadata [name] = (string) e.ConvertTo (parent_item_group.ParentProject, typeof (string));
+ evaluatedMetadata [name] = (string) e.ConvertTo (parent_item_group.ParentProject,
+ typeof (string), ExpressionOptions.ExpandItemRefs);
} else
evaluatedMetadata [name] = Utilities.Unescape (value);
excludeExpr = new Expression ();
excludeExpr.Parse (Exclude, true);
- includes = (string) includeExpr.ConvertTo (project, typeof (string));
- excludes = (string) excludeExpr.ConvertTo (project, typeof (string));
+ includes = (string) includeExpr.ConvertTo (project, typeof (string), ExpressionOptions.ExpandItemRefs);
+ excludes = (string) excludeExpr.ConvertTo (project, typeof (string), ExpressionOptions.ExpandItemRefs);
this.finalItemSpec = includes;
big.AddItem (bi);
}
- internal string ConvertToString (Expression transform)
+ // during item's eval phase, any item refs in this item, have either
+ // already been expanded or are non-existant, so expand can be _false_
+ //
+ // during prop's eval phase, this isn't reached, as it parses expressions
+ // with allowItems=false, so no ItemReferences are created at all
+ //
+ // at other times, item refs have already been expanded, so expand: false
+ internal string ConvertToString (Expression transform, ExpressionOptions options)
{
- return GetItemSpecFromTransform (transform);
+ return GetItemSpecFromTransform (transform, options);
}
- internal ITaskItem ConvertToITaskItem (Expression transform)
+ internal ITaskItem ConvertToITaskItem (Expression transform, ExpressionOptions options)
{
TaskItem taskItem;
- taskItem = new TaskItem (GetItemSpecFromTransform (transform), evaluatedMetadata);
+ taskItem = new TaskItem (GetItemSpecFromTransform (transform, options), evaluatedMetadata);
return taskItem;
}
}
}
- string GetItemSpecFromTransform (Expression transform)
+ string GetItemSpecFromTransform (Expression transform, ExpressionOptions options)
{
StringBuilder sb;
- if (transform == null)
- return finalItemSpec;
- else {
+ if (transform == null) {
+ if (options == ExpressionOptions.ExpandItemRefs) {
+ // With usual code paths, this will never execute,
+ // but letting this be here, incase BI.ConvertTo*
+ // is called directly
+ Expression expr = new Expression ();
+ expr.Parse (finalItemSpec, true);
+
+ return (string) expr.ConvertTo (parent_item_group.ParentProject,
+ typeof (string), ExpressionOptions.ExpandItemRefs);
+ } else {
+ return finalItemSpec;
+ }
+ } else {
+ // Transform, _DONT_ expand itemrefs
sb = new StringBuilder ();
foreach (object o in transform.Collection) {
if (o is string) {
sb.Append ((string)o);
} else if (o is PropertyReference) {
- sb.Append (((PropertyReference)o).ConvertToString (parent_item_group.ParentProject));
+ sb.Append (((PropertyReference)o).ConvertToString (
+ parent_item_group.ParentProject,
+ ExpressionOptions.DoNotExpandItemRefs));
} else if (o is ItemReference) {
- sb.Append (((ItemReference)o).ConvertToString (parent_item_group.ParentProject));
+ sb.Append (((ItemReference)o).ConvertToString (
+ parent_item_group.ParentProject,
+ ExpressionOptions.DoNotExpandItemRefs));
} else if (o is MetadataReference) {
sb.Append (GetMetadata (((MetadataReference)o).MetadataName));
}
buildItems.Add (buildItem);
}
+ // In eval phase, any ref'ed item would've already been expanded
+ // or it doesnt exist, so dont expand again
+ // In non-eval, items have _already_ been expanded, so dont expand again
+ // So, ignore @options
internal string ConvertToString (Expression transform,
- Expression separator)
+ Expression separator, ExpressionOptions options)
{
string separatorString;
+ // Item refs are not expanded for separator or transform
if (separator == null)
separatorString = ";";
else
- separatorString = (string) separator.ConvertTo (parentProject, typeof (string));
+ separatorString = (string) separator.ConvertTo (parentProject, typeof (string),
+ ExpressionOptions.DoNotExpandItemRefs);
string[] items = new string [buildItems.Count];
int i = 0;
foreach (BuildItem bi in buildItems)
- items [i++] = bi.ConvertToString (transform);
+ items [i++] = bi.ConvertToString (transform, ExpressionOptions.DoNotExpandItemRefs);
return String.Join (separatorString, items);
}
- internal ITaskItem[] ConvertToITaskItemArray (Expression transform)
+ // In eval phase, any ref'ed item would've already been expanded
+ // or it doesnt exist, so dont expand again
+ // In non-eval, items have _already_ been expanded, so dont expand again
+ // So, ignore @options
+ internal ITaskItem[] ConvertToITaskItemArray (Expression transform, ExpressionOptions options)
{
ITaskItem[] array = new ITaskItem [buildItems.Count];
int i = 0;
foreach (BuildItem item in buildItems)
- array [i++] = item.ConvertToITaskItem (transform);
+ array [i++] = item.ConvertToITaskItem (transform, ExpressionOptions.DoNotExpandItemRefs);
return array;
}
//
// Author:
// Marek Sieradzki (marek.sieradzki@gmail.com)
+// Ankit Jain (jankit@novell.com)
//
// (C) 2005 Marek Sieradzki
+// Copyright 2009 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
using System.Xml;
using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
namespace Microsoft.Build.BuildEngine {
public class BuildProperty {
string name;
Project parentProject;
PropertyType propertyType;
+ bool converting;
BuildProperty ()
{
{
BuildProperty evaluated = new BuildProperty (Name, Value);
+ // In evaluate phase, properties are not expanded
Expression exp = new Expression ();
exp.Parse (Value, false, false);
- evaluated.finalValue = (string) exp.ConvertTo (parentProject, typeof (string));
+ evaluated.finalValue = (string) exp.ConvertTo (parentProject, typeof (string),
+ ExpressionOptions.DoNotExpandItemRefs);
parentProject.EvaluatedProperties.AddProperty (evaluated);
}
- internal string ConvertToString (Project project)
+ // during property's eval phase, this is never reached, as PropertyReference
+ // handles the eval case
+ //
+ // during item's eval phase, we have expand: true, that's what we
+ // do here..
+ //
+ // during non-eval, expand: true
+ // So, its always true here
+ internal string ConvertToString (Project project, ExpressionOptions options)
{
- Expression exp = new Expression ();
- exp.Parse (Value, true, false);
+ if (converting) {
+ // found ref to @this while trying to ConvertToString
+ // for @this!
+ return FinalValue;
+ }
- return (string) exp.ConvertTo (project, typeof (string));
+ converting = true;
+ try {
+ Expression exp = new Expression ();
+
+ // in non-evaluation phase, properties are always expanded
+ exp.Parse (FinalValue, options == ExpressionOptions.ExpandItemRefs, false);
+ return (string) exp.ConvertTo (project, typeof (string), options);
+ } finally {
+ converting = false;
+ }
}
- internal ITaskItem[] ConvertToITaskItemArray (Project project)
+ internal ITaskItem[] ConvertToITaskItemArray (Project project, ExpressionOptions options)
{
- Expression exp = new Expression ();
- exp.Parse (Value, true, false);
+ if (converting) {
+ // found ref to @this while trying to ConvertToITaskItemArray
+ // for @this!
+ ITaskItem []items = new ITaskItem [1];
+ items [0] = new TaskItem (FinalValue);
+ return items;
+ }
- return (ITaskItem[]) exp.ConvertTo (project, typeof (ITaskItem[]));
+ converting = true;
+ try {
+ Expression exp = new Expression ();
+
+ // in non-evaluation phase, properties are always expanded
+ exp.Parse (FinalValue, options == ExpressionOptions.ExpandItemRefs, false);
+ return (ITaskItem[]) exp.ConvertTo (project, typeof (ITaskItem[]), options);
+ } finally {
+ converting = false;
+ }
}
internal bool FromXml {
else {
Expression exp = new Expression ();
exp.Parse (str, true);
- return (bool) exp.ConvertTo (parentTarget.Project, typeof (bool));
+ return (bool) exp.ConvertTo (parentTarget.Project, typeof (bool),
+ ExpressionOptions.ExpandItemRefs);
}
}
set {
+2009-08-29 Ankit Jain <jankit@novell.com>
+
+ * Expression.cs (ExpressionOptions): New.
+
+ Introduce a ExpressionOptions argument to all ConvertTo*
+ methods. Implement the rule: in evaluation phase, expand
+ all items completely, but dont expand item refs in properties.
+ At other times, expand the item refs in the properties.
+ See comments in Expression.cs, for a full explanation.
+ * BuildItem.cs: Track api changes.
+ * BuildItemGroup.cs: Likewise.
+ * BuildProperty.cs: Track api changes. Handle self-references.
+ * BuildTask.cs: Track api changes.
+ * IReference.cs: Add ExpressionOptions param.
+ * ItemReference.cs: Track api changes.
+ * PropertyReference.cs: Likewise.
+ * MetadataReference.cs: Likewise.
+ * ExpressionCollection.cs: Track api changes. Add support for
+ converting all primitive types and DateTime, instead of a fixed
+ few.
+ * Project.cs (GetMetadataBatched): Use the evaluated metadata.
+ * TaskBatchingImpl.cs: Handle the case when batching is required,
+ but no items are available.
+
+ * TaskEngine.cs: Throw on unsupported types. Correctly handle
+ properties in case of empty values.
+
2009-08-26 Ankit Jain <jankit@novell.com>
* Expression.cs: Correctly handle a item reference with transform
using System.Text.RegularExpressions;
namespace Microsoft.Build.BuildEngine {
+
+ // Properties and items are processed in two ways
+ // 1. Evaluate, Project calls evaluate on all the item and property groups.
+ // At this time, the items are fully expanded, all item and property
+ // references are expanded to get the item's value.
+ // Properties on the other hand, expand property refs, but _not_
+ // item references.
+ //
+ // 2. After the 'evaluation' phase, this could be when executing a target/task,
+ // - Items : no expansion required, as they are already at final value
+ // - Properties: Item references get expanded now, in the context of the
+ // batching
+ //
+ // The enum ExpressionOptions is for specifying this expansion of item references.
+ //
+ // GroupingCollection.Evaluate, evaluates all properties and then items
+
internal class Expression {
ExpressionCollection expressionCollection;
// @split: Split on ';'
// Eg. Property values don't need to be split
+ //
+ // @allowItems: item refs should not be treated as item refs!
+ // it converts them to strings in the final expressionCollection
public void Parse (string expression, bool allowItems, bool split)
{
expression = expression.Replace ('/', Path.DirectorySeparatorChar);
return phase2;
}
-
+
public object ConvertTo (Project project, Type type)
{
- return expressionCollection.ConvertTo (project, type);
+ return ConvertTo (project, type, ExpressionOptions.ExpandItemRefs);
+ }
+
+ public object ConvertTo (Project project, Type type, ExpressionOptions options)
+ {
+ return expressionCollection.ConvertTo (project, type, options);
}
public ExpressionCollection Collection {
}
}
}
+
+ enum ExpressionOptions {
+ ExpandItemRefs,
+ DoNotExpandItemRefs
+ }
}
#endif
objects.Add (s);
}
- public object ConvertTo (Project project, Type type)
+ public object ConvertTo (Project project, Type type, ExpressionOptions options)
{
if (type.IsArray) {
if (type == typeof (ITaskItem[]))
- return ConvertToITaskItemArray (project);
+ return ConvertToITaskItemArray (project, options);
else
- return ConvertToArray (project, type);
+ return ConvertToArray (project, type, options);
} else {
if (type == typeof (ITaskItem))
- return ConvertToITaskItem (project);
+ return ConvertToITaskItem (project, options);
else
- return ConvertToNonArray (project, type);
+ return ConvertToNonArray (project, type, options);
}
}
yield return o;
}
- object ConvertToNonArray (Project project, Type type)
+ object ConvertToNonArray (Project project, Type type, ExpressionOptions options)
{
- return ConvertToObject (ConvertToString (project), type);
+ return ConvertToObject (ConvertToString (project, options), type, options);
}
- object ConvertToArray (Project project, Type type)
+ object ConvertToArray (Project project, Type type, ExpressionOptions options)
{
- ITaskItem[] items = ConvertToITaskItemArray (project);
+ ITaskItem[] items = ConvertToITaskItemArray (project, options);
Type element_type = type.GetElementType ();
Array arr = Array.CreateInstance (element_type, items.Length);
for (int i = 0; i < arr.Length; i ++)
- arr.SetValue (ConvertToObject (items [i].ItemSpec, element_type), i);
+ arr.SetValue (ConvertToObject (items [i].ItemSpec, element_type, options), i);
return arr;
}
- object ConvertToObject (string raw, Type type)
+ object ConvertToObject (string raw, Type type, ExpressionOptions options)
{
if (type == typeof (bool)) {
bool value;
if (type == typeof (string))
return raw;
- else if (type == typeof (int))
- return Int32.Parse (raw);
- else if (type == typeof (uint))
- return UInt32.Parse (raw);
- else if (type == typeof (DateTime))
+
+ if (type.IsPrimitive)
+ return Convert.ChangeType (raw, type);
+
+ if (type == typeof (DateTime))
return DateTime.Parse (raw);
- else
- throw new Exception (String.Format ("Unknown type: {0}", type.ToString ()));
+
+ throw new Exception (String.Format ("Unsupported type: {0}", type));
}
- string ConvertToString (Project project)
+ string ConvertToString (Project project, ExpressionOptions options)
{
StringBuilder sb = new StringBuilder ();
IReference br = o as IReference;
if (br != null)
- sb.Append (br.ConvertToString (project));
+ sb.Append (br.ConvertToString (project, options));
else
throw new Exception ("BUG: Invalid type in objects collection.");
}
return sb.ToString ();
}
- ITaskItem ConvertToITaskItem (Project project)
+ ITaskItem ConvertToITaskItem (Project project, ExpressionOptions options)
{
ITaskItem item;
if (objects == null)
throw new Exception ("Cannot cast empty expression to ITaskItem.");
- ITaskItem[] items = ConvertToITaskItemArray (project);
- if (items.Length != 1)
+ ITaskItem[] items = ConvertToITaskItemArray (project, options);
+ if (items.Length > 1)
//FIXME: msbuild gives better errors
- throw new Exception (String.Format ("Too many items: {0}", items.Length));
+ throw new Exception (String.Format ("Exactly one item required, but got: {0}", items.Length));
+ if (items.Length == 0) return null;
return items [0];
}
// PropertyRef concats if it doesn't end in ';'
// - string cannot concat with ItemRef unless it is ';'.
// string concats if it ends in ';'
- ITaskItem[] ConvertToITaskItemArray (Project project)
+ ITaskItem[] ConvertToITaskItemArray (Project project, ExpressionOptions options)
{
List <ITaskItem> finalItems = new List <ITaskItem> ();
prev_can_concat = !(value.Length > 0 && value [value.Length - 1] == ';');
}
- AddItemsToArray (finalItems, br.ConvertToITaskItemArray (project), can_concat);
+ AddItemsToArray (finalItems, br.ConvertToITaskItemArray (project, options), can_concat);
prev = o;
}
namespace Microsoft.Build.BuildEngine {
internal interface IReference {
- string ConvertToString (Project project);
- ITaskItem[] ConvertToITaskItemArray (Project project);
+ string ConvertToString (Project project, ExpressionOptions options);
+ ITaskItem[] ConvertToITaskItemArray (Project project, ExpressionOptions options);
int Start { get; }
int End { get; }
//
// Author:
// Marek Sieradzki (marek.sieradzki@gmail.com)
+// Ankit Jain (jankit@novell.com)
//
// (C) 2005 Marek Sieradzki
+// Copyright 2009 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
this.length = length;
this.original_string = original_string;
+ // Transform and separator are never expanded for item refs
if (transform != null) {
this.transform = new Expression ();
this.transform.Parse (transform, false);
}
}
- public string ConvertToString (Project project)
+ // when evaluating property, allowItems=false, so,
+ // ItemRef will _not_ get created, so this wont get hit
+ // when evaluating items, expand: true
+ // other cases, expand: true
+ public string ConvertToString (Project project, ExpressionOptions options)
{
BuildItemGroup group;
if (project.TryGetEvaluatedItemByNameBatched (itemName, out group))
- return group.ConvertToString (transform, separator);
+ return group.ConvertToString (transform, separator, options);
else
return String.Empty;
}
- public ITaskItem [] ConvertToITaskItemArray (Project project)
+ public ITaskItem [] ConvertToITaskItemArray (Project project, ExpressionOptions options)
{
BuildItemGroup group;
if (project.TryGetEvaluatedItemByNameBatched (itemName, out group))
- return group.ConvertToITaskItemArray (transform);
+ return group.ConvertToITaskItemArray (transform, options);
else
return null;
-
}
public string ItemName {
get { return start + length - 1; }
}
- public string ConvertToString (Project project)
+ public string ConvertToString (Project project, ExpressionOptions options)
{
return project.GetMetadataBatched (itemName, metadataName);
}
- public ITaskItem [] ConvertToITaskItemArray (Project project)
+ public ITaskItem [] ConvertToITaskItemArray (Project project, ExpressionOptions options)
{
List<ITaskItem> items = new List<ITaskItem> ();
if (IsQualified) {
if (group != null) {
foreach (BuildItem item in group) {
if (item.HasMetadata (metadataName))
- return item.GetMetadata (metadataName);
+ return item.GetEvaluatedMetadata (metadataName);
}
}
return String.Empty;
//
// Author:
// Marek Sieradzki (marek.sieradzki@gmail.com)
+// Ankit Jain (jankit@novell.com)
//
// (C) 2005 Marek Sieradzki
+// Copyright 2009 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
this.length = length;
}
- public string ConvertToString (Project project)
+
+ // when evaluating items: expand: true
+ // all other times, expand: true
+ // so, always true, ignore @options
+ public string ConvertToString (Project project, ExpressionOptions options)
{
BuildProperty bp = project.EvaluatedProperties [name];
- return bp != null ? bp.ConvertToString (project) : String.Empty;
+ if (bp == null)
+ return String.Empty;
+
+ if (options == ExpressionOptions.DoNotExpandItemRefs)
+ return bp.FinalValue;
+
+ return bp.ConvertToString (project, ExpressionOptions.ExpandItemRefs);
}
- public ITaskItem[] ConvertToITaskItemArray (Project project)
+ // when evaluating items: expand: true
+ // all other times, expand: true
+ // so, always true, ignore @options
+ public ITaskItem[] ConvertToITaskItemArray (Project project, ExpressionOptions options)
{
BuildProperty bp = project.EvaluatedProperties [name];
- return bp != null ? bp.ConvertToITaskItemArray (project) : null;
+ if (bp == null)
+ return null;
+
+ if (options == ExpressionOptions.DoNotExpandItemRefs) {
+ List<ITaskItem> list = new List<ITaskItem> ();
+ foreach (string s in bp.FinalValue.Split (new char[] {';'}, StringSplitOptions.RemoveEmptyEntries))
+ list.Add (new TaskItem (s));
+ return list.ToArray ();
+ }
+
+ return bp.ConvertToITaskItemArray (project, ExpressionOptions.ExpandItemRefs);
}
public string Name {
Expression e = new Expression ();
e.Parse (inputs, true);
- inputFiles = (ITaskItem[]) e.ConvertTo (project, typeof (ITaskItem[]));
+ inputFiles = (ITaskItem[]) e.ConvertTo (project, typeof (ITaskItem[]), ExpressionOptions.ExpandItemRefs);
e = new Expression ();
e.Parse (outputs, true);
- outputFiles = (ITaskItem[]) e.ConvertTo (project, typeof (ITaskItem[]));
+ outputFiles = (ITaskItem[]) e.ConvertTo (project, typeof (ITaskItem[]), ExpressionOptions.ExpandItemRefs);
if (inputFiles == null || inputFiles.Length == 0)
return false;
// Run the task in batches
bool retval = true;
- foreach (Dictionary<string, BuildItemGroup> bucket in buckets) {
- project.SetBatchedItems (bucket, commonItemsByName);
+ if (buckets.Count > 0) {
+ foreach (Dictionary<string, BuildItemGroup> bucket in buckets) {
+ project.SetBatchedItems (bucket, commonItemsByName);
+ if (ConditionParser.ParseAndEvaluate (buildTask.Condition, project)) {
+ retval = buildTask.Execute ();
+ if (!retval && !buildTask.ContinueOnError) {
+ executeOnErrors = true;
+ break;
+ }
+ }
+ }
+ project.SetBatchedItems (null, null);
+ } else {
+ // batched mode, but no values in the corresponding items!
if (ConditionParser.ParseAndEvaluate (buildTask.Condition, project)) {
- retval = buildTask.Execute ();
- if (!retval && !buildTask.ContinueOnError) {
- executeOnErrors = true;
- break;
- }
+ retval = buildTask.Execute ();
+ if (!retval && !buildTask.ContinueOnError)
+ executeOnErrors = true;
}
}
- project.SetBatchedItems (null, null);
return retval;
}
//
// Author:
// Marek Sieradzki (marek.sieradzki@gmail.com)
+// Ankit Jain (jankit@novell.com)
//
// (C) 2005 Marek Sieradzki
+// Copyright 2009 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
{
parentProject = project;
}
+
+ // Rules (inferred) for property values incase of empty data
+ //
+ // Prop Type Argument Final Value Required
+ // string empty string null Yes/no
+ // string only whitespace @arg Yes/no
+ //
+ // string/
+ // ITaskItem[] empty/whitespace empty array Yes
+ //
+ // string/
+ // ITaskItem[] empty/whitespace null No
public void Prepare (ITask task, XmlElement taskElement,
IDictionary <string, string> parameters, Type taskType)
de.Key));
try {
- value = GetObjectFromString (de.Value, currentProperty.PropertyType);
+ if (TryGetObjectFromString (de.Value, currentProperty.PropertyType, out value))
+ values.Add (de.Key, value);
} catch (Exception e) {
throw new Exception (String.Format (
"Error converting Property named '{0}' with value '{1}' to type {2}: {3}",
de.Key, de.Value, currentProperty.PropertyType, e.Message), e);
}
-
- if (value != null)
- values.Add (de.Key, value);
}
properties = taskType.GetProperties ();
foreach (PropertyInfo pi in properties) {
- if (pi.IsDefined (requiredAttribute, false) && values.ContainsKey (pi.Name) == false)
- throw new InvalidProjectFileException (String.Format ("Required property '{0}' not set.", pi.Name));
-
- if (values.ContainsKey (pi.Name))
- InitializeParameter (pi, values [pi.Name]);
+ bool is_required = pi.IsDefined (requiredAttribute, false);
+
+ if (is_required && values.ContainsKey (pi.Name) == false)
+ throw new InvalidProjectFileException (String.Format ("Required property '{0}' not set.",
+ pi.Name));
+
+ if (!values.ContainsKey (pi.Name))
+ continue;
+
+ Type prop_type = pi.PropertyType;
+ if (prop_type.IsArray)
+ prop_type = prop_type.GetElementType ();
+
+ // Valid data types: primitive types, DateTime, string and ITaskItem, and their arrays
+ if (!prop_type.IsPrimitive && prop_type != typeof (string) && prop_type != typeof (ITaskItem))
+ throw new InvalidProjectFileException (String.Format (
+ "{0} is not a supported type for properties for msbuild tasks.",
+ pi.PropertyType));
+
+ object val = values [pi.Name];
+ if (val == null && pi.PropertyType.IsArray && is_required) {
+ if (pi.PropertyType == typeof (ITaskItem[]))
+ val = new ITaskItem [0];
+ else if (pi.PropertyType == typeof (string[]))
+ val = new string [0];
+ }
+
+ InitializeParameter (pi, val);
}
}
foreach (BuildItem bi in newItems)
parentProject.EvaluatedItems.AddItem (bi);
}
-
- object GetObjectFromString (string raw, Type type)
+
+ // returns true, if the @result should be included in the values list
+ bool TryGetObjectFromString (string raw, Type type, out object result)
{
Expression e;
- object result;
+ result = null;
e = new Expression ();
e.Parse (raw, true);
- // Empty contents allowed only for arrays
- // See TestRequiredTask_*
- if (!type.IsArray &&
- (string) e.ConvertTo (parentProject, typeof (string)) == String.Empty)
- return null;
-
- result = e.ConvertTo (parentProject, type);
+ // See rules in comment for 'Prepare'
+ string str = (string) e.ConvertTo (parentProject, typeof (string));
+ if (!type.IsArray && str == String.Empty)
+ return false;
+
+ if (str.Trim ().Length == 0 && type.IsArray &&
+ (type.GetElementType () == typeof (string) || type.GetElementType () == typeof (ITaskItem)))
+ return true;
+
+ result = e.ConvertTo (parentProject, type, ExpressionOptions.ExpandItemRefs);
- return result;
+ return true;
}
}
}
Assert.AreEqual ("A", project.EvaluatedItems [1].GetEvaluatedMetadata ("Meta"), "A6");
}
+ [Test]
+ public void TestSetMetadata5a () {
+ Engine engine;
+ Project project;
+ BuildItemGroup[] groups = new BuildItemGroup[1];
+
+ string documentString = @"
+ <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
+ <PropertyGroup>
+ <A>A</A>
+ <C>@(D)</C>
+ </PropertyGroup>
+ <ItemGroup>
+ <D Include='D'/>
+ <C Include='$(C)'/>
+ <A Include='a;b'>
+ <Md>@(C)</Md>
+ </A>
+ <B Include='$(A)'/>
+ </ItemGroup>
+ <Target Name='main'>
+ <Message Text=""a.md: %(A.Md)""/>
+ <Message Text=""a.md: %(A.Meta)""/>
+ </Target>
+ </Project>
+ ";
+
+ engine = new Engine (Consts.BinPath);
+ project = engine.CreateNewProject ();
+ MonoTests.Microsoft.Build.Tasks.TestMessageLogger logger = new MonoTests.Microsoft.Build.Tasks.TestMessageLogger ();
+ engine.RegisterLogger (logger);
+ project.LoadXml (documentString);
+
+ CheckMetadata (project, "A", "Md", new string [] {"@(C)", "@(C)"}, "G1");
+ CheckEvaluatedMetadata (project, "A", "Md", new string[] { "D", "D" }, "G2");
+
+ //@(B)
+ Assert.AreEqual ("A", project.GetEvaluatedItemsByName ("B")[0].FinalItemSpec, "B2");
+
+ project.ItemGroups.CopyTo (groups, 0);
+ /*Broken right now:
+ CheckBuildItemGroup (groups[0], new string[] {
+ "D", "D",
+ "C", "$(C)",
+ "A", "a;b",
+ "B", "$(A)"
+ }, "H1");*/
+
+ CheckBuildItemGroup (project.GetEvaluatedItemsByName ("C"), new string[] {
+ "C", "D"
+ }, "H2");
+
+ CheckBuildItemGroup (project.GetEvaluatedItemsByName ("C"), new string[] {
+ "C", "D"
+ }, "I");
+
+ project.GetEvaluatedItemsByName ("A")[0].SetMetadata ("Meta", "@(B)");
+
+ Assert.AreEqual (5, project.EvaluatedItems.Count, "A0");
+ Assert.AreEqual (2, project.GetEvaluatedItemsByName ("A").Count, "A7");
+
+ CheckMetadata (project, "A", "Meta", new string[] { "@(B)", "" }, "J");
+
+ if (!project.Build ()) {
+ logger.DumpMessages ();
+ Assert.Fail ("Build failed");
+ }
+ logger.DumpMessages ();
+
+ CheckMetadata (project, "A", "Meta", new string[] { "@(B)", "" }, "K1");
+ CheckEvaluatedMetadata (project, "A", "Meta", new string[] { "", "" }, "K2");
+
+ logger.CheckLoggedMessageHead ("a.md: D", "E10");
+ logger.CheckLoggedMessageHead ("a.md: ", "E11");
+ Assert.AreEqual (0, logger.NormalMessageCount, "Unexpected messages left");
+ }
+
[Test]
public void TestSetMetadata6 ()
{
Assert.AreEqual ("PropValue/abc.txt", grp [0].FinalItemSpec, "A2");
Assert.AreEqual ("PropValue/def.txt", grp [1].FinalItemSpec, "A3");
}
+
+ void CheckMetadata (Project p, string itemname, string metadataname, string[] values, string prefix)
+ {
+ BuildItemGroup group = p.GetEvaluatedItemsByName (itemname);
+
+ Assert.AreEqual (values.Length, group.Count, "Number of items for itemname " + itemname);
+
+ for (int i = 0; i < values.Length; i++) {
+ Assert.AreEqual (values[i], group [i].GetMetadata (metadataname), prefix + "#" + i.ToString ());
+ }
+ }
+
+ void CheckEvaluatedMetadata (Project p, string itemname, string metadataname, string[] values, string prefix)
+ {
+ BuildItemGroup group = p.GetEvaluatedItemsByName (itemname);
+
+ Assert.AreEqual (values.Length, group.Count, "Number of items for itemname " + itemname);
+
+ for (int i = 0; i < values.Length; i++) {
+ Assert.AreEqual (values[i], group [i].GetEvaluatedMetadata (metadataname), prefix + "#" + i.ToString ());
+ }
+ }
+
+ void CheckBuildItemGroup (BuildItemGroup group, string[] names, string prefix)
+ {
+ try {
+ Assert.AreEqual (group.Count, names.Length / 2, "Number of items in group");
+ for (int i = 0; i < group.Count; i++) {
+ Assert.AreEqual (names[i * 2], group[i].Name, String.Format ("{0}#{1} : item name", prefix, i));
+ Assert.AreEqual (names[(i * 2) + 1], group[i].FinalItemSpec, String.Format ("{0}#{1} : FinalItemSpec", prefix, i));
+ }
+ } catch (AssertionException) {
+ for (int i = 0; i < group.Count; i++) {
+ Console.WriteLine ("group[{0}] = {1}", i, group[i].Name);
+ Console.WriteLine ("group[{0}] = {1}", i, group[i].FinalItemSpec);
+ }
+ throw;
+ }
+ }
}
}
+2009-08-29 Ankit Jain <jankit@novell.com>
+
+ * BuildItemTest.cs (TestSetMetadata5a): New.
+ * ProjectTest.cs: Add tests for different property types
+ with required attribute. Also, check the values - null or
+ empty array.
+ * TestTasks.cs: Add new tasks for above.
+
2009-08-18 Ankit Jain <jankit@novell.com>
* ProjectTest.cs (TestCaseSensitivityOfProjectElements): New.
//
// Author:
// Marek Sieradzki (marek.sieradzki@gmail.com)
+// Ankit Jain (jankit@novell.com)
//
// (C) 2005 Marek Sieradzki
+// Copyright 2009 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
"<Project></Project>";
engine = new Engine (Consts.BinPath);
+
DateTime time = DateTime.Now;
project = engine.CreateNewProject ();
try {
public void TestRequiredTask_String1 ()
{
CheckProjectForRequiredTests ("RequiredTestTask_String", "@(NonExistant)",
- false, "Should've failed: No value specified for required field - 'Property' of RequiredTestTask_String");
+ false, "Should've failed: No value specified for required field - 'Property' of RequiredTestTask_String", null);
}
[Test]
public void TestRequiredTask_String2 ()
{
CheckProjectForRequiredTests ("RequiredTestTask_String", "$(NonExistant)",
- false, "Should've failed: No value specified for required field - 'Property' of RequiredTestTask_String");
+ false, "Should've failed: No value specified for required field - 'Property' of RequiredTestTask_String", null);
+ }
+
+ [Test]
+ public void TestRequiredTask_Strings1 () {
+ CheckProjectForRequiredTests ("RequiredTestTask_Strings", "@(NonExistant)",
+ true, "Build failed", "0");
+ }
+
+ [Test]
+ public void TestRequiredTask_Strings2 () {
+ CheckProjectForRequiredTests ("RequiredTestTask_Strings", "$(NonExistant)",
+ true, "Build failed", "0");
+ }
+
+ [Test]
+ public void TestRequiredTask_Strings3 () {
+ CheckProjectForRequiredTests ("RequiredTestTask_Strings", "%(NonExistant.Md)",
+ true, "Build failed", "0");
+ }
+
+ [Test]
+ public void TestRequiredTask_Strings4 () {
+ CheckProjectForRequiredTests ("RequiredTestTask_Strings", " %(NonExistant.Md)",
+ true, "Build failed", "0");
+ }
+
+ [Test]
+ public void TestRequiredTask_Ints1 () {
+ CheckProjectForRequiredTests ("RequiredTestTask_IntArray", "@(NonExistant)",
+ true, "Build failed", "count: 0");
+ }
+
+ [Test]
+ public void TestRequiredTask_Ints2 () {
+ CheckProjectForRequiredTests ("RequiredTestTask_IntArray", "$(NonExistant)",
+ true, "Build failed", "count: 0");
+ }
+
+ [Test]
+ public void TestRequiredTask_OtherObjectsArray () {
+ CheckProjectForRequiredTests ("RequiredTestTask_OtherObjectArray", "@(NonExistant)",
+ false, "Should've failed: ObjectArray type not supported as a property type", null);
+ }
+
+ [Test]
+ public void TestRequiredTask_OtherObject () {
+ CheckProjectForRequiredTests ("RequiredTestTask_OtherObjectArray", "@(NonExistant)",
+ false, "Should've failed: ObjectArray type not supported as a property type", null);
+ }
+
+ [Test]
+ public void TestRequiredTask_MyTaskItems1 () {
+ CheckProjectForRequiredTests ("RequiredTestTask_MyTaskItemArray", "@(NonExistant)",
+ false, "Should've failed: ObjectArray type not supported as a property type", null);
}
[Test]
public void TestRequiredTask_TaskItem1 ()
{
Project p = CheckProjectForRequiredTests ("RequiredTestTask_TaskItem", "@(NonExistant)",
- false, "Should've failed: No value specified for required field - 'Property' of RequiredTestTask_TaskItem");
+ false, "Should've failed: No value specified for required field - 'Property' of RequiredTestTask_TaskItem", null);
}
[Test]
public void TestRequiredTask_TaskItem2 ()
{
Project p = CheckProjectForRequiredTests ("RequiredTestTask_TaskItem", "$(NonExistant)",
- false, "Should've failed: No value specified for required field - 'Property' of RequiredTestTask_TaskItem");
+ false, "Should've failed: No value specified for required field - 'Property' of RequiredTestTask_TaskItem", null);
}
[Test]
public void TestRequiredTask_TaskItemArray1 ()
{
Project p = CheckProjectForRequiredTests ("RequiredTestTask_TaskItems", "@(NonExistant)",
- true, "Build failed");
+ true, "Build failed", "count: 0");
BuildItemGroup group = p.GetEvaluatedItemsByName ("OutItem");
Assert.AreEqual (1, group.Count, "A2");
public void TestRequiredTask_TaskItemArray2 ()
{
Project p = CheckProjectForRequiredTests ("RequiredTestTask_TaskItems", "$(NonExistant)",
- true, "Build failed");
+ true, "Build failed", "count: 0");
BuildItemGroup group = p.GetEvaluatedItemsByName ("OutItem");
Assert.AreEqual (1, group.Count, "A2");
public void TestRequiredTask_TaskItemArray3 ()
{
Project p = CheckProjectForRequiredTests ("RequiredTestTask_IntArray", "$(NonExistant)",
- true, "Build failed");
+ true, "Build failed", "count: 0");
BuildItemGroup group = p.GetEvaluatedItemsByName ("OutItem");
Assert.AreEqual (1, group.Count, "A2");
Assert.AreEqual ("count: 0", group [0].FinalItemSpec, "A3");
}
+ [Test]
+ public void TestRequiredTask_TaskItemArray4 () {
+ Project p = CheckProjectForRequiredTests ("RequiredTestTask_IntArray", "%(NonExistant.Md)",
+ true, "Build failed", "count: 0");
+
+ BuildItemGroup group = p.GetEvaluatedItemsByName ("OutItem");
+ Assert.AreEqual (1, group.Count, "A2");
+ Assert.AreEqual ("count: 0", group[0].FinalItemSpec, "A3");
+ }
+
+ [Test]
+ public void TestRequiredTask_TaskItemArray5 () {
+ // with extra space in prop value
+ Project p = CheckProjectForRequiredTests ("RequiredTestTask_IntArray", " %(NonExistant.Md)",
+ true, "Build failed", "count: 0");
+
+ BuildItemGroup group = p.GetEvaluatedItemsByName ("OutItem");
+ Assert.AreEqual (1, group.Count, "A2");
+ Assert.AreEqual ("count: 0", group[0].FinalItemSpec, "A3");
+ }
+
+
[Test]
public void TestCaseSensitivityOfProjectElements ()
{
}
}
- Project CheckProjectForRequiredTests (string taskname, string property_arg, bool expected_result, string error_msg)
+ Project CheckProjectForRequiredTests (string taskname, string property_arg, bool expected_result, string error_msg,
+ string expected_output_msg)
{
string projectString = String.Format (@"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
<UsingTask TaskName=""{0}"" AssemblyFile=""Test/resources/TestTasks.dll"" />
<{0} Property=""{1}"">
<Output TaskParameter=""Output"" ItemName=""OutItem""/>
</{0}>
+ <Message Text='@(OutItem)'/>
</Target>
</Project>", taskname, property_arg);
engine.RegisterLogger (logger);
Project project = engine.CreateNewProject ();
project.LoadXml (projectString);
-
try {
Assert.AreEqual (expected_result, project.Build (), error_msg);
+ if (expected_result) {
+ logger.CheckLoggedMessageHead (expected_output_msg, "A");
+ Assert.AreEqual (0, logger.NormalMessageCount, "Unexpected messages found");
+ }
} finally {
logger.DumpMessages ();
}
+2009-08-29 Ankit Jain <jankit@novell.com>
+
+ * TestTasks.cs: Add new tasks for different property types
+ with required attribute. Also, emit whether the value was
+ null or a zero length array.
+
2009-03-26 Jonathan Chambers <joncham@gmail.com>
* TestTasks.cs (NamespacedOutputTestTask): New.
using System;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
+using System.Text;
namespace Foo
{
}
}
+public class TestTask_TaskItems : Task
+{
+ string output;
+ public override bool Execute () {
+ output = items == null ? "null" : "count: " + items.Length.ToString ();
+ return true;
+ }
+
+ ITaskItem[] items;
+ public ITaskItem[] Property {
+ set { items = value; }
+ }
+
+ [Output]
+ public string Output {
+ get { return output; }
+ }
+}
+
+public class TestTask_TaskItem : Task
+{
+ string output;
+ public override bool Execute () {
+ output = item == null ? "null" : "not null: " + item.ItemSpec;
+ return true;
+ }
+
+ ITaskItem item;
+ public ITaskItem Property {
+ set { item = value; }
+ }
+
+ [Output]
+ public string Output {
+ get { return output; }
+ }
+}
+
+
public class RequiredTestTask_TaskItems : Task {
string output;
public override bool Execute ()
}
}
+public class RequiredTestTask_Strings : Task
+{
+ string output;
+ public override bool Execute () {
+ output = property == null ? "null" : property.Length.ToString ();
+ return true;
+ }
+
+ string []property;
+ [Required]
+ public string[] Property {
+ set { property = value; }
+ }
+
+ [Output]
+ public string Output {
+ get { return output; }
+ }
+}
+
+public class RequiredTestTask_OtherObjectArray : Task
+{
+ string output;
+ public override bool Execute () {
+ output = property == null ? "null" : property.Length.ToString ();
+ return true;
+ }
+
+ OtherClass[] property;
+ [Required]
+ public OtherClass[] Property {
+ set { property = value; }
+ }
+
+ [Output]
+ public string Output {
+ get { return output; }
+ }
+}
+
+public class RequiredTestTask_OtherObject : Task
+{
+ string output;
+ public override bool Execute () {
+ output = property == null ? "null" : "not null";
+ return true;
+ }
+
+ OtherClass property;
+ [Required]
+ public OtherClass Property {
+ set { property = value; }
+ }
+
+ [Output]
+ public string Output {
+ get { return output; }
+ }
+}
+
+public class RequiredTestTask_MyTaskItemArray : Task
+{
+ string output;
+ public override bool Execute () {
+ output = property == null ? "null" : property.Length.ToString ();
+ return true;
+ }
+
+ MyTaskItem[] property;
+ [Required]
+ public MyTaskItem[] Property {
+ set { property = value; }
+ }
+
+ [Output]
+ public string Output {
+ get { return output; }
+ }
+}
+
+public class OtherClass
+{
+}
+
+public class MyTaskItem : ITaskItem
+{
+ #region ITaskItem Members
+
+ public System.Collections.IDictionary CloneCustomMetadata () {
+ throw new NotImplementedException ();
+ }
+
+ public void CopyMetadataTo (ITaskItem destinationItem) {
+ throw new NotImplementedException ();
+ }
+
+ public string GetMetadata (string metadataName) {
+ throw new NotImplementedException ();
+ }
+
+ public string ItemSpec {
+ get {
+ throw new NotImplementedException ();
+ }
+ set {
+ throw new NotImplementedException ();
+ }
+ }
+
+ public int MetadataCount {
+ get { throw new NotImplementedException (); }
+ }
+
+ public System.Collections.ICollection MetadataNames {
+ get { throw new NotImplementedException (); }
+ }
+
+ public void RemoveMetadata (string metadataName) {
+ throw new NotImplementedException ();
+ }
+
+ public void SetMetadata (string metadataName, string metadataValue) {
+ throw new NotImplementedException ();
+ }
+
+ #endregion
+}
+
public class RequiredTestTask_IntArray: Task
{
string output;
}
public class StringTestTask : Task {
+ string output;
+
public override bool Execute ()
{
+ StringBuilder sb = new StringBuilder ();
+ sb.AppendFormat ("property: {0} ## ", property == null ? "null" : property);
+ sb.AppendFormat ("array: {0}", array == null ? "null" : array.Length.ToString ());
+
+ output = sb.ToString ();
return true;
}
public string[] Array {
get { return array; }
set { array = value; }
- }
+ }
+
+ [Output]
+ public string OutputString {
+ get { return output; }
+ }
}
public class PublishTestTask : Task {
+2009-08-29 Ankit Jain <jankit@novell.com>
+
+ * Items.cs: Add tests for property/item evaluation.
+
2009-06-12 Ankit Jain <jankit@novell.com>
* Items.cs (TestItemsInTarget3a): Add another case for valid whitespace
string documentString = @"
<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
+ <PropertyGroup>
+ <Prop1>@(Item0)</Prop1>
+ </PropertyGroup>
<ItemGroup>
+ <Item0 Include=""Foo""/>
<Item1 Include='A;B;C' />
<Item2 Include=""A\B.txt;A\C.txt;B\B.zip;B\C.zip"" />
+ <ItemT0 Include=""@(Item1)"" />
<ItemT1 Include=""@(Item1->'%(Identity)')"" />
<ItemT2 Include=""@(Item1->'%(Identity)%(Identity)')"" />
<ItemT3 Include=""@(Item1->'(-%(Identity)-)')"" />
<ItemT4 Include=""@(Item2->'%(Extension)')"" />
<ItemT5 Include=""@(Item2->'%(Filename)/%(Extension)')"" />
+ <ItemT6 Include=""@(Item2->'%(Extension)/$(Prop1)')"" />
</ItemGroup>
</Project>
";
proj.LoadXml (documentString);
+ //Assert.IsTrue (proj.Build (), "Build failed");
+
+ Assert.AreEqual ("@(Item0)", proj.EvaluatedProperties["Prop1"].FinalValue, "A0");
+ //Assert.AreEqual ("@(Item2->'%(Extension)/$(Prop1)')", proj.EvaluatedItems [7].FinalItemSpec, "B0");
+
+ CheckItems (proj, "ItemT0", "A1", "A", "B", "C");
CheckItems (proj, "ItemT1", "A1", "A", "B", "C");
CheckItems (proj, "ItemT2", "A2", "AA", "BB", "CC");
CheckItems (proj, "ItemT3", "A3", "(-A-)", "(-B-)", "(-C-)");
CheckItems (proj, "ItemT4", "A4", ".txt", ".txt", ".zip", ".zip");
CheckItems (proj, "ItemT5", "A5", "B/.txt", "C/.txt", "B/.zip", "C/.zip");
+ CheckItems (proj, "ItemT6", "A6", ".txt/@(Item0)", ".txt/@(Item0)", ".zip/@(Item0)", ".zip/@(Item0)");
}
[Test]
proj.LoadXml (documentString);
}
+ [Test]
+ // test item metadata
+ public void TestItems10 ()
+ {
+ string project_xml = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
+ <PropertyGroup>
+ <Prop1>@(Item0)</Prop1>
+ <Prop2>@(Ref1)</Prop2>
+ </PropertyGroup>
+ <ItemGroup>
+ <Item0 Include=""Foo""/>
+ <Ref1 Include=""File1"" />
+ <IWithM Include=""A"">
+ <Md>@(Item0)</Md>
+ <Md2>$(Prop2)</Md2>
+ </IWithM>
+ </ItemGroup>
+
+ <Target Name=""1"">
+ <Message Text=""IWithM.md: %(IWithM.Md)""/>
+ <Message Text=""IWithM.md2: %(IWithM.Md2)""/>
+
+ <CreateItem Include=""Bar;Xyz"">
+ <Output TaskParameter=""Include"" ItemName=""Item0""/>
+ </CreateItem>
+
+ <Message Text=""IWithM.md: %(IWithM.Md)""/>
+ <Message Text=""IWithM.md2: %(IWithM.Md2)""/>
+ </Target>
+</Project>
+";
+
+ Engine engine = new Engine (Consts.BinPath);
+ Project proj = engine.CreateNewProject ();
+ MonoTests.Microsoft.Build.Tasks.TestMessageLogger logger =
+ new MonoTests.Microsoft.Build.Tasks.TestMessageLogger ();
+ proj.LoadXml (project_xml);
+ engine.RegisterLogger (logger);
+
+ if (!proj.Build ("1")) {
+ logger.DumpMessages ();
+ Assert.Fail ("Build failed");
+ }
+
+ logger.CheckLoggedMessageHead ("IWithM.md: Foo", "A1");
+ logger.CheckLoggedMessageHead ("IWithM.md2: File1", "A2");
+
+ logger.CheckLoggedMessageHead ("IWithM.md: Foo", "A3");
+ logger.CheckLoggedMessageHead ("IWithM.md2: File1", "A4");
+ Assert.AreEqual (0, logger.NormalMessageCount, "unexpected messages found");
+ }
+
+ [Test]
+ // Test Item/prop references in conditions
+ public void TestItems11 () {
+ string project_xml = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
+ <PropertyGroup>
+ <Prop1>@(Item0)</Prop1>
+ </PropertyGroup>
+ <ItemGroup>
+ <Item0 Include=""Foo""/>
+ <Item1 Include=""@(Item0)""/>
+
+ <CondItem Condition=""'@(Item1)' == '@(Item0)'"" Include=""Equal to item0""/>
+ <CondItem Condition=""'@(Item1)' == 'Foo'"" Include=""Equal to item0's value""/>
+
+ <CondItem1 Condition=""'$(Prop1)' == '@(Item0)'"" Include=""Equal to item0""/>
+ <CondItem1 Condition=""'$(Prop1)' == 'Foo'"" Include=""Equal to item0's value""/>
+ </ItemGroup>
+
+ <Target Name=""1"">
+ <Message Text = ""CondItem: %(CondItem.Identity)""/>
+ <Message Text = ""CondItem1: %(CondItem1.Identity)""/>
+ </Target>
+</Project>
+";
+
+ Engine engine = new Engine (Consts.BinPath);
+ Project proj = engine.CreateNewProject ();
+ MonoTests.Microsoft.Build.Tasks.TestMessageLogger logger =
+ new MonoTests.Microsoft.Build.Tasks.TestMessageLogger ();
+ proj.LoadXml (project_xml);
+ engine.RegisterLogger (logger);
+
+ if (!proj.Build ("1")) {
+ logger.DumpMessages ();
+ Assert.Fail ("Build failed");
+ }
+
+ logger.CheckLoggedMessageHead ("CondItem: Equal to item0", "A1");
+ logger.CheckLoggedMessageHead ("CondItem: Equal to item0's value", "A2");
+ logger.CheckLoggedMessageHead ("CondItem1: Equal to item0", "A3");
+ logger.CheckLoggedMessageHead ("CondItem1: Equal to item0's value", "A4");
+ Assert.AreEqual (0, logger.NormalMessageCount, "unexpected messages found");
+ }
+
+ [Test]
+ // test properties and item refs, with dynamic properties/items
+ public void TestItems12 ()
+ {
+ string project_xml = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
+ <PropertyGroup>
+ <Prop2>@(Ref1)</Prop2>
+ </PropertyGroup>
+ <ItemGroup>
+ <Ref1 Include=""File1"" />
+ <Files Include=""@(Ref1)""/>
+ </ItemGroup>
+
+ <Target Name=""1"">
+ <Message Text=""Prop2: $(Prop2)""/>
+
+ <Message Text=""Files: @(Files)""/>
+ <CreateItem Include=""foobar"">
+ <Output TaskParameter=""Include"" ItemName=""Ref1""/>
+ </CreateItem>
+ <Message Text=""Files: @(Files)""/>
+
+ <Message Text=""Prop2: $(Prop2)""/>
+ <CreateProperty Value=""NewValue"">
+ <Output TaskParameter=""Value"" PropertyName=""Prop2""/>
+ </CreateProperty>
+ <Message Text=""Prop2: $(Prop2)""/>
+ </Target>
+</Project>
+";
+
+ Engine engine = new Engine (Consts.BinPath);
+ Project proj = engine.CreateNewProject ();
+ MonoTests.Microsoft.Build.Tasks.TestMessageLogger logger =
+ new MonoTests.Microsoft.Build.Tasks.TestMessageLogger ();
+ proj.LoadXml (project_xml);
+ engine.RegisterLogger (logger);
+
+ if (!proj.Build ("1")) {
+ logger.DumpMessages ();
+ Assert.Fail ("Build failed");
+ }
+
+ logger.DumpMessages ();
+ logger.CheckLoggedMessageHead ("Prop2: File1", "A1");
+ logger.CheckLoggedMessageHead ("Files: File1", "A1");
+ logger.CheckLoggedMessageHead ("Files: File1", "A1");
+ logger.CheckLoggedMessageHead ("Prop2: File1;foobar", "A1");
+ logger.CheckLoggedMessageHead ("Prop2: NewValue", "A1");
+ Assert.AreEqual (0, logger.NormalMessageCount, "unexpected messages found");
+ }
+
+ [Test]
+ // test item refs in properties
+ public void TestItems13 () {
+ string project_xml = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
+ <PropertyGroup>
+ <Prop1>@(Item0)</Prop1>
+ </PropertyGroup>
+ <ItemGroup>
+ <Item0 Include=""Foo""/>
+ <Item1 Include=""A\B.txt;A\C.txt;B\B.zip;B\C.zip"" />
+ <Item2 Include=""@(Item1->'%(Extension)/$(Prop1)')"" />
+ </ItemGroup>
+
+ <Target Name='1'>
+ <Message Text=""Item2: @(Item2)""/>
+ </Target>
+</Project>";
+
+ Engine engine = new Engine (Consts.BinPath);
+ Project proj = engine.CreateNewProject ();
+ MonoTests.Microsoft.Build.Tasks.TestMessageLogger logger =
+ new MonoTests.Microsoft.Build.Tasks.TestMessageLogger ();
+ proj.LoadXml (project_xml);
+ engine.RegisterLogger (logger);
+
+ if (!proj.Build ("1")) {
+ logger.DumpMessages ();
+ Assert.Fail ("Build failed");
+ }
+
+ logger.CheckLoggedMessageHead ("Item2: .txt/@(Item0);.txt/@(Item0);.zip/@(Item0);.zip/@(Item0)", "A1");
+ Assert.AreEqual (0, logger.NormalMessageCount, "unexpected messages found");
+ }
+
+ [Test]
+ public void TestSelfRefrentialItems ()
+ {
+ string project_xml = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
+ <PropertyGroup>
+ <Prop1>@(Item1);Val</Prop1>
+ <Prop2>@(Item2)</Prop2>
+ <Prop3>@(Item3)</Prop3>
+ </PropertyGroup>
+ <ItemGroup>
+ <Item1 Include=""Item1OldVal""/>
+ <Item1 Include=""@(Item1);$(Prop1)""/>
+
+ <Item2 Include=""Item2OldVal""/>
+ <Item2 Include=""@(Item2->'%(Identity)');$(Prop2)""/>
+
+ <Item3 Include=""Item3OldVal""/>
+ <Item3 Include=""@(Item3, '_');$(Prop3)""/>
+
+ <Item4 Include=""@(Item4)""/>
+ </ItemGroup>
+
+ <Target Name=""1"">
+ <Message Text=""Item1: %(Item1.Identity)""/>
+ <Message Text=""Item2: %(Item2.Identity)""/>
+ <Message Text=""Item3: %(Item3.Identity)""/>
+ <Message Text=""%(Item4.Identity)""/>
+ <Message Text=""Item4: %(Item4.Identity)""/>
+ </Target>
+</Project>
+";
+
+ Engine engine = new Engine (Consts.BinPath);
+ Project proj = engine.CreateNewProject ();
+ MonoTests.Microsoft.Build.Tasks.TestMessageLogger logger =
+ new MonoTests.Microsoft.Build.Tasks.TestMessageLogger ();
+ proj.LoadXml (project_xml);
+ engine.RegisterLogger (logger);
+
+ if (!proj.Build ("1")) {
+ logger.DumpMessages ();
+ Assert.Fail ("Build failed");
+ }
+
+ logger.DumpMessages ();
+ logger.CheckLoggedMessageHead ("Item1: Item1OldVal", "A1");
+ logger.CheckLoggedMessageHead ("Item1: Val", "A2");
+ logger.CheckLoggedMessageHead ("Item2: Item2OldVal", "A3");
+ logger.CheckLoggedMessageHead ("Item3: Item3OldVal", "A4");
+ logger.CheckLoggedMessageHead ("Item4: ", "A5");
+ Assert.AreEqual (0, logger.NormalMessageCount, "unexpected messages found");
+ }
+
+ [Test]
+ public void TestEmptyItemsWithBatching ()
+ {
+ string project_xml = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
+ <UsingTask TaskName='StringTestTask' AssemblyFile='Test\resources\TestTasks.dll' />
+ <UsingTask TaskName='TestTask_TaskItem' AssemblyFile='Test\resources\TestTasks.dll' />
+ <UsingTask TaskName='TestTask_TaskItems' AssemblyFile='Test\resources\TestTasks.dll' />
+ <Target Name=""1"">
+ <StringTestTask Property=""%(Item4.Identity)"">
+ <Output TaskParameter=""OutputString"" PropertyName=""OutputString""/>
+ </StringTestTask>
+ <Message Text='output1: $(OutputString)'/>
+
+ <StringTestTask Property="" %(Item4.Identity)"">
+ <Output TaskParameter=""OutputString"" PropertyName=""OutputString""/>
+ </StringTestTask>
+ <Message Text='output2: $(OutputString)'/>
+
+ <StringTestTask Array=""%(Item4.Identity)"">
+ <Output TaskParameter=""OutputString"" PropertyName=""OutputString""/>
+ </StringTestTask>
+ <Message Text='output3: $(OutputString)'/>
+
+ <StringTestTask Array="" %(Item4.Identity)"">
+ <Output TaskParameter=""OutputString"" PropertyName=""OutputString""/>
+ </StringTestTask>
+ <Message Text='output4: $(OutputString)'/>
+
+
+ <TestTask_TaskItem Property=""%(Item4.Identity)"">
+ <Output TaskParameter=""Output"" PropertyName=""OutputString""/>
+ </TestTask_TaskItem>
+ <Message Text='output5: $(OutputString)'/>
+
+ <TestTask_TaskItem Property="" %(Item4.Identity)"">
+ <Output TaskParameter=""Output"" PropertyName=""OutputString""/>
+ </TestTask_TaskItem>
+ <Message Text='output6: $(OutputString)'/>
+
+
+ <TestTask_TaskItems Property="" %(Item4.Identity)"">
+ <Output TaskParameter=""Output"" PropertyName=""OutputString""/>
+ </TestTask_TaskItems>
+ <Message Text='output7: $(OutputString)'/>
+
+
+ <!-- no space in property -->
+ <TestTask_TaskItems Property=""%(Item4.Identity)"">
+ <Output TaskParameter=""Output"" PropertyName=""OutputString""/>
+ </TestTask_TaskItems>
+ <Message Text='output8: $(OutputString)'/>
+
+ </Target>
+</Project>
+";
+
+ Engine engine = new Engine (Consts.BinPath);
+ Project proj = engine.CreateNewProject ();
+ MonoTests.Microsoft.Build.Tasks.TestMessageLogger logger =
+ new MonoTests.Microsoft.Build.Tasks.TestMessageLogger ();
+ proj.LoadXml (project_xml);
+ engine.RegisterLogger (logger);
+
+ if (!proj.Build ("1")) {
+ logger.DumpMessages ();
+ Assert.Fail ("Build failed");
+ }
+
+ logger.DumpMessages ();
+ logger.CheckLoggedMessageHead ("output1: property: null ## array: null", "A1");
+ logger.CheckLoggedMessageHead ("output2: property: ## array: null", "A2");
+ logger.CheckLoggedMessageHead ("output3: property: null ## array: null", "A3");
+ logger.CheckLoggedMessageHead ("output4: property: null ## array: null", "A4");
+
+ logger.CheckLoggedMessageHead ("output5: null", "A5");
+ logger.CheckLoggedMessageHead ("output6: null", "A6");
+ logger.CheckLoggedMessageHead ("output7: null", "A7");
+ logger.CheckLoggedMessageHead ("output8: null", "A8");
+
+ Assert.AreEqual (0, logger.NormalMessageCount, "unexpected messages found");
+ }
+
[Test]
public void TestItemsInTarget1 ()
{
<UsingTask TaskName='StringTestTask' AssemblyFile='Test\resources\TestTasks.dll' />
<PropertyGroup>
<A>A</A>
+ <B>@(A)g</B>
</PropertyGroup>
<ItemGroup>
<A Include='A;B;C' />
<StringTestTask Property=""@(A,'@(A,'')')"">
<Output TaskParameter='Property' PropertyName='P5' />
</StringTestTask>
+ <StringTestTask Property=""@(A,'$(B)')"">
+ <Output TaskParameter='Property' PropertyName='P6' />
+ </StringTestTask>
<StringTestTask Property=""%(A.Filename)"">
<Output TaskParameter='Property' ItemName='I1' />
</StringTestTask>
</Project>
";
+ MonoTests.Microsoft.Build.Tasks.TestMessageLogger logger = new MonoTests.Microsoft.Build.Tasks.TestMessageLogger ();
+ engine.RegisterLogger (logger);
proj.LoadXml (documentString);
- Assert.IsTrue (proj.Build ("1"), "A0, Build failed");
+ if (!proj.Build ("1")) {
+ logger.DumpMessages ();
+ Assert.Fail ("build failed");
+ }
Assert.AreEqual ("A;B;C", proj.GetEvaluatedProperty ("P1"), "A1");
Assert.AreEqual ("ABC", proj.GetEvaluatedProperty ("P2"), "A2");
Assert.AreEqual ("A@(A)B@(A)C", proj.GetEvaluatedProperty ("P3"), "A3");
Assert.AreEqual ("AABAC", proj.GetEvaluatedProperty ("P4"), "A4");
Assert.AreEqual ("@(A,'ABC')", proj.GetEvaluatedProperty ("P5"), "A5");
+ Assert.AreEqual ("A@(A)gB@(A)gC", proj.GetEvaluatedProperty ("P6"), "A6");
CheckItems (proj, "I1", "A6", "A", "B", "C");
CheckItems (proj, "I2", "A7", "A A", "B B", "C C");
}
CheckItems (proj, "I5", "A5", "A", "Foo A", "Bar", "A", "B");
CheckItems (proj, "I6", "A6", "A", "B", "C", "A");
CheckItems (proj, "I7", "A7", "A", "B", "C", "A", "B", "C");
- CheckItems (proj, "I8", "A8", "abc", "A", "B", "C", "A", "foo");
+ CheckItems(proj, "I8", "A8", "abc", "A", "B", "C", "A", "foo");
}
[Test]
{
Engine engine = new Engine (Consts.BinPath);
Project proj = engine.CreateNewProject ();
+ MonoTests.Microsoft.Build.Tasks.TestMessageLogger logger =
+ new MonoTests.Microsoft.Build.Tasks.TestMessageLogger();
+ engine.RegisterLogger(logger);
string documentString = @"
<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
"$(C) $(C)",
"@(A);$(C)",
"@(A);A;B;C",
- "@(A) $(C) @(A)"
+ "@(A) $(C) @(A)",
}) + "</Project>";
proj.LoadXml (documentString);
- Assert.IsTrue (proj.Build ("1"), "Build failed");
+ if (!proj.Build("1")) {
+ logger.DumpMessages();
+ Assert.Fail("Build failed");
+ }
BuildProperty bp = proj.EvaluatedProperties ["D"];
Assert.AreEqual ("$(C);Foo", bp.Value, "B0");