Skip to content

Commit 5e23163

Browse files
jpobstjonpryor
authored andcommitted
[generator] Support XML defined enums with no JNI info (#659)
Fixes: #515 Our `.csv` format for specifying enums allows creating enum fields that do not map to a JNI field. This is often used to add a `None` enum field to a Java `[Flags]` enum: 0,,0,Android.AccessibilityServices.AccessibilityServiceCapabilities,None However our XML format does not support this because it considers the (`//mapping/@jni-class` or `//mapping/@jni-interface`) and `//mapping/@jni-name` attributes to be mandatory when translating the XML format to `.csv` format. We can remove this restriction and correctly generate the needed `.csv` format so that users using the XML format can add arbitrary enums that `generator` knows about, permitting: <mapping clr-enum-type='Android.Support.V4.App.FragmentTagType' bitfield='true'> <field clr-name='Name' value='0' /> <field clr-name='Id' value='1' /> <field clr-name='Tag' value='2' /> </mapping> in addition to the previously required: <mapping jni-interface='android/support/v4/app/FragmentActivity$FragmentTag' clr-enum-type='Android.Support.V4.App.FragmentTagType' bitfield='true'> <field jni-name='Fragment_name' clr-name='Name' value='0' /> <field jni-name='Fragment_id' clr-name='Id' value='1' /> <field jni-name='Fragment_tag' clr-name='Tag' value='2' /> </mapping>
1 parent 5c4581d commit 5e23163

File tree

2 files changed

+120
-15
lines changed

2 files changed

+120
-15
lines changed

src/utils/EnumMappings.Xml.cs

+23-15
Original file line numberDiff line numberDiff line change
@@ -23,25 +23,33 @@ internal static TextReader FieldXmlToCsv (string file)
2323
if (file == null)
2424
return null;
2525

26+
return FieldXmlToCsv (XDocument.Load (file, LoadOptions.SetBaseUri | LoadOptions.SetLineInfo));
27+
}
28+
29+
internal static TextReader FieldXmlToCsv (XDocument doc)
30+
{
2631
var sw = new StringWriter ();
27-
var doc = XDocument.Load (file, LoadOptions.SetBaseUri | LoadOptions.SetLineInfo);
2832

2933
foreach (var e in doc.XPathSelectElements ("/enum-field-mappings/mapping")) {
30-
string enu = GetMandatoryAttribute (e, "clr-enum-type");
31-
string jni_type = e.Attribute ("jni-class") != null
32-
? e.XGetAttribute ("jni-class")
33-
: e.Attribute ("jni-interface") != null
34-
? "I:" + e.XGetAttribute ("jni-interface")
35-
: GetMandatoryAttribute (e, "jni-class or jni-interface");
36-
bool bitfield = e.Attribute ("bitfield") != null && e.XGetAttribute ("bitfield") == "true";
34+
35+
var enu = GetMandatoryAttribute (e, "clr-enum-type");
36+
var jni_type = e.XGetAttribute ("jni-class") ?? "I:" + e.XGetAttribute ("jni-interface");
37+
38+
// If neither jni was specified leave it blank
39+
if (jni_type == "I:")
40+
jni_type = string.Empty;
41+
42+
var bitfield = e.XGetAttribute ("bitfield") == "true";
43+
3744
foreach (var m in e.XPathSelectElements ("field")) {
38-
string verstr = m.Attribute ("api-level") != null
39-
? m.XGetAttribute ("api-level")
40-
: "0";
41-
string member = GetMandatoryAttribute (m, "clr-name");
42-
string jni_name = GetMandatoryAttribute (m, "jni-name");
43-
string value = GetMandatoryAttribute (m, "value");
44-
sw.WriteLine ("{0}, {1}, {2}, {3}, {4}{5}", verstr, enu, member, jni_type + '.' + jni_name, value, bitfield ? ", Flags" : null);
45+
var verstr = m.XGetAttribute ("api-level") ?? "0";
46+
var member = GetMandatoryAttribute (m, "clr-name");
47+
var jni_name = m.XGetAttribute ("jni-name");
48+
var value = GetMandatoryAttribute (m, "value");
49+
50+
var jni_member = string.IsNullOrWhiteSpace (jni_name) ? string.Empty : jni_type + '.' + jni_name;
51+
52+
sw.WriteLine ("{0}, {1}, {2}, {3}, {4}{5}", verstr, enu, member, jni_member, value, bitfield ? ", Flags" : null);
4553
}
4654
}
4755

tests/generator-Tests/Unit-Tests/EnumMappingsTests.cs

+97
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Linq;
55
using System.Text;
66
using System.Threading.Tasks;
7+
using System.Xml.Linq;
78
using MonoDroid.Generation;
89
using NUnit.Framework;
910

@@ -284,5 +285,101 @@ public void TransientEnumificationV2Test ()
284285
Assert.AreEqual ("[Cdsect, I:org/xmlpull/v1/XmlPullParser.CDSECT]", enums.First ().Value.JniNames.Single ().ToString ());
285286
Assert.AreEqual ("[Cdsect, 5]", enums.First ().Value.Members.Single ().ToString ());
286287
}
288+
289+
[Test]
290+
public void XmlEnumMapWithJNI ()
291+
{
292+
var xml = @"<enum-field-mappings>
293+
<mapping jni-class='android/support/v4/app/FragmentActivity$FragmentTag' clr-enum-type='Android.Support.V4.App.FragmentTagType'>
294+
<field jni-name='Fragment_name' clr-name='Name' value='0' />
295+
<field jni-name='Fragment_id' clr-name='Id' value='1' />
296+
<field jni-name='Fragment_tag' clr-name='Tag' value='2' />
297+
</mapping>
298+
</enum-field-mappings>";
299+
300+
var doc = XDocument.Parse (xml, LoadOptions.SetBaseUri | LoadOptions.SetLineInfo);
301+
var sr = EnumMappings.FieldXmlToCsv (doc);
302+
303+
var lines = sr.ReadToEnd ().Split (new [] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
304+
var expected = new [] {
305+
"0, Android.Support.V4.App.FragmentTagType, Name, android/support/v4/app/FragmentActivity$FragmentTag.Fragment_name, 0",
306+
"0, Android.Support.V4.App.FragmentTagType, Id, android/support/v4/app/FragmentActivity$FragmentTag.Fragment_id, 1",
307+
"0, Android.Support.V4.App.FragmentTagType, Tag, android/support/v4/app/FragmentActivity$FragmentTag.Fragment_tag, 2"
308+
};
309+
310+
Assert.AreEqual (expected, lines);
311+
}
312+
313+
[Test]
314+
public void XmlEnumMapWithInterfaceJNI ()
315+
{
316+
var xml = @"<enum-field-mappings>
317+
<mapping jni-interface='android/support/v4/app/FragmentActivity$FragmentTag' clr-enum-type='Android.Support.V4.App.FragmentTagType' bitfield='true'>
318+
<field jni-name='Fragment_name' clr-name='Name' value='0' />
319+
<field jni-name='Fragment_id' clr-name='Id' value='1' />
320+
<field jni-name='Fragment_tag' clr-name='Tag' value='2' />
321+
</mapping>
322+
</enum-field-mappings>";
323+
324+
var doc = XDocument.Parse (xml, LoadOptions.SetBaseUri | LoadOptions.SetLineInfo);
325+
var sr = EnumMappings.FieldXmlToCsv (doc);
326+
327+
var lines = sr.ReadToEnd ().Split (new [] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
328+
var expected = new [] {
329+
"0, Android.Support.V4.App.FragmentTagType, Name, I:android/support/v4/app/FragmentActivity$FragmentTag.Fragment_name, 0, Flags",
330+
"0, Android.Support.V4.App.FragmentTagType, Id, I:android/support/v4/app/FragmentActivity$FragmentTag.Fragment_id, 1, Flags",
331+
"0, Android.Support.V4.App.FragmentTagType, Tag, I:android/support/v4/app/FragmentActivity$FragmentTag.Fragment_tag, 2, Flags"
332+
};
333+
334+
Assert.AreEqual (expected, lines);
335+
}
336+
337+
[Test]
338+
public void XmlEnumMapWithoutJNI ()
339+
{
340+
var xml = @"<enum-field-mappings>
341+
<mapping clr-enum-type='Android.Support.V4.App.FragmentTagType' bitfield='true'>
342+
<field clr-name='Name' value='0' />
343+
<field clr-name='Id' value='1' />
344+
<field clr-name='Tag' value='2' />
345+
</mapping>
346+
</enum-field-mappings>";
347+
348+
var doc = XDocument.Parse (xml, LoadOptions.SetBaseUri | LoadOptions.SetLineInfo);
349+
var sr = EnumMappings.FieldXmlToCsv (doc);
350+
351+
var lines = sr.ReadToEnd ().Split (new [] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
352+
var expected = new [] {
353+
"0, Android.Support.V4.App.FragmentTagType, Name, , 0, Flags",
354+
"0, Android.Support.V4.App.FragmentTagType, Id, , 1, Flags",
355+
"0, Android.Support.V4.App.FragmentTagType, Tag, , 2, Flags"
356+
};
357+
358+
Assert.AreEqual (expected, lines);
359+
}
360+
361+
[Test]
362+
public void XmlEnumMapWithMixedJNI ()
363+
{
364+
var xml = @"<enum-field-mappings>
365+
<mapping jni-class='android/support/v4/app/FragmentActivity$FragmentTag' clr-enum-type='Android.Support.V4.App.FragmentTagType' bitfield='true'>
366+
<field clr-name='Name' value='0' />
367+
<field jni-name='Fragment_id' clr-name='Id' value='1' />
368+
<field clr-name='Tag' value='2' />
369+
</mapping>
370+
</enum-field-mappings>";
371+
372+
var doc = XDocument.Parse (xml, LoadOptions.SetBaseUri | LoadOptions.SetLineInfo);
373+
var sr = EnumMappings.FieldXmlToCsv (doc);
374+
375+
var lines = sr.ReadToEnd ().Split (new [] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
376+
var expected = new [] {
377+
"0, Android.Support.V4.App.FragmentTagType, Name, , 0, Flags",
378+
"0, Android.Support.V4.App.FragmentTagType, Id, android/support/v4/app/FragmentActivity$FragmentTag.Fragment_id, 1, Flags",
379+
"0, Android.Support.V4.App.FragmentTagType, Tag, , 2, Flags"
380+
};
381+
382+
Assert.AreEqual (expected, lines);
383+
}
287384
}
288385
}

0 commit comments

Comments
 (0)