diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/Aapt.cs b/src/Xamarin.Android.Build.Tasks/Tasks/Aapt.cs index 3ff06581597..3d02828977f 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/Aapt.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/Aapt.cs @@ -364,8 +364,9 @@ protected void LogEventsFromTextOutput (string singleLine, MessageImportance mes int line = 0; if (!string.IsNullOrEmpty (match.Groups["line"]?.Value)) line = int.Parse (match.Groups["line"].Value) + 1; - var error = match.Groups["message"].Value; - if (error.Contains ("warning")) { + var level = match.Groups["level"].Value; + var message = match.Groups ["message"].Value; + if (level.Contains ("warning")) { LogWarning (singleLine); return; } @@ -379,10 +380,10 @@ protected void LogEventsFromTextOutput (string singleLine, MessageImportance mes } // Strip any "Error:" text from aapt's output - if (error.StartsWith ("error: ", StringComparison.InvariantCultureIgnoreCase)) - error = error.Substring ("error: ".Length); + if (message.StartsWith ("error: ", StringComparison.InvariantCultureIgnoreCase)) + message = message.Substring ("error: ".Length); - LogError ("APT0000", error, file, line); + LogError ("APT0000", message, file, line); return; } diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/AndroidToolTask.cs b/src/Xamarin.Android.Build.Tasks/Tasks/AndroidToolTask.cs index b53d4322f4d..18f66b83916 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/AndroidToolTask.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/AndroidToolTask.cs @@ -80,10 +80,32 @@ protected virtual Regex ErrorRegex { // res/drawable/foo-bar.jpg: Invalid file name: must contain only [a-z0-9_.] // Look for them and convert them to MSBuild compatible errors. static Regex androidErrorRegex; - internal static Regex AndroidErrorRegex { + public static Regex AndroidErrorRegex { get { if (androidErrorRegex == null) - androidErrorRegex = new Regex (@"^(?.+?)([:(](?\d+)[:)])?:+\s*((error)\s*(?\w*(?=:)):?)?(?.*)", RegexOptions.Compiled | RegexOptions.ExplicitCapture); + androidErrorRegex = new Regex (@" +^ +( # start optional path followed by `:` + (? + (?.+[\\/][^:\(]+) + ( + ([:](?\d+)) + | + (\((?\d+)\)) + )? + ) + \s* + : +)? +( # optional warning|error: + \s* + (?(warning|error)[^:]*)\s* + : +)? +\s* +(?.*) +$ +", RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.IgnorePatternWhitespace); return androidErrorRegex; } } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidRegExTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidRegExTests.cs new file mode 100644 index 00000000000..ab9162330f0 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidRegExTests.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using NUnit.Framework; + +namespace Xamarin.Android.Build.Tests +{ + public class AndroidRegExTests + { + + + /* +"Resources/values/theme.xml(2): error APT0000: Error retrieving parent for item: No resource found that matches the given name '@android:style/Theme.AppCompat'." \ + "Resources/values/theme.xml:2: error APT0000: Error retrieving parent for item: No resource found that matches the given name '@android:style/Theme.AppCompat'." \ + "res/drawable/foo-bar.jpg: Invalid file name: must contain only [a-z0-9_.]" + + */ + class AndroidRegExTestsCases : IEnumerable { + public IEnumerator GetEnumerator () + { + yield return new object [] { + /*message*/ "warning: string 'app_name1' has no default translation.", + /*expectedToMatch*/ true, + /*expectedFile*/ "", + /*expectedLine*/ "", + /*expectedLevel*/ "warning", + /*expectedMessage*/ "string 'app_name1' has no default translation." + }; + yield return new object [] { + /*message*/ "res\\layout\\main.axml: error: No resource identifier found for attribute \"id2\" in package \"android\" (TaskId:22)", + /*expectedToMatch*/ true, + /*expectedFile*/ "res\\layout\\main.axml", + /*expectedLine*/ "", + /*expectedLevel*/ "error", + /*expectedMessage*/ "No resource identifier found for attribute \"id2\" in package \"android\" (TaskId:22)" + }; + yield return new object [] { + /*message*/ "Resources/values/theme.xml(2): error APT0000: Error retrieving parent for item: No resource found that matches the given name '@android:style/Theme.AppCompat'.", + /*expectedToMatch*/ true, + /*expectedFile*/ "Resources/values/theme.xml", + /*expectedLine*/ "2", + /*expectedLevel*/ "error APT0000", + /*expectedMessage*/ "Error retrieving parent for item: No resource found that matches the given name '@android:style/Theme.AppCompat'." + }; + yield return new object [] { + /*message*/ "Resources/values/theme.xml:2: error APT0000: Error retrieving parent for item: No resource found that matches the given name '@android:style/Theme.AppCompat'.", + /*expectedToMatch*/ true, + /*expectedFile*/ "Resources/values/theme.xml", + /*expectedLine*/ "2", + /*expectedLevel*/ "error APT0000", + /*expectedMessage*/ "Error retrieving parent for item: No resource found that matches the given name '@android:style/Theme.AppCompat'." + }; + yield return new object [] { + /*message*/ "res/drawable/foo-bar.jpg: Invalid file name: must contain only [a-z0-9_.]", + /*expectedToMatch*/ true, + /*expectedFile*/ "res/drawable/foo-bar.jpg", + /*expectedLine*/ "", + /*expectedLevel*/ "", + /*expectedMessage*/ "Invalid file name: must contain only [a-z0-9_.]" + }; + + } + } + + [Test] + [TestCaseSource(typeof (AndroidRegExTestsCases))] + public void RegExTests(string message, bool expectedToMatch, string expectedFile, string expectedLine, string expectedLevel, string expextedMessage) + { + var regex = Xamarin.Android.Tasks.AndroidToolTask.AndroidErrorRegex; + var result = regex.Match (message); + Assert.AreEqual (expectedToMatch,result.Success); + Assert.AreEqual (expectedFile, result.Groups["file"].Value); + Assert.AreEqual (expectedLine.ToString (), result.Groups ["line"].Value); + Assert.AreEqual (expectedLevel, result.Groups ["level"].Value); + Assert.AreEqual (expextedMessage, result.Groups ["message"].Value); + } + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidUpdateResourcesTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidUpdateResourcesTest.cs index bd2905b787d..a0ea8e8bcc3 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidUpdateResourcesTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidUpdateResourcesTest.cs @@ -1083,5 +1083,29 @@ public void BuildAppWithManagedResourceParserAndLibraries () } } } + + [Test] + public void CheckDefaultTranslationWarnings () + { + var path = Path.Combine ("temp", TestName); + var proj = new XamarinAndroidApplicationProject () { + IsRelease = true, + OtherBuildItems = { + new BuildItem.Folder ("Resources\\values-fr\\") { + }, + }, + }; + + proj.AndroidResources.Add (new AndroidItem.AndroidResource ("Resources\\values-fr\\Strings.xml") { + TextContent = () => @" + + Test +", + }); + using (var builder = CreateApkBuilder (path, false, false)) { + Assert.IsTrue (builder.Build (proj), "Build should have succeeded."); + StringAssert.Contains ("has no default translation", builder.LastBuildOutput, "Build output should contain a warning about 'no default translation'"); + } + } } } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Xamarin.Android.Build.Tests.csproj b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Xamarin.Android.Build.Tests.csproj index 11100590be9..9a04c0c8228 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Xamarin.Android.Build.Tests.csproj +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Xamarin.Android.Build.Tests.csproj @@ -38,6 +38,14 @@ ..\..\..\..\packages\NUnit.3.7.1\lib\net45\nunit.framework.dll + + + + @@ -49,6 +57,10 @@ {E248B2CA-303B-4645-ADDC-9D4459D550FD} libZipSharp + + {3F1F2F50-AF1A-4A5A-BEDB-193372F068D7} + Xamarin.Android.Build.Tasks + @@ -59,5 +71,6 @@ + diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/BuildActions.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/BuildActions.cs index 668f90adf32..c23af2dfcb1 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/BuildActions.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/BuildActions.cs @@ -15,5 +15,6 @@ public static class BuildActions public const string Compile = "Compile"; public const string EmbeddedResource = "EmbeddedResource"; public const string Content = "Content"; + public const string Folder = "Folder"; } } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/BuildItem.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/BuildItem.cs index ba5ec269195..bef93df1404 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/BuildItem.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/BuildItem.cs @@ -34,6 +34,18 @@ public NoActionResource (Func include) } } + public class Folder : BuildItem + { + public Folder (string include) + : this (() => include) + { + } + public Folder (Func include) + : base (BuildActions.Folder, include) + { + } + } + public class Content : BuildItem { public Content (string include)