From db455f56484c0f3c220e1ee4d15b9c775a3ae976 Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Fri, 13 Jan 2017 10:43:52 -0800 Subject: [PATCH 01/60] Consolidating nuget packaging logic in icu.net.csproj --- source/icu.net/icu.net.csproj | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/source/icu.net/icu.net.csproj b/source/icu.net/icu.net.csproj index 4a9860b6..c3249af6 100644 --- a/source/icu.net/icu.net.csproj +++ b/source/icu.net/icu.net.csproj @@ -115,6 +115,8 @@ + net40 + ..\..\lib\icu ..\..\output\$(Configuration) $(DefineConstants);ICU_VER_$(icu_ver) true @@ -188,8 +190,12 @@ --> + + $(SolutionDir)NuGetBuild/$(PlatformAlias) + $(ProjectDir)NuGetAssets + - + @@ -197,10 +203,10 @@ - - - - + + + + From 21bbfb7ef12d819208e39cf03c50737e9b101cc9 Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Wed, 30 Mar 2016 15:20:51 -0700 Subject: [PATCH 02/60] Updating .gitignore --- .gitignore | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 1b3939a1..cf35c463 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ build/NuGet.exe build/nuget.exe lib/ output/ +bin/ obj/ test-results/ .idea/ @@ -15,4 +16,13 @@ source/packages/ source/NuGetBuild/ # Visual Studio 2015 cache/options directory -.vs/ \ No newline at end of file +.vs/ + +# DNX +*project.lock.json +*project.fragment.lock.json +artifacts/ + +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets \ No newline at end of file From fde4236d80d9d340fc3668e1ecdc70367f08922b Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Fri, 13 Jan 2017 09:14:21 -0800 Subject: [PATCH 03/60] Replacing unsupported exceptions in .NETStandard --- source/icu.net/ErrorCode.cs | 170 +++++++++--------- source/icu.net/Exceptions/BreakException.cs | 17 ++ source/icu.net/Exceptions/IDNAException.cs | 17 ++ .../Exceptions/MissingResourceException.cs | 17 ++ source/icu.net/Exceptions/RegexException.cs | 17 ++ .../Exceptions/SyntaxErrorException.cs | 17 ++ .../TransliteratorParseException.cs | 17 ++ source/icu.net/Exceptions/WarningException.cs | 17 ++ source/icu.net/icu.net.csproj | 7 + 9 files changed, 210 insertions(+), 86 deletions(-) create mode 100644 source/icu.net/Exceptions/BreakException.cs create mode 100644 source/icu.net/Exceptions/IDNAException.cs create mode 100644 source/icu.net/Exceptions/MissingResourceException.cs create mode 100644 source/icu.net/Exceptions/RegexException.cs create mode 100644 source/icu.net/Exceptions/SyntaxErrorException.cs create mode 100644 source/icu.net/Exceptions/TransliteratorParseException.cs create mode 100644 source/icu.net/Exceptions/WarningException.cs diff --git a/source/icu.net/ErrorCode.cs b/source/icu.net/ErrorCode.cs index 8e7f95ef..53b9dfac 100644 --- a/source/icu.net/ErrorCode.cs +++ b/source/icu.net/ErrorCode.cs @@ -1,8 +1,6 @@ // Copyright (c) 2013 SIL International // This software is licensed under the MIT license (http://opensource.org/licenses/MIT) using System; -using System.ComponentModel; -using System.Data; using System.IO; namespace Icu @@ -428,15 +426,15 @@ private static void ThrowIfError(ErrorCode e, string extraInfo, bool throwOnWarn case ErrorCode.ILLEGAL_ARGUMENT_ERROR: throw new ArgumentException(extraInfo); case ErrorCode.MISSING_RESOURCE_ERROR: - throw new ApplicationException("The requested resource cannot be found " + extraInfo); + throw new MissingResourceException("The requested resource cannot be found " + extraInfo); case ErrorCode.INVALID_FORMAT_ERROR: - throw new ApplicationException("Data format is not what is expected " + extraInfo); + throw new ArgumentException("Data format is not what is expected " + extraInfo); case ErrorCode.FILE_ACCESS_ERROR: throw new FileNotFoundException("The requested file cannot be found " + extraInfo); case ErrorCode.INTERNAL_PROGRAM_ERROR: throw new InvalidOperationException("Indicates a bug in the library code " + extraInfo); case ErrorCode.MESSAGE_PARSE_ERROR: - throw new ApplicationException("Unable to parse a message (message format) " + extraInfo); + throw new ArgumentException("Unable to parse a message (message format) " + extraInfo); case ErrorCode.MEMORY_ALLOCATION_ERROR: throw new OutOfMemoryException(extraInfo); case ErrorCode.INDEX_OUTOFBOUNDS_ERROR: @@ -454,7 +452,7 @@ private static void ThrowIfError(ErrorCode e, string extraInfo, bool throwOnWarn case ErrorCode.INVALID_TABLE_FILE: throw new FileNotFoundException("Conversion table file not found " + extraInfo); case ErrorCode.BUFFER_OVERFLOW_ERROR: - throw new InternalBufferOverflowException("A result would not fit in the supplied buffer " + extraInfo); + throw new OverflowException("A result would not fit in the supplied buffer " + extraInfo); case ErrorCode.UNSUPPORTED_ERROR: throw new InvalidOperationException("Requested operation not supported in current context " + extraInfo); case ErrorCode.RESOURCE_TYPE_MISMATCH: @@ -472,79 +470,79 @@ private static void ThrowIfError(ErrorCode e, string extraInfo, bool throwOnWarn case ErrorCode.STATE_TOO_OLD_ERROR: throw new NotSupportedException("ICU cannot construct a service from this state, as it is no longer supported " + extraInfo); case ErrorCode.TOO_MANY_ALIASES_ERROR: - throw new ApplicationException("There are too many aliases in the path to the requested resource.\nIt is very possible that a circular alias definition has occured " + extraInfo); + throw new ArgumentException("There are too many aliases in the path to the requested resource.\nIt is very possible that a circular alias definition has occured " + extraInfo); case ErrorCode.ENUM_OUT_OF_SYNC_ERROR: throw new InvalidOperationException("Enumeration out of sync with underlying collection " + extraInfo); case ErrorCode.INVARIANT_CONVERSION_ERROR: - throw new ApplicationException("Unable to convert a UChar* string to char* with the invariant converter " + extraInfo); + throw new ArgumentException("Unable to convert a UChar* string to char* with the invariant converter " + extraInfo); case ErrorCode.INVALID_STATE_ERROR: throw new InvalidOperationException("Requested operation can not be completed with ICU in its current state " + extraInfo); case ErrorCode.COLLATOR_VERSION_MISMATCH: throw new InvalidOperationException("Collator version is not compatible with the base version " + extraInfo); case ErrorCode.USELESS_COLLATOR_ERROR: - throw new ApplicationException("Collator is options only and no base is specified " + extraInfo); + throw new ArgumentException("Collator is options only and no base is specified " + extraInfo); case ErrorCode.NO_WRITE_PERMISSION: - throw new ApplicationException("Attempt to modify read-only or constant data. " + extraInfo); + throw new InvalidOperationException("Attempt to modify read-only or constant data. " + extraInfo); case ErrorCode.BAD_VARIABLE_DEFINITION: - throw new ApplicationException("Transliterator Parse Error: Missing '$' or duplicate variable name " + extraInfo); + throw new TransliteratorParseException("Transliterator Parse Error: Missing '$' or duplicate variable name " + extraInfo); case ErrorCode.MALFORMED_RULE: - throw new ApplicationException("Transliterator Parse Error: Elements of a rule are misplaced " + extraInfo); + throw new TransliteratorParseException("Transliterator Parse Error: Elements of a rule are misplaced " + extraInfo); case ErrorCode.MALFORMED_SET: - throw new ApplicationException("Transliterator Parse Error: A UnicodeSet pattern is invalid " + extraInfo); + throw new TransliteratorParseException("Transliterator Parse Error: A UnicodeSet pattern is invalid " + extraInfo); case ErrorCode.MALFORMED_UNICODE_ESCAPE: - throw new ApplicationException("Transliterator Parse Error: A Unicode escape pattern is invalid " + extraInfo); + throw new TransliteratorParseException("Transliterator Parse Error: A Unicode escape pattern is invalid " + extraInfo); case ErrorCode.MALFORMED_VARIABLE_DEFINITION: - throw new ApplicationException("Transliterator Parse Error: A variable definition is invalid " + extraInfo); + throw new TransliteratorParseException("Transliterator Parse Error: A variable definition is invalid " + extraInfo); case ErrorCode.MALFORMED_VARIABLE_REFERENCE: - throw new ApplicationException("Transliterator Parse Error: A variable reference is invalid " + extraInfo); + throw new TransliteratorParseException("Transliterator Parse Error: A variable reference is invalid " + extraInfo); case ErrorCode.MISPLACED_ANCHOR_START: - throw new ApplicationException("Transliterator Parse Error: A start anchor appears at an illegal position " + extraInfo); + throw new TransliteratorParseException("Transliterator Parse Error: A start anchor appears at an illegal position " + extraInfo); case ErrorCode.MISPLACED_CURSOR_OFFSET: - throw new ApplicationException("Transliterator Parse Error: A cursor offset occurs at an illegal position " + extraInfo); + throw new TransliteratorParseException("Transliterator Parse Error: A cursor offset occurs at an illegal position " + extraInfo); case ErrorCode.MISPLACED_QUANTIFIER: - throw new ApplicationException("Transliterator Parse Error: A quantifier appears after a segment close delimiter " + extraInfo); + throw new TransliteratorParseException("Transliterator Parse Error: A quantifier appears after a segment close delimiter " + extraInfo); case ErrorCode.MISSING_OPERATOR: - throw new ApplicationException("Transliterator Parse Error: A rule contains no operator " + extraInfo); + throw new TransliteratorParseException("Transliterator Parse Error: A rule contains no operator " + extraInfo); case ErrorCode.MULTIPLE_ANTE_CONTEXTS: - throw new ApplicationException("Transliterator Parse Error: More than one ante context " + extraInfo); + throw new TransliteratorParseException("Transliterator Parse Error: More than one ante context " + extraInfo); case ErrorCode.MULTIPLE_CURSORS: - throw new ApplicationException("Transliterator Parse Error: More than one cursor " + extraInfo); + throw new TransliteratorParseException("Transliterator Parse Error: More than one cursor " + extraInfo); case ErrorCode.MULTIPLE_POST_CONTEXTS: - throw new ApplicationException("Transliterator Parse Error: More than one post context " + extraInfo); + throw new TransliteratorParseException("Transliterator Parse Error: More than one post context " + extraInfo); case ErrorCode.TRAILING_BACKSLASH: - throw new ApplicationException("Transliterator Parse Error: A dangling backslash " + extraInfo); + throw new TransliteratorParseException("Transliterator Parse Error: A dangling backslash " + extraInfo); case ErrorCode.UNDEFINED_SEGMENT_REFERENCE: - throw new ApplicationException("Transliterator Parse Error: A segment reference does not correspond to a defined segment " + extraInfo); + throw new TransliteratorParseException("Transliterator Parse Error: A segment reference does not correspond to a defined segment " + extraInfo); case ErrorCode.UNDEFINED_VARIABLE: - throw new ApplicationException("Transliterator Parse Error: A variable reference does not correspond to a defined variable " + extraInfo); + throw new TransliteratorParseException("Transliterator Parse Error: A variable reference does not correspond to a defined variable " + extraInfo); case ErrorCode.UNQUOTED_SPECIAL: - throw new ApplicationException("Transliterator Parse Error: A special character was not quoted or escaped " + extraInfo); + throw new TransliteratorParseException("Transliterator Parse Error: A special character was not quoted or escaped " + extraInfo); case ErrorCode.UNTERMINATED_QUOTE: - throw new ApplicationException("Transliterator Parse Error: A closing single quote is missing " + extraInfo); + throw new TransliteratorParseException("Transliterator Parse Error: A closing single quote is missing " + extraInfo); case ErrorCode.RULE_MASK_ERROR: - throw new ApplicationException("Transliterator Parse Error: A rule is hidden by an earlier more general rule " + extraInfo); + throw new TransliteratorParseException("Transliterator Parse Error: A rule is hidden by an earlier more general rule " + extraInfo); case ErrorCode.MISPLACED_COMPOUND_FILTER: - throw new ApplicationException("Transliterator Parse Error: A compound filter is in an invalid location " + extraInfo); + throw new TransliteratorParseException("Transliterator Parse Error: A compound filter is in an invalid location " + extraInfo); case ErrorCode.MULTIPLE_COMPOUND_FILTERS: - throw new ApplicationException("Transliterator Parse Error: More than one compound filter " + extraInfo); + throw new TransliteratorParseException("Transliterator Parse Error: More than one compound filter " + extraInfo); case ErrorCode.INVALID_RBT_SYNTAX: - throw new ApplicationException("Transliterator Parse Error: A '::id' rule was passed to the RuleBasedTransliterator parser " + extraInfo); + throw new TransliteratorParseException("Transliterator Parse Error: A '::id' rule was passed to the RuleBasedTransliterator parser " + extraInfo); case ErrorCode.MALFORMED_PRAGMA: - throw new ApplicationException("Transliterator Parse Error: A 'use' pragma is invlalid " + extraInfo); + throw new TransliteratorParseException("Transliterator Parse Error: A 'use' pragma is invlalid " + extraInfo); case ErrorCode.UNCLOSED_SEGMENT: - throw new ApplicationException("Transliterator Parse Error: A closing ')' is missing " + extraInfo); + throw new TransliteratorParseException("Transliterator Parse Error: A closing ')' is missing " + extraInfo); case ErrorCode.VARIABLE_RANGE_EXHAUSTED: - throw new ApplicationException("Transliterator Parse Error: Too many stand-ins generated for the given variable range " + extraInfo); + throw new TransliteratorParseException("Transliterator Parse Error: Too many stand-ins generated for the given variable range " + extraInfo); case ErrorCode.VARIABLE_RANGE_OVERLAP: - throw new ApplicationException("Transliterator Parse Error: The variable range overlaps characters used in rules " + extraInfo); + throw new TransliteratorParseException("Transliterator Parse Error: The variable range overlaps characters used in rules " + extraInfo); case ErrorCode.ILLEGAL_CHARACTER: - throw new ApplicationException("Transliterator Parse Error: A special character is outside its allowed context " + extraInfo); + throw new TransliteratorParseException("Transliterator Parse Error: A special character is outside its allowed context " + extraInfo); case ErrorCode.INTERNAL_TRANSLITERATOR_ERROR: - throw new ApplicationException("Transliterator Parse Error: Internal transliterator system error " + extraInfo); + throw new TransliteratorParseException("Transliterator Parse Error: Internal transliterator system error " + extraInfo); case ErrorCode.INVALID_ID: - throw new ApplicationException("Transliterator Parse Error: A '::id' rule specifies an unknown transliterator " + extraInfo); + throw new TransliteratorParseException("Transliterator Parse Error: A '::id' rule specifies an unknown transliterator " + extraInfo); case ErrorCode.INVALID_FUNCTION: - throw new ApplicationException("Transliterator Parse Error: A '&fn()' rule specifies an unknown transliterator " + extraInfo); + throw new TransliteratorParseException("Transliterator Parse Error: A '&fn()' rule specifies an unknown transliterator " + extraInfo); case ErrorCode.UNEXPECTED_TOKEN: throw new SyntaxErrorException("Format Parse Error: Unexpected token in format pattern " + extraInfo); case ErrorCode.MULTIPLE_DECIMAL_SEPARATORS: @@ -574,97 +572,97 @@ private static void ThrowIfError(ErrorCode e, string extraInfo, bool throwOnWarn case ErrorCode.DEFAULT_KEYWORD_MISSING: throw new SyntaxErrorException("Format Parse Error: Missing DEFAULT rule in plural rules. " + extraInfo); case ErrorCode.BRK_INTERNAL_ERROR: - throw new ApplicationException("Break Error: An internal error (bug) was detected. " + extraInfo); + throw new BreakException("Break Error: An internal error (bug) was detected. " + extraInfo); case ErrorCode.BRK_HEX_DIGITS_EXPECTED: - throw new ApplicationException("Break Error: Hex digits expected as part of a escaped char in a rule. " + extraInfo); + throw new BreakException("Break Error: Hex digits expected as part of a escaped char in a rule. " + extraInfo); case ErrorCode.BRK_SEMICOLON_EXPECTED: - throw new ApplicationException("Break Error: Missing ';' at the end of a RBBI rule. " + extraInfo); + throw new BreakException("Break Error: Missing ';' at the end of a RBBI rule. " + extraInfo); case ErrorCode.BRK_RULE_SYNTAX: - throw new ApplicationException("Break Error: Syntax error in RBBI rule. " + extraInfo); + throw new BreakException("Break Error: Syntax error in RBBI rule. " + extraInfo); case ErrorCode.BRK_UNCLOSED_SET: - throw new ApplicationException("Break Error: UnicodeSet witing an RBBI rule missing a closing ']'. " + extraInfo); + throw new BreakException("Break Error: UnicodeSet witing an RBBI rule missing a closing ']'. " + extraInfo); case ErrorCode.BRK_ASSIGN_ERROR: - throw new ApplicationException("Break Error: Syntax error in RBBI rule assignment statement. " + extraInfo); + throw new BreakException("Break Error: Syntax error in RBBI rule assignment statement. " + extraInfo); case ErrorCode.BRK_VARIABLE_REDFINITION: - throw new ApplicationException("Break Error: RBBI rule $Variable redefined. " + extraInfo); + throw new BreakException("Break Error: RBBI rule $Variable redefined. " + extraInfo); case ErrorCode.BRK_MISMATCHED_PAREN: - throw new ApplicationException("Break Error: Mis-matched parentheses in an RBBI rule. " + extraInfo); + throw new BreakException("Break Error: Mis-matched parentheses in an RBBI rule. " + extraInfo); case ErrorCode.BRK_NEW_LINE_IN_QUOTED_STRING: - throw new ApplicationException("Break Error: Missing closing quote in an RBBI rule. " + extraInfo); + throw new BreakException("Break Error: Missing closing quote in an RBBI rule. " + extraInfo); case ErrorCode.BRK_UNDEFINED_VARIABLE: - throw new ApplicationException("Break Error: Use of an undefined $Variable in an RBBI rule. " + extraInfo); + throw new BreakException("Break Error: Use of an undefined $Variable in an RBBI rule. " + extraInfo); case ErrorCode.BRK_INIT_ERROR: - throw new ApplicationException("Break Error: Initialization failure. Probable missing ICU Data. " + extraInfo); + throw new BreakException("Break Error: Initialization failure. Probable missing ICU Data. " + extraInfo); case ErrorCode.BRK_RULE_EMPTY_SET: - throw new ApplicationException("Break Error: Rule contains an empty Unicode Set. " + extraInfo); + throw new BreakException("Break Error: Rule contains an empty Unicode Set. " + extraInfo); case ErrorCode.BRK_UNRECOGNIZED_OPTION: - throw new ApplicationException("Break Error: !!option in RBBI rules not recognized. " + extraInfo); + throw new BreakException("Break Error: !!option in RBBI rules not recognized. " + extraInfo); case ErrorCode.BRK_MALFORMED_RULE_TAG: - throw new ApplicationException("Break Error: The {nnn} tag on a rule is mal formed " + extraInfo); + throw new BreakException("Break Error: The {nnn} tag on a rule is mal formed " + extraInfo); case ErrorCode.BRK_ERROR_LIMIT: - throw new ApplicationException("Break Error: This must always be the last value to indicate the limit for Break Iterator failures " + extraInfo); + throw new BreakException("Break Error: This must always be the last value to indicate the limit for Break Iterator failures " + extraInfo); case ErrorCode.REGEX_INTERNAL_ERROR: - throw new ApplicationException("RegEx Error: An internal error (bug) was detected. " + extraInfo); + throw new RegexException("RegEx Error: An internal error (bug) was detected. " + extraInfo); case ErrorCode.REGEX_RULE_SYNTAX: - throw new ApplicationException("RegEx Error: Syntax error in regexp pattern. " + extraInfo); + throw new RegexException("RegEx Error: Syntax error in regexp pattern. " + extraInfo); case ErrorCode.REGEX_INVALID_STATE: - throw new ApplicationException("RegEx Error: RegexMatcher in invalid state for requested operation " + extraInfo); + throw new RegexException("RegEx Error: RegexMatcher in invalid state for requested operation " + extraInfo); case ErrorCode.REGEX_BAD_ESCAPE_SEQUENCE: - throw new ApplicationException("RegEx Error: Unrecognized backslash escape sequence in pattern " + extraInfo); + throw new RegexException("RegEx Error: Unrecognized backslash escape sequence in pattern " + extraInfo); case ErrorCode.REGEX_PROPERTY_SYNTAX: - throw new ApplicationException("RegEx Error: Incorrect Unicode property " + extraInfo); + throw new RegexException("RegEx Error: Incorrect Unicode property " + extraInfo); case ErrorCode.REGEX_UNIMPLEMENTED: - throw new ApplicationException("RegEx Error: Use of regexp feature that is not yet implemented. " + extraInfo); + throw new RegexException("RegEx Error: Use of regexp feature that is not yet implemented. " + extraInfo); case ErrorCode.REGEX_MISMATCHED_PAREN: - throw new ApplicationException("RegEx Error: Incorrectly nested parentheses in regexp pattern. " + extraInfo); + throw new RegexException("RegEx Error: Incorrectly nested parentheses in regexp pattern. " + extraInfo); case ErrorCode.REGEX_NUMBER_TOO_BIG: - throw new ApplicationException("RegEx Error: Decimal number is too large. " + extraInfo); + throw new RegexException("RegEx Error: Decimal number is too large. " + extraInfo); case ErrorCode.REGEX_BAD_INTERVAL: - throw new ApplicationException("RegEx Error: Error in {min,max} interval " + extraInfo); + throw new RegexException("RegEx Error: Error in {min,max} interval " + extraInfo); case ErrorCode.REGEX_MAX_LT_MIN: - throw new ApplicationException("RegEx Error: In {min,max}, max is less than min. " + extraInfo); + throw new RegexException("RegEx Error: In {min,max}, max is less than min. " + extraInfo); case ErrorCode.REGEX_INVALID_BACK_REF: - throw new ApplicationException("RegEx Error: Back-reference to a non-existent capture group. " + extraInfo); + throw new RegexException("RegEx Error: Back-reference to a non-existent capture group. " + extraInfo); case ErrorCode.REGEX_INVALID_FLAG: - throw new ApplicationException("RegEx Error: Invalid value for match mode flags. " + extraInfo); + throw new RegexException("RegEx Error: Invalid value for match mode flags. " + extraInfo); case ErrorCode.REGEX_LOOK_BEHIND_LIMIT: - throw new ApplicationException("RegEx Error: Look-Behind pattern matches must have a bounded maximum length. " + extraInfo); + throw new RegexException("RegEx Error: Look-Behind pattern matches must have a bounded maximum length. " + extraInfo); case ErrorCode.REGEX_SET_CONTAINS_STRING: - throw new ApplicationException("RegEx Error: Regexps cannot have UnicodeSets containing strings. " + extraInfo); + throw new RegexException("RegEx Error: Regexps cannot have UnicodeSets containing strings. " + extraInfo); case ErrorCode.REGEX_OCTAL_TOO_BIG: - throw new ApplicationException("Regex Error: Octal character constants must be <= 0377. " + extraInfo); + throw new RegexException("Regex Error: Octal character constants must be <= 0377. " + extraInfo); case ErrorCode.REGEX_MISSING_CLOSE_BRACKET: - throw new ApplicationException("Regex Error: Missing closing bracket on a bracket expression. " + extraInfo); + throw new RegexException("Regex Error: Missing closing bracket on a bracket expression. " + extraInfo); case ErrorCode.REGEX_INVALID_RANGE: - throw new ApplicationException("Regex Error: In a character range [x-y], x is greater than y. " + extraInfo); + throw new RegexException("Regex Error: In a character range [x-y], x is greater than y. " + extraInfo); case ErrorCode.REGEX_STACK_OVERFLOW: - throw new ApplicationException("Regex Error: Regular expression backtrack stack overflow. " + extraInfo); + throw new RegexException("Regex Error: Regular expression backtrack stack overflow. " + extraInfo); case ErrorCode.REGEX_TIME_OUT: - throw new ApplicationException("Regex Error: Maximum allowed match time exceeded. " + extraInfo); + throw new RegexException("Regex Error: Maximum allowed match time exceeded. " + extraInfo); case ErrorCode.REGEX_STOPPED_BY_CALLER: - throw new ApplicationException("Regex Error: Matching operation aborted by user callback fn. " + extraInfo); + throw new RegexException("Regex Error: Matching operation aborted by user callback fn. " + extraInfo); case ErrorCode.REGEX_ERROR_LIMIT: - throw new ApplicationException("RegEx Error: " + extraInfo); + throw new RegexException("RegEx Error: " + extraInfo); case ErrorCode.IDNA_PROHIBITED_ERROR: - throw new ApplicationException("IDNA Error: Prohibited " + extraInfo); + throw new IDNAException("IDNA Error: Prohibited " + extraInfo); case ErrorCode.IDNA_UNASSIGNED_ERROR: - throw new ApplicationException("IDNA Error: Unassigned " + extraInfo); + throw new IDNAException("IDNA Error: Unassigned " + extraInfo); case ErrorCode.IDNA_CHECK_BIDI_ERROR: - throw new ApplicationException("IDNA Error: Check Bidi " + extraInfo); + throw new IDNAException("IDNA Error: Check Bidi " + extraInfo); case ErrorCode.IDNA_STD3_ASCII_RULES_ERROR: - throw new ApplicationException("IDNA Error: Std3 Ascii Rules Error " + extraInfo); + throw new IDNAException("IDNA Error: Std3 Ascii Rules Error " + extraInfo); case ErrorCode.IDNA_ACE_PREFIX_ERROR: - throw new ApplicationException("IDNA Error: Ace Prefix Error " + extraInfo); + throw new IDNAException("IDNA Error: Ace Prefix Error " + extraInfo); case ErrorCode.IDNA_VERIFICATION_ERROR: - throw new ApplicationException("IDNA Error: Verification Error " + extraInfo); + throw new IDNAException("IDNA Error: Verification Error " + extraInfo); case ErrorCode.IDNA_LABEL_TOO_LONG_ERROR: - throw new ApplicationException("IDNA Error: Label too long " + extraInfo); + throw new IDNAException("IDNA Error: Label too long " + extraInfo); case ErrorCode.IDNA_ZERO_LENGTH_LABEL_ERROR: - throw new ApplicationException("IDNA Error: Zero length label " + extraInfo); + throw new IDNAException("IDNA Error: Zero length label " + extraInfo); case ErrorCode.IDNA_DOMAIN_NAME_TOO_LONG_ERROR: - throw new ApplicationException("IDNA Error: Domain name too long " + extraInfo); + throw new IDNAException("IDNA Error: Domain name too long " + extraInfo); default: - throw new InvalidEnumArgumentException("Missing implementation for ErrorCode " + e); + throw new NotSupportedException("Missing implementation for ErrorCode " + e); } } } diff --git a/source/icu.net/Exceptions/BreakException.cs b/source/icu.net/Exceptions/BreakException.cs new file mode 100644 index 00000000..6f7dbd7a --- /dev/null +++ b/source/icu.net/Exceptions/BreakException.cs @@ -0,0 +1,17 @@ +using System; + +namespace Icu +{ + /// + /// Exceptions related to BreakIterator functionality. + /// + public class BreakException : Exception + { + /// + /// Creates exception with the provided message. + /// + /// The message that describes the error. + public BreakException(string message) : base(message) + { } + } +} diff --git a/source/icu.net/Exceptions/IDNAException.cs b/source/icu.net/Exceptions/IDNAException.cs new file mode 100644 index 00000000..563b10ed --- /dev/null +++ b/source/icu.net/Exceptions/IDNAException.cs @@ -0,0 +1,17 @@ +using System; + +namespace Icu +{ + /// + /// Exception thrown when an IDNA ErrorCode is thrown. + /// + public class IDNAException : Exception + { + /// + /// Create an IDNA Exception with the following message. + /// + /// Message to pass to exception + public IDNAException(string message) : base(message) + { } + } +} diff --git a/source/icu.net/Exceptions/MissingResourceException.cs b/source/icu.net/Exceptions/MissingResourceException.cs new file mode 100644 index 00000000..487eff78 --- /dev/null +++ b/source/icu.net/Exceptions/MissingResourceException.cs @@ -0,0 +1,17 @@ +using System; + +namespace Icu +{ + /// + /// Exception when icu4c cannot find a resource. + /// + public class MissingResourceException : Exception + { + /// + /// Creates exception with the provided message. + /// + /// The message that describes the error. + public MissingResourceException(string message) : base(message) + { } + } +} diff --git a/source/icu.net/Exceptions/RegexException.cs b/source/icu.net/Exceptions/RegexException.cs new file mode 100644 index 00000000..cad457e5 --- /dev/null +++ b/source/icu.net/Exceptions/RegexException.cs @@ -0,0 +1,17 @@ +using System; + +namespace Icu +{ + /// + /// Exceptions indicating Regexp failures + /// + public class RegexException : Exception + { + /// + /// Creates exception with the provided message. + /// + /// The message that describes the error. + public RegexException(string message) : base(message) + { } + } +} diff --git a/source/icu.net/Exceptions/SyntaxErrorException.cs b/source/icu.net/Exceptions/SyntaxErrorException.cs new file mode 100644 index 00000000..3811eb7b --- /dev/null +++ b/source/icu.net/Exceptions/SyntaxErrorException.cs @@ -0,0 +1,17 @@ +using System; + +namespace Icu +{ + /// + /// Exception for syntax errors in a format pattern (ie. Number, exponent patterns.) + /// + public class SyntaxErrorException : Exception + { + /// + /// Creates exception with the provided message. + /// + /// The message that describes the error. + public SyntaxErrorException(string message) : base(message) + { } + } +} diff --git a/source/icu.net/Exceptions/TransliteratorParseException.cs b/source/icu.net/Exceptions/TransliteratorParseException.cs new file mode 100644 index 00000000..8fa17120 --- /dev/null +++ b/source/icu.net/Exceptions/TransliteratorParseException.cs @@ -0,0 +1,17 @@ +using System; + +namespace Icu +{ + /// + /// Exceptions for Transliterator errors. + /// + public class TransliteratorParseException : Exception + { + /// + /// Creates exception with the provided message. + /// + /// The message that describes the error. + public TransliteratorParseException(string message) : base(message) + { } + } +} diff --git a/source/icu.net/Exceptions/WarningException.cs b/source/icu.net/Exceptions/WarningException.cs new file mode 100644 index 00000000..66d086ec --- /dev/null +++ b/source/icu.net/Exceptions/WarningException.cs @@ -0,0 +1,17 @@ +using System; + +namespace Icu +{ + /// + /// Exceptions indicating that there was a warning returned from icu. + /// + public class WarningException : Exception + { + /// + /// Creates exception with the provided message. + /// + /// The message that describes the error. + public WarningException(string message) : base(message) + { } + } +} diff --git a/source/icu.net/icu.net.csproj b/source/icu.net/icu.net.csproj index c3249af6..709cef71 100644 --- a/source/icu.net/icu.net.csproj +++ b/source/icu.net/icu.net.csproj @@ -142,7 +142,14 @@ + + + + + + + From 452c98e016ffb7939a2c8860c41eb15d0274adac Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Fri, 13 Jan 2017 09:16:50 -0800 Subject: [PATCH 04/60] Fixing tests to assert ArgumentException rather than ApplicationException --- source/icu.net.tests/Collation/RuleBasedCollatorTests.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/icu.net.tests/Collation/RuleBasedCollatorTests.cs b/source/icu.net.tests/Collation/RuleBasedCollatorTests.cs index 5e1b523c..9d327ef9 100644 --- a/source/icu.net.tests/Collation/RuleBasedCollatorTests.cs +++ b/source/icu.net.tests/Collation/RuleBasedCollatorTests.cs @@ -68,7 +68,7 @@ public void Construct_SyntaxErrorInRules_Throws() { // Previously "<<<<" was assumed to be syntax. Now that is Quaternary so we use a longer string string badRules = "& C < č <<<<<<<< Č < ć <<< Ć"; - Assert.That(() => new RuleBasedCollator(badRules), Throws.TypeOf()); + Assert.That(() => new RuleBasedCollator(badRules), Throws.TypeOf()); } [Test] @@ -831,7 +831,7 @@ public void GetAvailableLocales_ReturnsList() [Category("KnownMonoIssue")] public void ConvertToIcuRules_SurrogateCharacterLowBound_Throws() { - Assert.Throws( + Assert.Throws( // Invalid unicode character escape sequence: () => new RuleBasedCollator(IcuStart + "\ud800") ); @@ -845,7 +845,7 @@ public void ConvertToIcuRules_SurrogateCharacterLowBound_Throws() [Category("KnownMonoIssue")] public void ConvertToIcuRules_SurrogateCharacterHighBound_Throws() { - Assert.Throws( + Assert.Throws( // Invalid unicode character escape sequence: () => new RuleBasedCollator(IcuStart + "\udfff") ); @@ -859,7 +859,7 @@ public void ConvertToIcuRules_SurrogateCharacterHighBound_Throws() [Category("KnownMonoIssue")] public void ConvertToIcuRules_SurrogateCharactersOutOfOrder_Throws() { - Assert.Throws( + Assert.Throws( // Invalid unicode character escape sequence: () => new RuleBasedCollator(IcuStart + "a << \udc00\ud800") ); From 8e2716360e74e9d36f1d437f707b2c4431fa0135 Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Fri, 13 Jan 2017 09:35:43 -0800 Subject: [PATCH 05/60] Migrating Character, Collator, Locale and UnicodeSet --- source/icu.net/Character.cs | 4 ++-- source/icu.net/Collation/Collator.cs | 7 +++++-- source/icu.net/Collation/RuleBasedCollator.cs | 11 +++++++++-- source/icu.net/Locale.cs | 5 ++++- source/icu.net/UnicodeSet.cs | 2 +- source/icu.net/icu.net.csproj | 2 +- 6 files changed, 22 insertions(+), 9 deletions(-) diff --git a/source/icu.net/Character.cs b/source/icu.net/Character.cs index 98c88890..81108c9b 100644 --- a/source/icu.net/Character.cs +++ b/source/icu.net/Character.cs @@ -724,8 +724,8 @@ public static string GetPrettyICUCharName(string chr) string name; if (CharName(chr[0], UCharNameChoice.UNICODE_CHAR_NAME, out name) > 0) { - name = name.ToLower(); - return CultureInfo.CurrentUICulture.TextInfo.ToTitleCase(name); + var lowercase = CultureInfo.CurrentUICulture.TextInfo.ToLower(name); + return UnicodeString.ToTitle(lowercase, new Locale()); } } return null; diff --git a/source/icu.net/Collation/Collator.cs b/source/icu.net/Collation/Collator.cs index 471cb674..7aef11c4 100644 --- a/source/icu.net/Collation/Collator.cs +++ b/source/icu.net/Collation/Collator.cs @@ -14,7 +14,10 @@ namespace Icu.Collation /// You use this class to build searching and sorting routines for natural /// language text. /// - public abstract class Collator : IComparer, ICloneable, IDisposable + public abstract class Collator : IComparer, IDisposable +#if FEATURE_ICLONEABLE + , ICloneable +#endif { /// /// Gets or sets the minimum strength that will be used in comparison @@ -151,7 +154,7 @@ public static Collator Create(CultureInfo cultureInfo, Fallback fallback) { throw new ArgumentNullException(); } - return Create(cultureInfo.IetfLanguageTag, fallback); + return Create(cultureInfo.Name, fallback); } /// diff --git a/source/icu.net/Collation/RuleBasedCollator.cs b/source/icu.net/Collation/RuleBasedCollator.cs index 153cf529..8e8b2bb0 100644 --- a/source/icu.net/Collation/RuleBasedCollator.cs +++ b/source/icu.net/Collation/RuleBasedCollator.cs @@ -2,9 +2,12 @@ // This software is licensed under the MIT license (http://opensource.org/licenses/MIT) using System; using System.Collections.Generic; -using System.Runtime.ConstrainedExecution; using System.Runtime.InteropServices; + +#if !NETSTANDARD using System.Globalization; +using System.Runtime.ConstrainedExecution; +#endif namespace Icu.Collation { @@ -26,7 +29,9 @@ public SafeRuleBasedCollatorHandle() : /// true if the handle is released successfully; otherwise, in the event of a catastrophic failure, false. /// In this case, it generates a ReleaseHandleFailed Managed Debugging Assistant. /// +#if !NETSTANDARD [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] +#endif protected override bool ReleaseHandle() { if (handle != IntPtr.Zero) @@ -301,7 +306,7 @@ public static IList GetAvailableCollationLocales() } finally { - en.Close(); + en.Dispose(); } return locales; } @@ -318,7 +323,9 @@ public SafeEnumeratorHandle() /// ///true if the handle is released successfully; otherwise, in the event of a catastrophic failure, false. In this case, it generates a ReleaseHandleFailed Managed Debugging Assistant. /// +#if !NETSTANDARD [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] +#endif protected override bool ReleaseHandle() { NativeMethods.uenum_close(handle); diff --git a/source/icu.net/Locale.cs b/source/icu.net/Locale.cs index 824141ce..66937fcf 100644 --- a/source/icu.net/Locale.cs +++ b/source/icu.net/Locale.cs @@ -11,7 +11,10 @@ namespace Icu /// /// A Locale object represents a specific geographical, political, or cultural region. /// - public class Locale: ICloneable + public class Locale +#if FEATURE_ICLONEABLE + : ICloneable +#endif { /// /// Construct a default locale object, a Locale for the default locale ID diff --git a/source/icu.net/UnicodeSet.cs b/source/icu.net/UnicodeSet.cs index ebaf7e42..031480b6 100644 --- a/source/icu.net/UnicodeSet.cs +++ b/source/icu.net/UnicodeSet.cs @@ -89,7 +89,7 @@ public static IEnumerable ToCharacters(string pattern) // Add a character range to the set for (int j = startChar; j <= endChar; j++) { - output.Add(((char) j).ToString(CultureInfo.InvariantCulture)); + output.Add(string.Format(CultureInfo.InvariantCulture, "{0}", (char)j)); } } else diff --git a/source/icu.net/icu.net.csproj b/source/icu.net/icu.net.csproj index 709cef71..b057882e 100644 --- a/source/icu.net/icu.net.csproj +++ b/source/icu.net/icu.net.csproj @@ -118,7 +118,7 @@ net40 ..\..\lib\icu ..\..\output\$(Configuration) - $(DefineConstants);ICU_VER_$(icu_ver) + $(DefineConstants);ICU_VER_$(icu_ver);FEATURE_ICLONEABLE true From e319513e7265b81789d1c376f08b9901f510d104 Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Tue, 7 Mar 2017 23:13:27 -0800 Subject: [PATCH 06/60] Add icu.net.netstandard.csproj --- .../icu.net.netstandard.csproj | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 source/icu.net.netstandard/icu.net.netstandard.csproj diff --git a/source/icu.net.netstandard/icu.net.netstandard.csproj b/source/icu.net.netstandard/icu.net.netstandard.csproj new file mode 100644 index 00000000..cdfdd86f --- /dev/null +++ b/source/icu.net.netstandard/icu.net.netstandard.csproj @@ -0,0 +1,46 @@ + + + + netstandard1.6 + net40;net451;netstandard1.6 + + ..\icu.net + + icu.net + AllRules.ruleset + prompt + 4 + false + + + + + $(DefineConstants);FEATURE_ICLONEABLE + + + + + ..\..\output\$(MSBuildProjectName) + true + $(IcuSourceDirectory)\icu.net.snk + + + + + + + + + + + + + + %(RecursiveDir)%(Filename)%(Extension) + + + + + + + \ No newline at end of file From 7decdd792f7f2550849a2e2bcf2ea4a4c37fe89f Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Tue, 7 Mar 2017 23:36:08 -0800 Subject: [PATCH 07/60] Adding SortKey support on .NET Standard --- source/icu.net.netstandard/SortKey.cs | 138 ++++++++++++++++++ source/icu.net/Collation/Collator.cs | 44 +++--- source/icu.net/Collation/RuleBasedCollator.cs | 10 +- 3 files changed, 165 insertions(+), 27 deletions(-) create mode 100644 source/icu.net.netstandard/SortKey.cs diff --git a/source/icu.net.netstandard/SortKey.cs b/source/icu.net.netstandard/SortKey.cs new file mode 100644 index 00000000..2a9ff825 --- /dev/null +++ b/source/icu.net.netstandard/SortKey.cs @@ -0,0 +1,138 @@ +using System; +using System.Globalization; + +namespace Icu +{ + /// + /// Replacement for System.Globalization.SortKey, which does not exist in + /// .NET Standard 1.5. Will be brought back in .NET Standard 2.0. + /// See https://github.com/dotnet/corefx/issues/10065 for more information. + /// + public class SortKey + { + private readonly string localeName; + private readonly CompareOptions options; + private readonly byte[] m_KeyData; + private readonly string m_String; + + internal SortKey(string localeName, string str, CompareOptions options, byte[] keyData) + { + var copy = new byte[keyData.Length]; + keyData.CopyTo(copy, 0); + + this.m_KeyData = copy; + this.localeName = localeName; + this.options = options; + this.m_String = str; + } + + /// + /// Gets the byte array representing the current System.Globalization.SortKey object. + /// + public virtual byte[] KeyData + { + get + { + var copy = new byte[m_KeyData.Length]; + m_KeyData.CopyTo(copy, 0); + + return copy; + } + } + + /// + /// Gets the original string used to create the current System.Globalization.SortKey + /// object. + /// + public virtual string OriginalString { get { return m_String; } } + + /// + /// Compares two sort keys. + /// + /// The first sort key to compare. + /// The second sort key to compare. + /// A signed integer that indicates the relationship between sortkey1 and sortkey2. + /// Value + /// Condition Less than zero: sortkey1 is less than sortkey2. + /// Zero : sortkey1 is equal to sortkey2. + /// Greater than zero : sortkey1 is greater than sortkey2. + /// + public static int Compare(SortKey sortkey1, SortKey sortkey2) + { + if (sortkey1 == null || sortkey2 == null) + { + throw new ArgumentNullException("A value is required to compare both values"); + } + + var keyData1 = sortkey1.KeyData; + var keyData2 = sortkey2.KeyData; + + if (keyData1.Length == 0) + { + return keyData2.Length == 0 ? 0 : -1; + } + + if (keyData2.Length == 0) + { + return keyData1.Length == 0 ? 0 : 1; + } + + var length = Math.Min(keyData1.Length, keyData2.Length); + + for (int i = 0; i < length; i++) + { + var value = keyData1[i]; + var value2 = keyData2[i]; + + if (value > value2) + { + return 1; + } + + if (value < value2) + { + return -1; + } + } + + return 0; + } + + /// + /// Determines whether the specified object is equal to the current + /// System.Globalization.SortKey object. + /// + /// The object to compare with the current + /// System.Globalization.SortKey object. + /// true if the value parameter is equal to the current + /// System.Globalization.SortKey object; otherwise, false. + public override bool Equals(object value) + { + var obj = value as SortKey; + + if (obj == null) + return false; + + return Compare(this, obj) == 0; + } + + /// + /// Serves as a hash function for the current System.Globalization.SortKey object + /// that is suitable for hashing algorithms and data structures such as a hash table. + /// + /// A hash code for the current System.Globalization.SortKey object. + public override int GetHashCode() + { + return CompareInfo.GetCompareInfo(localeName).GetHashCode(m_String, options); + } + + /// + /// Returns a string that represents the current System.Globalization.SortKey object. + /// + /// A string that represents the current System.Globalization.SortKey object. + public override string ToString() + { + return string.Format("SortKey - {0}, {1}, {3}", localeName, options, OriginalString); + } + } +} diff --git a/source/icu.net/Collation/Collator.cs b/source/icu.net/Collation/Collator.cs index 7aef11c4..8841646c 100644 --- a/source/icu.net/Collation/Collator.cs +++ b/source/icu.net/Collation/Collator.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2013 SIL International +// Copyright (c) 2013 SIL International // This software is licensed under the MIT license (http://opensource.org/licenses/MIT) using System; using System.Collections.Generic; @@ -192,14 +192,21 @@ static public SortKey CreateSortKey(string originalString, byte[] keyData, int k throw new ArgumentOutOfRangeException("keyDataLength"); } - SortKey sortKey = CultureInfo.InvariantCulture.CompareInfo.GetSortKey(string.Empty); - SetInternalOriginalStringField(sortKey, originalString); + CompareOptions options = CompareOptions.None; + +#if NETSTANDARD1_6 + SortKey sortKey = new SortKey(CultureInfo.InvariantCulture.Name, originalString, options, keyData); +#else + SortKey sortKey = CultureInfo.InvariantCulture.CompareInfo.GetSortKey(string.Empty, options); + SetInternalOriginalStringField(sortKey, originalString); SetInternalKeyDataField(sortKey, keyData, keyDataLength); +#endif - return sortKey; + return sortKey; } - private static void SetInternalKeyDataField(SortKey sortKey, byte[] keyData, int keyDataLength) +#if !NETSTANDARD1_6 + private static void SetInternalKeyDataField(SortKey sortKey, byte[] keyData, int keyDataLength) { byte[] keyDataCopy = new byte[keyDataLength]; Array.Copy(keyData, keyDataCopy, keyDataLength); @@ -236,19 +243,9 @@ private static void SetInternalFieldForPublicProperty( { Type type = instance.GetType(); - FieldInfo fieldInfo; - if (IsRunningOnMono()) - { - fieldInfo = type.GetField(monoInternalFieldName, - BindingFlags.Instance - | BindingFlags.NonPublic); - } - else //Is Running On .Net - { - fieldInfo = type.GetField(netInternalFieldName, - BindingFlags.Instance - | BindingFlags.NonPublic); - } + string fieldName = IsRunningOnMono() ? monoInternalFieldName : netInternalFieldName; + + FieldInfo fieldInfo = type.GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic); Debug.Assert(fieldInfo != null, "Unsupported runtime", @@ -261,16 +258,17 @@ private static void SetInternalFieldForPublicProperty( fieldInfo.SetValue(instance, value); } - + private static bool IsRunningOnMono() { return Type.GetType("Mono.Runtime") != null; } +#endif - /// - /// Simple class to allow passing collation error info back to the caller of CheckRules. - /// - public class CollationRuleErrorInfo + /// + /// Simple class to allow passing collation error info back to the caller of CheckRules. + /// + public class CollationRuleErrorInfo { /// Line number (1-based) containing the error public int Line; diff --git a/source/icu.net/Collation/RuleBasedCollator.cs b/source/icu.net/Collation/RuleBasedCollator.cs index 8e8b2bb0..a70f8479 100644 --- a/source/icu.net/Collation/RuleBasedCollator.cs +++ b/source/icu.net/Collation/RuleBasedCollator.cs @@ -1,10 +1,12 @@ -// Copyright (c) 2013 SIL International +// Copyright (c) 2013 SIL International // This software is licensed under the MIT license (http://opensource.org/licenses/MIT) using System; using System.Collections.Generic; using System.Runtime.InteropServices; -#if !NETSTANDARD +#if NETSTANDARD1_6 +using Icu; +#else using System.Globalization; using System.Runtime.ConstrainedExecution; #endif @@ -29,7 +31,7 @@ public SafeRuleBasedCollatorHandle() : /// true if the handle is released successfully; otherwise, in the event of a catastrophic failure, false. /// In this case, it generates a ReleaseHandleFailed Managed Debugging Assistant. /// -#if !NETSTANDARD +#if !NETSTANDARD1_6 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] #endif protected override bool ReleaseHandle() @@ -323,7 +325,7 @@ public SafeEnumeratorHandle() /// ///true if the handle is released successfully; otherwise, in the event of a catastrophic failure, false. In this case, it generates a ReleaseHandleFailed Managed Debugging Assistant. /// -#if !NETSTANDARD +#if !NETSTANDARD1_6 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] #endif protected override bool ReleaseHandle() From 82c91dd9f6b0578633683c78b1a77aec0a923c14 Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Wed, 8 Mar 2017 01:02:54 -0800 Subject: [PATCH 08/60] Add icu.net.netstandard solution --- source/icu.net.netstandard.sln | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 source/icu.net.netstandard.sln diff --git a/source/icu.net.netstandard.sln b/source/icu.net.netstandard.sln new file mode 100644 index 00000000..cb867d89 --- /dev/null +++ b/source/icu.net.netstandard.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26228.4 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "icu.net.netstandard", "icu.net.netstandard\icu.net.netstandard.csproj", "{AA4C50FD-F411-484F-A17B-0A69B8784A10}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {AA4C50FD-F411-484F-A17B-0A69B8784A10}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AA4C50FD-F411-484F-A17B-0A69B8784A10}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AA4C50FD-F411-484F-A17B-0A69B8784A10}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AA4C50FD-F411-484F-A17B-0A69B8784A10}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal From 10d539fceff51a55d89b76f16699be29a5779e4a Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Fri, 13 Jan 2017 11:24:20 -0800 Subject: [PATCH 09/60] Add OS architecture and platform detection for .NET Standard --- source/icu.net/NativeMethods.cs | 2 +- source/icu.net/Platform.cs | 70 +++++++++++++++++++++++++++++++++ source/icu.net/icu.net.csproj | 1 + 3 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 source/icu.net/Platform.cs diff --git a/source/icu.net/NativeMethods.cs b/source/icu.net/NativeMethods.cs index 696b1338..bdedd6a5 100644 --- a/source/icu.net/NativeMethods.cs +++ b/source/icu.net/NativeMethods.cs @@ -1810,7 +1810,7 @@ public static IntPtr uregex_open( } /// - /// Attempts to match the input string against the pattern. + /// Attempts to match the input string against the pattern. /// public static bool uregex_matches( IntPtr regexp, diff --git a/source/icu.net/Platform.cs b/source/icu.net/Platform.cs new file mode 100644 index 00000000..160765d1 --- /dev/null +++ b/source/icu.net/Platform.cs @@ -0,0 +1,70 @@ +using System; +using System.Runtime.InteropServices; + +namespace Icu +{ + /// + /// Operating systems. + /// Taken from: + /// https://github.com/libgit2/libgit2sharp/blob/master/LibGit2Sharp/Core/Platform.cs + /// + internal enum OperatingSystemType + { + Windows, + Unix, + MacOSX + } + + /// + /// Class that fetches the current process bitness and architecture. + /// Adapted from: + /// https://github.com/libgit2/libgit2sharp/blob/master/LibGit2Sharp/Core/Platform.cs + /// + internal static class Platform + { + public static string ProcessArchitecture + { + get { + const string x86 = "x86"; + const string x64 = "x64"; + +#if NETSTANDARD1_6 + // Workaround described here since the API does not exist: + // https://github.com/dotnet/corefx/issues/999#issuecomment-75907756 + return IntPtr.Size == 4 ? x86 : x64; +#else + return Environment.Is64BitProcess ? x64 : x86; +#endif + } + } + + public static OperatingSystemType OperatingSystem + { + get + { +#if NET40 + // See http://www.mono-project.com/docs/faq/technical/#how-to-detect-the-execution-platform + switch ((int)Environment.OSVersion.Platform) + { + case 4: + case 128: + return OperatingSystemType.Unix; + case 6: + return OperatingSystemType.MacOSX; + default: + return OperatingSystemType.Windows; + } +#else + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + return OperatingSystemType.Windows; + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + return OperatingSystemType.Unix; + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + return OperatingSystemType.MacOSX; + else + throw new NotSupportedException("Cannot get OperatingSystemType from: " + RuntimeInformation.OSDescription); +#endif + } + } + } +} diff --git a/source/icu.net/icu.net.csproj b/source/icu.net/icu.net.csproj index b057882e..83ed9462 100644 --- a/source/icu.net/icu.net.csproj +++ b/source/icu.net/icu.net.csproj @@ -144,6 +144,7 @@ + From fc143a14ad36ffbfc503e8cf61ac12336ca9391e Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Tue, 7 Mar 2017 23:41:26 -0800 Subject: [PATCH 10/60] Fix DirectoryOfThisAssembly for .NET Standard --- source/icu.net/NativeMethods.cs | 12 ++++++++++-- source/icu.net/icu.net.csproj | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/source/icu.net/NativeMethods.cs b/source/icu.net/NativeMethods.cs index bdedd6a5..75b2ec8b 100644 --- a/source/icu.net/NativeMethods.cs +++ b/source/icu.net/NativeMethods.cs @@ -99,11 +99,19 @@ private static IntPtr IcuI18NLibHandle } } - private static string DirectoryOfThisAssembly + internal static string DirectoryOfThisAssembly { get { - var uri = new Uri(typeof(NativeMethods).Assembly.CodeBase); + //NOTE: .GetTypeInfo() is not supported until .NET 4.5 onwards. +#if NET40 + Assembly currentAssembly = typeof(NativeMethods).Assembly; +#else + Assembly currentAssembly = typeof(NativeMethods).GetTypeInfo().Assembly; +#endif + var managedPath = currentAssembly.CodeBase ?? currentAssembly.Location; + var uri = new Uri(managedPath); + return Path.GetDirectoryName(uri.LocalPath); } } diff --git a/source/icu.net/icu.net.csproj b/source/icu.net/icu.net.csproj index 83ed9462..d2b75bdf 100644 --- a/source/icu.net/icu.net.csproj +++ b/source/icu.net/icu.net.csproj @@ -118,7 +118,7 @@ net40 ..\..\lib\icu ..\..\output\$(Configuration) - $(DefineConstants);ICU_VER_$(icu_ver);FEATURE_ICLONEABLE + $(DefineConstants);FEATURE_ICLONEABLE;NET40 true From e3bb425c6532da6a81865f4a974d43135a6c87df Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Wed, 11 Jan 2017 12:57:00 -0800 Subject: [PATCH 11/60] Modify obsolete GetDelegateForFunctionPointer(typeof(T)) with GetDelegateForFunctionPointer --- source/icu.net/NativeMethods.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/icu.net/NativeMethods.cs b/source/icu.net/NativeMethods.cs index 75b2ec8b..eeb0040e 100644 --- a/source/icu.net/NativeMethods.cs +++ b/source/icu.net/NativeMethods.cs @@ -273,8 +273,13 @@ private static T GetMethod(IntPtr handle, string methodName, bool missingInMi dlsym(handle, versionedMethodName); if (methodPointer != IntPtr.Zero) { + // NOTE: Starting in .NET 4.5.1, Marshal.GetDelegateForFunctionPointer(IntPtr, Type) is obsolete. +#if NET40 return Marshal.GetDelegateForFunctionPointer( methodPointer, typeof(T)) as T; +#else + return Marshal.GetDelegateForFunctionPointer(methodPointer); +#endif } if (missingInMinimal) { From 6d03dcab12335826f220a39614077d17584781e1 Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Fri, 13 Jan 2017 14:44:00 -0800 Subject: [PATCH 12/60] Change TestCase.Result to TestCase.ExpectedResult --- .../Collation/RuleBasedCollatorTests.cs | 120 +++++++++--------- source/icu.net.tests/NormalizerTests.cs | 18 +-- 2 files changed, 69 insertions(+), 69 deletions(-) diff --git a/source/icu.net.tests/Collation/RuleBasedCollatorTests.cs b/source/icu.net.tests/Collation/RuleBasedCollatorTests.cs index 9d327ef9..e9ecbbf2 100644 --- a/source/icu.net.tests/Collation/RuleBasedCollatorTests.cs +++ b/source/icu.net.tests/Collation/RuleBasedCollatorTests.cs @@ -81,11 +81,11 @@ public void Clone() } } - [TestCase("", null, "a", Result = -1)] - [TestCase("", "a", null, Result = 1)] - [TestCase("", null, null, Result = 0)] - [TestCase("", "ČUKIĆ SLOBODAN", "CUKIĆ SVETOZAR", Result = -1)] - [TestCase(SerbianRules, "ČUKIĆ SLOBODAN", "CUKIĆ SVETOZAR", Result = 1)] + [TestCase("", null, "a", ExpectedResult = -1)] + [TestCase("", "a", null, ExpectedResult = 1)] + [TestCase("", null, null, ExpectedResult = 0)] + [TestCase("", "ČUKIĆ SLOBODAN", "CUKIĆ SVETOZAR", ExpectedResult = -1)] + [TestCase(SerbianRules, "ČUKIĆ SLOBODAN", "CUKIĆ SVETOZAR", ExpectedResult = 1)] public int Compare(string rules, string string1, string string2) { using (var ucaCollator = new RuleBasedCollator(rules)) @@ -136,22 +136,22 @@ public void SetCollatorStrengthToIdentical() } } - [TestCase(CollationStrength.Tertiary, AlternateHandling.Shifted, "di Silva", "diSilva", Result = + [TestCase(CollationStrength.Tertiary, AlternateHandling.Shifted, "di Silva", "diSilva", ExpectedResult = 0)] - [TestCase(CollationStrength.Tertiary, AlternateHandling.Shifted, "diSilva", "Di Silva", Result = + [TestCase(CollationStrength.Tertiary, AlternateHandling.Shifted, "diSilva", "Di Silva", ExpectedResult = -1)] - [TestCase(CollationStrength.Tertiary, AlternateHandling.Shifted, "U.S.A.", "USA", Result = 0)] + [TestCase(CollationStrength.Tertiary, AlternateHandling.Shifted, "U.S.A.", "USA", ExpectedResult = 0)] [TestCase(CollationStrength.Quaternary, AlternateHandling.Shifted, "di Silva", "diSilva", - Result = -1)] + ExpectedResult = -1)] [TestCase(CollationStrength.Quaternary, AlternateHandling.Shifted, "diSilva", "Di Silva", - Result = -1)] - [TestCase(CollationStrength.Quaternary, AlternateHandling.Shifted, "U.S.A.", "USA", Result = + ExpectedResult = -1)] + [TestCase(CollationStrength.Quaternary, AlternateHandling.Shifted, "U.S.A.", "USA", ExpectedResult = -1)] [TestCase(CollationStrength.Tertiary, AlternateHandling.NonIgnorable, "di Silva", "Di Silva", - Result = -1)] + ExpectedResult = -1)] [TestCase(CollationStrength.Tertiary, AlternateHandling.NonIgnorable, "Di Silva", "diSilva", - Result = -1)] - [TestCase(CollationStrength.Tertiary, AlternateHandling.NonIgnorable, "U.S.A.", "USA", Result = + ExpectedResult = -1)] + [TestCase(CollationStrength.Tertiary, AlternateHandling.NonIgnorable, "U.S.A.", "USA", ExpectedResult = -1)] public int AlternateHandlingSetting(CollationStrength collationStrength, AlternateHandling alternateHandling, string string1, string string2) @@ -179,15 +179,15 @@ public int AlternateHandlingSetting(CollationStrength collationStrength, } } - [TestCase(CaseFirst.LowerFirst, "china", "China", Result = -1)] - [TestCase(CaseFirst.LowerFirst, "China", "denmark", Result = -1)] - [TestCase(CaseFirst.LowerFirst, "denmark", "Denmark", Result = -1)] - [TestCase(CaseFirst.Off, "china", "China", Result = -1)] - [TestCase(CaseFirst.Off, "China", "denmark", Result = -1)] - [TestCase(CaseFirst.Off, "denmark", "Denmark", Result = -1)] - [TestCase(CaseFirst.UpperFirst, "China", "china", Result = -1)] - [TestCase(CaseFirst.UpperFirst, "china", "Denmark", Result = -1)] - [TestCase(CaseFirst.UpperFirst, "Denmark", "denmark", Result = -1)] + [TestCase(CaseFirst.LowerFirst, "china", "China", ExpectedResult = -1)] + [TestCase(CaseFirst.LowerFirst, "China", "denmark", ExpectedResult = -1)] + [TestCase(CaseFirst.LowerFirst, "denmark", "Denmark", ExpectedResult = -1)] + [TestCase(CaseFirst.Off, "china", "China", ExpectedResult = -1)] + [TestCase(CaseFirst.Off, "China", "denmark", ExpectedResult = -1)] + [TestCase(CaseFirst.Off, "denmark", "Denmark", ExpectedResult = -1)] + [TestCase(CaseFirst.UpperFirst, "China", "china", ExpectedResult = -1)] + [TestCase(CaseFirst.UpperFirst, "china", "Denmark", ExpectedResult = -1)] + [TestCase(CaseFirst.UpperFirst, "Denmark", "denmark", ExpectedResult = -1)] public int CaseFirstSetting(CaseFirst caseFirst, string string1, string string2) { /* The Case_First attribute is used to control whether uppercase letters @@ -212,10 +212,10 @@ public int CaseFirstSetting(CaseFirst caseFirst, string string1, string string2) } } - [TestCase(CaseLevel.Off, "role", "Role", Result = 0)] - [TestCase(CaseLevel.Off, "role", "rôle", Result = 0)] - [TestCase(CaseLevel.On, "role", "rôle", Result = 0)] - [TestCase(CaseLevel.On, "rôle", "Role", Result = -1)] + [TestCase(CaseLevel.Off, "role", "Role", ExpectedResult = 0)] + [TestCase(CaseLevel.Off, "role", "rôle", ExpectedResult = 0)] + [TestCase(CaseLevel.On, "role", "rôle", ExpectedResult = 0)] + [TestCase(CaseLevel.On, "rôle", "Role", ExpectedResult = -1)] public int CaseLevelSetting(CaseLevel caseLevel, string string1, string string2) { /*The Case_Level attribute is used when ignoring accents but not case. In @@ -233,12 +233,12 @@ public int CaseLevelSetting(CaseLevel caseLevel, string string1, string string2) } } - [TestCase(FrenchCollation.Off, "cote", "coté", Result = -1)] - [TestCase(FrenchCollation.Off, "coté", "côte", Result = -1)] - [TestCase(FrenchCollation.Off, "côte", "côté", Result = -1)] - [TestCase(FrenchCollation.On, "cote", "côte", Result = -1)] - [TestCase(FrenchCollation.On, "côte", "coté", Result = -1)] - [TestCase(FrenchCollation.On, "coté", "côté", Result = -1)] + [TestCase(FrenchCollation.Off, "cote", "coté", ExpectedResult = -1)] + [TestCase(FrenchCollation.Off, "coté", "côte", ExpectedResult = -1)] + [TestCase(FrenchCollation.Off, "côte", "côté", ExpectedResult = -1)] + [TestCase(FrenchCollation.On, "cote", "côte", ExpectedResult = -1)] + [TestCase(FrenchCollation.On, "côte", "coté", ExpectedResult = -1)] + [TestCase(FrenchCollation.On, "coté", "côté", ExpectedResult = -1)] public int FrenchCollationSetting(FrenchCollation frenchCollation, string string1, string string2) { @@ -271,12 +271,12 @@ private static Collator CreateJaCollator() } } - [TestCase(CollationStrength.Tertiary, "きゅう", "キュウ", Result = 0)] - [TestCase(CollationStrength.Tertiary, "キュウ", "きゆう", Result = -1)] - [TestCase(CollationStrength.Tertiary, "きゆう", "キユウ", Result = 0)] - [TestCase(CollationStrength.Quaternary, "きゅう", "キュウ", Result = -1)] - [TestCase(CollationStrength.Quaternary, "キュウ", "きゆう", Result = -1)] - [TestCase(CollationStrength.Quaternary, "きゆう", "キユウ", Result = -1)] + [TestCase(CollationStrength.Tertiary, "きゅう", "キュウ", ExpectedResult = 0)] + [TestCase(CollationStrength.Tertiary, "キュウ", "きゆう", ExpectedResult = -1)] + [TestCase(CollationStrength.Tertiary, "きゆう", "キユウ", ExpectedResult = 0)] + [TestCase(CollationStrength.Quaternary, "きゅう", "キュウ", ExpectedResult = -1)] + [TestCase(CollationStrength.Quaternary, "キュウ", "きゆう", ExpectedResult = -1)] + [TestCase(CollationStrength.Quaternary, "きゆう", "キユウ", ExpectedResult = -1)] public int HiraganaQuarternarySetting(CollationStrength collationStrength, string string1, string string2) { @@ -298,12 +298,12 @@ public int HiraganaQuarternarySetting(CollationStrength collationStrength, strin } } - [TestCase(NormalizationMode.Off, "ä", "a\u0308", Result = 0)] - [TestCase(NormalizationMode.Off, "a\u0308", "ä\u0323", Result = -1)] - [TestCase(NormalizationMode.Off, "ä\u0323", "ạ\u0308", Result = -1)] - [TestCase(NormalizationMode.On, "ä", "a\u0308", Result = 0)] - [TestCase(NormalizationMode.On, "a\u0308", "ä\u0323", Result = -1)] - [TestCase(NormalizationMode.On, "ä\u0323", "ạ\u0308", Result = 0)] + [TestCase(NormalizationMode.Off, "ä", "a\u0308", ExpectedResult = 0)] + [TestCase(NormalizationMode.Off, "a\u0308", "ä\u0323", ExpectedResult = -1)] + [TestCase(NormalizationMode.Off, "ä\u0323", "ạ\u0308", ExpectedResult = -1)] + [TestCase(NormalizationMode.On, "ä", "a\u0308", ExpectedResult = 0)] + [TestCase(NormalizationMode.On, "a\u0308", "ä\u0323", ExpectedResult = -1)] + [TestCase(NormalizationMode.On, "ä\u0323", "ạ\u0308", ExpectedResult = 0)] public int NormalizationModeSetting(NormalizationMode normalizationMode, string string1, string string2) { @@ -330,13 +330,13 @@ public int NormalizationModeSetting(NormalizationMode normalizationMode, string } // 1 < 10 < 2 < 20 - [TestCase(NumericCollation.Off, "1", "10", Result = -1)] - [TestCase(NumericCollation.Off, "10", "2", Result = -1)] - [TestCase(NumericCollation.Off, "2", "20", Result = -1)] + [TestCase(NumericCollation.Off, "1", "10", ExpectedResult = -1)] + [TestCase(NumericCollation.Off, "10", "2", ExpectedResult = -1)] + [TestCase(NumericCollation.Off, "2", "20", ExpectedResult = -1)] // 1 < 2 < 10 < 20 - [TestCase(NumericCollation.On, "1", "10", Result = -1)] - [TestCase(NumericCollation.On, "10", "2", Result = 1)] - [TestCase(NumericCollation.On, "2", "20", Result = -1)] + [TestCase(NumericCollation.On, "1", "10", ExpectedResult = -1)] + [TestCase(NumericCollation.On, "10", "2", ExpectedResult = 1)] + [TestCase(NumericCollation.On, "2", "20", ExpectedResult = -1)] public int NumericCollationSetting(NumericCollation numericCollation, string string1, string string2) { @@ -348,15 +348,15 @@ public int NumericCollationSetting(NumericCollation numericCollation, string str } } - [TestCase(CollationStrength.Primary, "role", "Role", Result = 0)] - [TestCase(CollationStrength.Primary, "Role", "rôle", Result = 0)] - [TestCase(CollationStrength.Secondary, "role", "Role", Result = 0)] - [TestCase(CollationStrength.Secondary, "Role", "rôle", Result = -1)] - [TestCase(CollationStrength.Tertiary, "role", "Role", Result = -1)] - [TestCase(CollationStrength.Tertiary, "Role", "rôle", Result = -1)] - [TestCase(CollationStrength.Quaternary, "ab", "a c", Result = -1)] - [TestCase(CollationStrength.Quaternary, "a c", "a-c", Result = -1)] - [TestCase(CollationStrength.Quaternary, "a-c", "ac", Result = -1)] + [TestCase(CollationStrength.Primary, "role", "Role", ExpectedResult = 0)] + [TestCase(CollationStrength.Primary, "Role", "rôle", ExpectedResult = 0)] + [TestCase(CollationStrength.Secondary, "role", "Role", ExpectedResult = 0)] + [TestCase(CollationStrength.Secondary, "Role", "rôle", ExpectedResult = -1)] + [TestCase(CollationStrength.Tertiary, "role", "Role", ExpectedResult = -1)] + [TestCase(CollationStrength.Tertiary, "Role", "rôle", ExpectedResult = -1)] + [TestCase(CollationStrength.Quaternary, "ab", "a c", ExpectedResult = -1)] + [TestCase(CollationStrength.Quaternary, "a c", "a-c", ExpectedResult = -1)] + [TestCase(CollationStrength.Quaternary, "a-c", "ac", ExpectedResult = -1)] public int StrengthSetting(CollationStrength collationStrength, string string1, string string2) { diff --git a/source/icu.net.tests/NormalizerTests.cs b/source/icu.net.tests/NormalizerTests.cs index ddfda1eb..adfe601d 100644 --- a/source/icu.net.tests/NormalizerTests.cs +++ b/source/icu.net.tests/NormalizerTests.cs @@ -10,20 +10,20 @@ namespace Icu.Tests [TestFixture] public class NormalizerTests { - [TestCase("XA\u0308bc", Normalizer.UNormalizationMode.UNORM_NFC, Result = "X\u00C4bc")] - [TestCase("X\u00C4bc", Normalizer.UNormalizationMode.UNORM_NFD, Result = "XA\u0308bc")] - [TestCase("tést", Normalizer.UNormalizationMode.UNORM_NFD, Result = "te\u0301st")] - [TestCase("te\u0301st", Normalizer.UNormalizationMode.UNORM_NFC, Result = "tést")] - [TestCase("te\u0301st", Normalizer.UNormalizationMode.UNORM_NFD, Result = "te\u0301st")] + [TestCase("XA\u0308bc", Normalizer.UNormalizationMode.UNORM_NFC, ExpectedResult = "X\u00C4bc")] + [TestCase("X\u00C4bc", Normalizer.UNormalizationMode.UNORM_NFD, ExpectedResult = "XA\u0308bc")] + [TestCase("tést", Normalizer.UNormalizationMode.UNORM_NFD, ExpectedResult = "te\u0301st")] + [TestCase("te\u0301st", Normalizer.UNormalizationMode.UNORM_NFC, ExpectedResult = "tést")] + [TestCase("te\u0301st", Normalizer.UNormalizationMode.UNORM_NFD, ExpectedResult = "te\u0301st")] public string Normalize(string src, Normalizer.UNormalizationMode mode) { return Normalizer.Normalize(src, mode); } - [TestCase("X\u00C4bc", Normalizer.UNormalizationMode.UNORM_NFC, Result = true)] - [TestCase("XA\u0308bc", Normalizer.UNormalizationMode.UNORM_NFC, Result = false)] - [TestCase("X\u00C4bc", Normalizer.UNormalizationMode.UNORM_NFD, Result = false)] - [TestCase("XA\u0308bc", Normalizer.UNormalizationMode.UNORM_NFD, Result = true)] + [TestCase("X\u00C4bc", Normalizer.UNormalizationMode.UNORM_NFC, ExpectedResult = true)] + [TestCase("XA\u0308bc", Normalizer.UNormalizationMode.UNORM_NFC, ExpectedResult = false)] + [TestCase("X\u00C4bc", Normalizer.UNormalizationMode.UNORM_NFD, ExpectedResult = false)] + [TestCase("XA\u0308bc", Normalizer.UNormalizationMode.UNORM_NFD, ExpectedResult = true)] public bool IsNormalized(string src, Normalizer.UNormalizationMode expectNormalizationMode) { return Normalizer.IsNormalized(src, expectNormalizationMode); From d3c4dd4cce76b1465c1bc5a47ed968c76942793a Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Fri, 13 Jan 2017 14:53:48 -0800 Subject: [PATCH 13/60] Replace Assert.IsNotNullOrEmpty -> Assert.IsNotNull and Assert.IsNotEmpty --- source/icu.net.tests/Collation/RuleBasedCollatorTests.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/icu.net.tests/Collation/RuleBasedCollatorTests.cs b/source/icu.net.tests/Collation/RuleBasedCollatorTests.cs index e9ecbbf2..9d78a67e 100644 --- a/source/icu.net.tests/Collation/RuleBasedCollatorTests.cs +++ b/source/icu.net.tests/Collation/RuleBasedCollatorTests.cs @@ -905,7 +905,8 @@ public void GetSortRules_English() var collationRules = Collator.GetCollationRules(locale, UColRuleOption.UCOL_FULL_RULES); Assert.IsEmpty(tailoredRules); - Assert.IsNotNullOrEmpty(collationRules); + Assert.IsNotNull(collationRules); + Assert.IsNotEmpty(collationRules); } } } From 9b286dca096e50f79ac53120faeecc5b065dea7b Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Fri, 13 Jan 2017 14:54:09 -0800 Subject: [PATCH 14/60] Replace ExpectedException(T) with Assert.Throws --- .../icu.net.tests/Collation/SortKeyTests.cs | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/source/icu.net.tests/Collation/SortKeyTests.cs b/source/icu.net.tests/Collation/SortKeyTests.cs index 3a2f0b6c..af68cb48 100644 --- a/source/icu.net.tests/Collation/SortKeyTests.cs +++ b/source/icu.net.tests/Collation/SortKeyTests.cs @@ -15,34 +15,30 @@ public class SortKeyTests public const int Same = 0; [Test] - [ExpectedException(typeof(ArgumentNullException))] public void SortKey_nullKeyData_Throws() { - Collator.CreateSortKey("hello", null); + Assert.Throws(() => Collator.CreateSortKey("hello", null)); } [Test] - [ExpectedException(typeof(ArgumentOutOfRangeException))] public void SortKey_KeyDataLengthTooLarge_Throws() { byte[] keyData = new byte[] { 0xae, 0x1,0x20,0x1}; - Collator.CreateSortKey("hello", keyData, keyData.Length+1); + Assert.Throws(() => Collator.CreateSortKey("hello", keyData, keyData.Length + 1)); } [Test] - [ExpectedException(typeof(ArgumentOutOfRangeException))] public void SortKey_KeyDataLengthNegative_Throws() { byte[] keyData = new byte[] { 0xae, 0x1, 0x20,0x1 }; - Collator.CreateSortKey("hello", keyData, -1); + Assert.Throws(() => Collator.CreateSortKey("hello", keyData, -1)); } [Test] - [ExpectedException(typeof(ArgumentNullException))] public void SortKey_nullOriginalString_Throws() { byte[] keyData = new byte[] { 0xae, 0x1, 0x20,0x1 }; - Collator.CreateSortKey(null, keyData); + Assert.Throws(() => Collator.CreateSortKey(null, keyData)); } [Test] @@ -73,28 +69,25 @@ public void Compare_keyDataByteChanges_NotAffected() } [Test] - [ExpectedException(typeof(ArgumentNullException))] public void Compare_bothnull_throws() { - SortKey.Compare(null, null); + Assert.Throws(() => SortKey.Compare(null, null)); } [Test] - [ExpectedException(typeof(ArgumentNullException))] public void Compare_firstnull_throws() { byte[] keyData = new byte[] { 0xae, 0x1, 0x20, 0x1 }; SortKey sortKey = Collator.CreateSortKey("heo", keyData); - SortKey.Compare(null, sortKey); + Assert.Throws(() => SortKey.Compare(null, sortKey)); } [Test] - [ExpectedException(typeof(ArgumentNullException))] public void Compare_secondnull_throws() { byte[] keyData = new byte[] { 0xae, 0x1, 0x20, 0x1 }; SortKey sortKey = Collator.CreateSortKey("heo", keyData); - SortKey.Compare(sortKey, null); + Assert.Throws(() => SortKey.Compare(sortKey, null)); } [Test] From 3f620fd5c427b4223e394a9c15672707efecdae2 Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Wed, 8 Mar 2017 01:05:43 -0800 Subject: [PATCH 15/60] Add icu.net.netstandard.tests project --- .../icu.net.netstandard.tests.csproj | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 source/icu.net.netstandard.tests/icu.net.netstandard.tests.csproj diff --git a/source/icu.net.netstandard.tests/icu.net.netstandard.tests.csproj b/source/icu.net.netstandard.tests/icu.net.netstandard.tests.csproj new file mode 100644 index 00000000..761c6375 --- /dev/null +++ b/source/icu.net.netstandard.tests/icu.net.netstandard.tests.csproj @@ -0,0 +1,27 @@ + + + + ..\icu.net.tests + + netcoreapp1.1 + + + + + + + + + + + + + + + + + %(RecursiveDir)%(Filename)%(Extension) + + + + From 2f08c0ed66ea01fe34b949b419ca7b3578ea6b4b Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Tue, 28 Feb 2017 14:06:20 -0800 Subject: [PATCH 16/60] Specifying icu-dotnet as CLS-Compliant --- source/icu.net/Properties/AssemblyInfo.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/icu.net/Properties/AssemblyInfo.cs b/source/icu.net/Properties/AssemblyInfo.cs index 569d99fe..cd9312bc 100644 --- a/source/icu.net/Properties/AssemblyInfo.cs +++ b/source/icu.net/Properties/AssemblyInfo.cs @@ -1,6 +1,5 @@ -// Copyright (c) 2007-2017 SIL International +// Copyright (c) 2007-2017 SIL International // This software is licensed under the MIT license (http://opensource.org/licenses/MIT) - using System; using System.Reflection; using System.Runtime.InteropServices; @@ -17,6 +16,7 @@ [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] +// Setting assembly to CLS compliant so that it can be used on any other .NET languages. [assembly: CLSCompliant(true)] // Setting ComVisible to false makes the types in this assembly not visible From 01643bfe1b688ebe7f37b2b92bafabca64e154e6 Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Tue, 28 Feb 2017 14:54:32 -0800 Subject: [PATCH 17/60] Use LoadLibraryEx instead of LoadLibrary (and remove use of SetDllDirectory). --- source/icu.net/NativeMethods.cs | 48 +++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/source/icu.net/NativeMethods.cs b/source/icu.net/NativeMethods.cs index eeb0040e..8d506a38 100644 --- a/source/icu.net/NativeMethods.cs +++ b/source/icu.net/NativeMethods.cs @@ -1,6 +1,7 @@ // Copyright (c) 2013-2017 SIL International // This software is licensed under the MIT license (http://opensource.org/licenses/MIT) using System; +using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Linq; @@ -60,7 +61,7 @@ static NativeMethods() #region Native methods for Windows [DllImport("kernel32.dll", SetLastError = true)] - private static extern IntPtr LoadLibrary(string dllToLoad); + private static extern IntPtr LoadLibraryEx(string dllToLoad, IntPtr hReservedNull, LoadLibraryFlags dwFlags); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool FreeLibrary(IntPtr hModule); @@ -68,8 +69,23 @@ static NativeMethods() [DllImport("kernel32.dll", SetLastError = true)] private static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName); - [DllImport("kernel32.dll", SetLastError = true)] - private static extern bool SetDllDirectory(string dllDirectory); + [Flags] + internal enum LoadLibraryFlags : uint + { + NONE = 0x00000000, + DONT_RESOLVE_DLL_REFERENCES = 0x00000001, + LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x00000010, + LOAD_LIBRARY_AS_DATAFILE = 0x00000002, + LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 0x00000040, + LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020, + LOAD_LIBRARY_SEARCH_APPLICATION_DIR = 0x00000200, + LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x00001000, + LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR = 0x00000100, + LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800, + LOAD_LIBRARY_SEARCH_USER_DIRS = 0x00000400, + LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008 + } + #endregion private static int IcuVersion; @@ -122,9 +138,10 @@ internal static string DirectoryOfThisAssembly private static void AddDirectoryToSearchPath(string directory) { - if (IsWindows) - SetDllDirectory(directory); - else + // Only perform this for Linux because we are using LoadLibraryEx + // to ensure that a library's dependencies is loaded starting from + // where that library is located. + if (!IsWindows) { var ldLibPath = Environment.GetEnvironmentVariable("LD_LIBRARY_PATH"); Environment.SetEnvironmentVariable("LD_LIBRARY_PATH", @@ -154,6 +171,7 @@ private static bool CheckDirectoryForIcuBinaries(string directory, string librar icuVersion, directory); IcuVersion = icuVersion; _IcuPath = directory; + AddDirectoryToSearchPath(directory); return true; } @@ -219,8 +237,22 @@ private static IntPtr GetIcuLibHandle(string basename, int icuVersion) if (IsWindows) { var libName = $"{basename}{icuVersion}.dll"; - libPath = string.IsNullOrEmpty(_IcuPath) ? libName : Path.Combine(_IcuPath, libName); - handle = LoadLibrary(libPath); + var isIcuPathSpecified = !string.IsNullOrEmpty(_IcuPath); + libPath = isIcuPathSpecified ? Path.Combine(_IcuPath, libName) : libName; + + var loadLibraryFlags = LoadLibraryFlags.NONE; + + if (isIcuPathSpecified) + loadLibraryFlags |= LoadLibraryFlags.LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LoadLibraryFlags.LOAD_LIBRARY_SEARCH_DEFAULT_DIRS; + + handle = LoadLibraryEx(libPath, IntPtr.Zero, loadLibraryFlags); + var lastError = Marshal.GetLastWin32Error(); + + if (handle == IntPtr.Zero && lastError != 0) + { + string errorMessage = new Win32Exception(lastError).Message; + Trace.WriteLine(string.Format("Unable to load [{0}]. Error: {1}", libPath, errorMessage)); + } } else { From 10a5d0780878b68461d387de302875d7d748b02c Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Tue, 28 Feb 2017 14:58:09 -0800 Subject: [PATCH 18/60] Add NativeMethods.NetCore locate native assets on Windows or NetCore --- source/icu.net/NativeMethods.NetCore.cs | 333 ++++++++++++++++++++++++ 1 file changed, 333 insertions(+) create mode 100644 source/icu.net/NativeMethods.NetCore.cs diff --git a/source/icu.net/NativeMethods.NetCore.cs b/source/icu.net/NativeMethods.NetCore.cs new file mode 100644 index 00000000..bdcb1794 --- /dev/null +++ b/source/icu.net/NativeMethods.NetCore.cs @@ -0,0 +1,333 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; + +#if !NET40 +using Microsoft.Extensions.DependencyModel; +#endif + +namespace Icu +{ + /// + /// Helper class to try and get path to icu native binaries when running on + /// Windows or .NET Core. + /// + internal static class NativeMethodsHelper + { + private const string Icu4c = nameof(Icu4c); + private const string IcuRegexLinux = @"libicu\w+.so\.(?[0-9\.]{2,})"; + private const string IcuRegexWindows = @"icu\w+(?[0-9\.]{2,})\.dll"; + + private static readonly Regex IcuBinaryRegex = new Regex($"{IcuRegexWindows}|{IcuRegexLinux}$", RegexOptions.Compiled); + private static readonly string IcuSearchPattern = Platform.OperatingSystem == OperatingSystemType.Windows ? "icu*.dll" : "libicu*.so.*"; + private static readonly string NugetPackageDirectory = GetDefaultPackageDirectory(Platform.OperatingSystem); + + private static IcuVersionInfo IcuVersion; + + /// + /// Tries to get path and version to Icu when running on .NET Core or Windows. + /// + /// The path and version of icu binaries if found. Check + /// to see if the values were set. + public static IcuVersionInfo GetIcuVersionInfoForNetCoreOrWindows() + { + // We've already tried to set the path to native assets. Don't try again. + if (IcuVersion != null) + { + return IcuVersion; + } + + // Set the default to IcuVersion with an empty path and no version set. + IcuVersion = new IcuVersionInfo(); + + if (TryGetPathFromAssemblyDirectory()) + { + return IcuVersion; + } + + // That's odd.. I guess we use normal search paths from %PATH% then. + // One possibility is that it is not a dev machine and the application + // is a published app... but then it should have returned true in + // TryGetPathFromAssemblyDirectory. + if (string.IsNullOrEmpty(NugetPackageDirectory)) + { + Trace.TraceWarning($"{nameof(NugetPackageDirectory)} is empty and application was unable to set path from current assembly directory."); + return IcuVersion; + } + +#if !NET40 + var context = DependencyContext.Default; + // If this is false, something went wrong. These files should have + // either been found above or we should have been able to locate the + // asset paths (for .NET Core and NuGet v3+ projects). + if (!TryGetNativeAssetPaths(context, out string[] nativeAssetPaths)) + { + Trace.WriteLine("Could not locate icu native assets from DependencyModel."); + return IcuVersion; + } + + var icuLib = context.CompileLibraries + .Where(x => x.Name.StartsWith(Icu4c, StringComparison.OrdinalIgnoreCase)) + .FirstOrDefault(); + + if (icuLib == default(CompilationLibrary)) + { + Trace.TraceWarning("Could not find Icu4c compilation library. Possible that the library writer did not include the Icu4c.Win.Full.Lib or Icu4c.Win.Full.Lib NuGet package."); + return IcuVersion; + } + + if (!TryResolvePackagePath(icuLib, NugetPackageDirectory, out string packagePath)) + { + Trace.WriteLine("Could not resolve nuget package directory...."); + return IcuVersion; + } + + TrySetIcuPathFromDirectory(new DirectoryInfo(packagePath), nativeAssetPaths); +#endif + + return IcuVersion; + } + + /// + /// Tries to set the native library using the + /// as the root directory. The following scenarios could happen: + /// 1. {directoryOfAssembly}/icu*.dll + /// Occurs when the project is published using the .NET Core CLI + /// against the full .NET framework. + /// 2. {directoryOfAssembly}/lib/{arch}/icu*.dll + /// Occurs when the project is using NuGet v2, the traditional + /// .NET Framework csproj or the new VS2017 projects. + /// 3. {directoryOfAssembly}/runtimes/{runtimeId}/native/icu*.dll + /// Occurs when the project is published using the .NET Core CLI. + /// If one of the scenarios match, sets the . + /// + /// True if it was able to find the icu binaries within + /// , false otherwise. + /// + private static bool TryGetPathFromAssemblyDirectory() + { + var assemblyDirectory = new DirectoryInfo(NativeMethods.DirectoryOfThisAssembly); + int version; + + // 1. Check in {assemblyDirectory}/ + if (TryGetIcuVersionNumber(assemblyDirectory, out version)) + { + IcuVersion = new IcuVersionInfo(assemblyDirectory, version); + return true; + } + + // 2. Check in {assemblyDirectory}/lib/{architecture}/ + var libPath = new DirectoryInfo(Path.Combine(assemblyDirectory.FullName, "lib", Platform.ProcessArchitecture)); + if (TryGetIcuVersionNumber(libPath, out version)) + { + IcuVersion = new IcuVersionInfo(libPath, version); + return true; + } + + string[] nativeAssetPaths = null; +#if !NET40 + // 3. Check in {directoryOfAssembly}/runtimes/{runtimeId}/native/ + if (!TryGetNativeAssetPaths(DependencyContext.Default, out nativeAssetPaths)) + { + Trace.WriteLine("Could not locate icu native assets from DependencyModel."); + return false; + } +#endif + // If we found the icu*.dll files under {directoryOfAssembly}/runtimes/{rid}/native/, + // they should ALL be there... or else something went wrong in publishing the app or + // restoring the files, or packaging the NuGet package. + return TrySetIcuPathFromDirectory(assemblyDirectory, nativeAssetPaths); + } + + /// + /// Iterates through the directory for files with the path icu*.dll and + /// tries to fetch the icu version number from them. + /// + /// Returns the version number if the search was successful and + /// null, otherwise. + private static bool TryGetIcuVersionNumber(DirectoryInfo directory, out int icuVersion) + { + icuVersion = int.MinValue; + + if (directory == null || !directory.Exists) + return false; + + var version = directory.GetFiles(IcuSearchPattern) + ?.Select(x => + { + var match = IcuBinaryRegex.Match(x.Name); + return match.Success + ? int.Parse(match.Groups["version"].Value) + : new int?(); + }) + .OrderByDescending(x => x) + .FirstOrDefault(); + + if (version.HasValue) + icuVersion = version.Value; + + return version.HasValue; + } + + /// + /// Given a root path and a set of native asset paths, tries to see if + /// the files exist and if they do, sets . + /// + /// Root path to append asset paths to. + /// Set of native asset paths to check. + /// true if it was able to find the directory for all the asset + /// paths given; false otherwise. + private static bool TrySetIcuPathFromDirectory(DirectoryInfo baseDirectory, string[] nativeAssetPaths) + { + if (nativeAssetPaths == null || nativeAssetPaths.Length == 0) + return false; + + Trace.WriteLine("Assets: " + Environment.NewLine + string.Join(Environment.NewLine + "\t-", nativeAssetPaths)); + + var assetPaths = nativeAssetPaths + .Select(asset => new FileInfo(Path.Combine(baseDirectory.FullName, asset))); + + var doAllAssetsExistInDirectory = assetPaths.All(x => x.Exists); + + if (doAllAssetsExistInDirectory) + { + var directories = assetPaths.Select(file => file.Directory).ToArray(); + + if (directories.Length > 1) + Trace.TraceWarning($"There are multiple directories for these runtime assets: {string.Join(Path.PathSeparator.ToString(), directories.Select(x => x.FullName))}. There should only be one... Using first directory."); + + var icuDirectory = directories.First(); + + if (TryGetIcuVersionNumber(icuDirectory, out int version)) + { + IcuVersion = new IcuVersionInfo(icuDirectory, version); + } + } + + return doAllAssetsExistInDirectory; + } + +#if !NET40 + /// + /// Tries to get the icu native binaries by searching the Runtime + /// ID graph to find the first set of paths that have those binaries. + /// + /// Unique relative paths to the native assets; empty if none + /// could be found. + private static bool TryGetNativeAssetPaths(DependencyContext context, out string[] nativeAssetPaths) + { + var assetPaths = Enumerable.Empty(); + + if (context == null) + { + nativeAssetPaths = assetPaths.ToArray(); + return false; + } + + var defaultNativeAssets = context.GetDefaultNativeAssets().ToArray(); + + // This goes through the runtime graph and tries to find icu native + // asset paths matching that runtime. + foreach (var runtime in context.RuntimeGraph) + { + var nativeAssets = context.GetRuntimeNativeAssets(runtime.Runtime); + assetPaths = nativeAssets.Except(defaultNativeAssets).Where(assetPath => IcuBinaryRegex.IsMatch(assetPath)); + + if (assetPaths.Any()) + break; + } + + nativeAssetPaths = assetPaths.ToArray(); + + return nativeAssetPaths.Length > 0; + } + + /// + /// Given a CompilationLibrary and a base path, tries to construct the + /// nuget package location and returns true if it exists. + /// + /// Taken from: https://github.com/dotnet/core-setup/blob/master/src/Microsoft.Extensions.DependencyModel/Resolution/ResolverUtils.cs#L12 + /// + /// Compilation library to try to get the rooted + /// path from. + /// Rooted base path to try and get library from. + /// The path for the library if it exists; + /// null otherwise. + /// + private static bool TryResolvePackagePath(CompilationLibrary library, string basePath, out string packagePath) + { + var path = library.Path; + if (string.IsNullOrEmpty(path)) + { + path = Path.Combine(library.Name, library.Version); + } + + packagePath = Path.Combine(basePath, path); + + return Directory.Exists(packagePath); + } +#endif + + /// + /// Tries to fetch the default package directory for NuGet packages. + /// Taken from: + /// https://github.com/dotnet/core-setup/blob/master/src/Microsoft.Extensions.DependencyModel/Resolution/PackageCompilationAssemblyResolver.cs#L41-L64 + /// + /// OS Platform to fetch default package + /// directory for. + /// The path to the default package directory; null if none + /// could be set. + private static string GetDefaultPackageDirectory(OperatingSystemType osPlatform) + { + var packageDirectory = Environment.GetEnvironmentVariable("NUGET_PACKAGES"); + + if (!string.IsNullOrEmpty(packageDirectory)) + { + return packageDirectory; + } + + string basePath; + if (osPlatform == OperatingSystemType.Windows) + { + basePath = Environment.GetEnvironmentVariable("USERPROFILE"); + } + else + { + basePath = Environment.GetEnvironmentVariable("HOME"); + } + if (string.IsNullOrEmpty(basePath)) + { + return null; + } + return Path.Combine(basePath, ".nuget", "packages"); + } + + /// + /// Returns the result of trying to resolve the icu binary paths. + /// + internal class IcuVersionInfo + { + public IcuVersionInfo() + { + Success = false; + } + + public IcuVersionInfo(DirectoryInfo icuPath, int icuVersion) + { + if (icuVersion <= 0) + throw new ArgumentOutOfRangeException(nameof(icuVersion), "IcuVersion should be greater than 0"); + + IcuPath = icuPath; + IcuVersion = icuVersion; + Success = true; + } + + public bool Success { get; } + + public readonly DirectoryInfo IcuPath; + public readonly int IcuVersion; + } + } +} From 563efc5e1c9b1ff09a8bdb224c266b167d72c4bb Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Tue, 7 Mar 2017 23:22:53 -0800 Subject: [PATCH 19/60] NativeMethods now calls into .NET Core helper to try and get IcuVersion --- source/icu.net/NativeMethods.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/source/icu.net/NativeMethods.cs b/source/icu.net/NativeMethods.cs index 8d506a38..e40a81e4 100644 --- a/source/icu.net/NativeMethods.cs +++ b/source/icu.net/NativeMethods.cs @@ -39,6 +39,14 @@ public static void SetMinMaxIcuVersions(int minVersion = MinIcuVersionDefault, static NativeMethods() { Methods = new MethodsContainer(); +#if !NET40 + var icuInfo = NativeMethodsHelper.GetIcuVersionInfoForNetCoreOrWindows(); + if (icuInfo.Success) + { + _IcuPath = icuInfo.IcuPath.FullName; + IcuVersion = icuInfo.IcuVersion; + } +#endif } #region Dynamic method loading From 909d05d816d74bb4e3838441036d62c8f32add86 Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Tue, 7 Mar 2017 23:24:05 -0800 Subject: [PATCH 20/60] Remove [MarshalAs(UnmanagedType.LPTStr] from dlopen and dlsym because they result in errors when PInvoking on Linux --- source/icu.net/NativeMethods.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/icu.net/NativeMethods.cs b/source/icu.net/NativeMethods.cs index e40a81e4..fd4c3981 100644 --- a/source/icu.net/NativeMethods.cs +++ b/source/icu.net/NativeMethods.cs @@ -56,13 +56,13 @@ static NativeMethods() private const int RTLD_NOW = 2; [DllImport("libdl.so", SetLastError = true)] - private static extern IntPtr dlopen([MarshalAs(UnmanagedType.LPTStr)] string file, int mode); + private static extern IntPtr dlopen(string file, int mode); [DllImport("libdl.so", SetLastError = true)] private static extern int dlclose(IntPtr handle); [DllImport("libdl.so", SetLastError = true)] - private static extern IntPtr dlsym(IntPtr handle, [MarshalAs(UnmanagedType.LPTStr)] string name); + private static extern IntPtr dlsym(IntPtr handle, string name); #endregion From 90fce877ca16d5bd107e607010006234d48b8a52 Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Tue, 7 Mar 2017 23:09:09 -0800 Subject: [PATCH 21/60] Ignoring NativeMethodsTests and adding Compiler directive around unsupported PlatformAttribute --- source/icu.net.tests/NativeMethodsTests.cs | 6 +++++- source/icu.net.tests/icu.net.tests.csproj | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/source/icu.net.tests/NativeMethodsTests.cs b/source/icu.net.tests/NativeMethodsTests.cs index 86cecf76..5d3278fd 100644 --- a/source/icu.net.tests/NativeMethodsTests.cs +++ b/source/icu.net.tests/NativeMethodsTests.cs @@ -8,9 +8,13 @@ namespace Icu.Tests { - [TestFixture] +#if NETCOREAPP1_1 + [Ignore("System.Diagnostics.Process is not supported in .NETStandard 1.6.")] +#else [Platform(Exclude = "Linux", Reason = "These tests require ICU4C installed from NuGet packages which isn't available on Linux")] +#endif + [TestFixture] public class NativeMethodsTests { private string _tmpDir; diff --git a/source/icu.net.tests/icu.net.tests.csproj b/source/icu.net.tests/icu.net.tests.csproj index 1a5672e9..39f13eb5 100644 --- a/source/icu.net.tests/icu.net.tests.csproj +++ b/source/icu.net.tests/icu.net.tests.csproj @@ -110,7 +110,7 @@ - $(DefineConstants);ICU_VER_$(icu_ver) + $(DefineConstants);NET40 ..\..\output\$(Configuration) From cd01c98cdbe77df53f697d4d7802768e3ef55d34 Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Wed, 8 Mar 2017 01:29:44 -0800 Subject: [PATCH 22/60] Adding test project to solution --- source/icu.net.netstandard.sln | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source/icu.net.netstandard.sln b/source/icu.net.netstandard.sln index cb867d89..607db8cb 100644 --- a/source/icu.net.netstandard.sln +++ b/source/icu.net.netstandard.sln @@ -5,6 +5,8 @@ VisualStudioVersion = 15.0.26228.4 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "icu.net.netstandard", "icu.net.netstandard\icu.net.netstandard.csproj", "{AA4C50FD-F411-484F-A17B-0A69B8784A10}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "icu.net.netstandard.tests", "icu.net.netstandard.tests\icu.net.netstandard.tests.csproj", "{9D724A81-8913-45DA-B798-4710DA90BC91}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -15,6 +17,10 @@ Global {AA4C50FD-F411-484F-A17B-0A69B8784A10}.Debug|Any CPU.Build.0 = Debug|Any CPU {AA4C50FD-F411-484F-A17B-0A69B8784A10}.Release|Any CPU.ActiveCfg = Release|Any CPU {AA4C50FD-F411-484F-A17B-0A69B8784A10}.Release|Any CPU.Build.0 = Release|Any CPU + {9D724A81-8913-45DA-B798-4710DA90BC91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9D724A81-8913-45DA-B798-4710DA90BC91}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9D724A81-8913-45DA-B798-4710DA90BC91}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9D724A81-8913-45DA-B798-4710DA90BC91}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 3775fb9124c560259b708e4fef35f3f1554c986e Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Wed, 8 Mar 2017 01:30:10 -0800 Subject: [PATCH 23/60] Add [SetCulture] and [SetUICulture] because .NUnit portable does not contain it --- .../SetCultureAttribute.cs | 36 +++++++++++++++++++ .../SetUICultureAttribute.cs | 36 +++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 source/icu.net.netstandard.tests/SetCultureAttribute.cs create mode 100644 source/icu.net.netstandard.tests/SetUICultureAttribute.cs diff --git a/source/icu.net.netstandard.tests/SetCultureAttribute.cs b/source/icu.net.netstandard.tests/SetCultureAttribute.cs new file mode 100644 index 00000000..8b72d64f --- /dev/null +++ b/source/icu.net.netstandard.tests/SetCultureAttribute.cs @@ -0,0 +1,36 @@ +using System; +using NUnit.Framework; +using NUnit.Framework.Interfaces; +using NUnit.Framework.Internal; + +namespace Icu.Tests +{ + /// + /// TODO: Remove this when NUnit adds this to its .NETStandard packages. + /// Taken from: + /// https://github.com/nunit/nunit/blob/master/src/NUnitFramework/framework/Attributes/SetCultureAttribute.cs + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Assembly, AllowMultiple = false, Inherited = true)] + public class SetCultureAttribute : PropertyAttribute, IApplyToContext + { + private string _culture; + + /// + /// Construct given the name of a culture + /// + /// + public SetCultureAttribute(string culture) : base("SetCulture", culture) + { + _culture = culture; + } + + #region IApplyToContext Members + + void IApplyToContext.ApplyToContext(TestExecutionContext context) + { + context.CurrentCulture = new System.Globalization.CultureInfo(_culture); + } + + #endregion + } +} diff --git a/source/icu.net.netstandard.tests/SetUICultureAttribute.cs b/source/icu.net.netstandard.tests/SetUICultureAttribute.cs new file mode 100644 index 00000000..90234ed8 --- /dev/null +++ b/source/icu.net.netstandard.tests/SetUICultureAttribute.cs @@ -0,0 +1,36 @@ +using System; +using NUnit.Framework; +using NUnit.Framework.Interfaces; +using NUnit.Framework.Internal; + +namespace Icu.Tests +{ + /// + /// TODO: Remove this when NUnit adds this to its .NETStandard packages. + /// Taken from: + /// https://github.com/nunit/nunit/blob/master/src/NUnitFramework/framework/Attributes/SetUICultureAttribute.cs + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Assembly, AllowMultiple = false, Inherited = true)] + public class SetUICultureAttribute : PropertyAttribute, IApplyToContext + { + private string _culture; + + /// + /// Construct given the name of a culture + /// + /// + public SetUICultureAttribute(string culture) : base("SetUICulture", culture) + { + _culture = culture; + } + + #region IApplyToContext Members + + void IApplyToContext.ApplyToContext(TestExecutionContext context) + { + context.CurrentUICulture = new System.Globalization.CultureInfo(_culture); + } + + #endregion + } +} From 9fa373e454a28004af3aaa0d5e79ee6e4befedf2 Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Thu, 13 Apr 2017 21:57:56 -0700 Subject: [PATCH 24/60] Replacing [SetCulture] and [SetUICulture] and replacing it with helper method --- .../SetCultureAttribute.cs | 36 -------------- .../SetUICultureAttribute.cs | 36 -------------- source/icu.net.tests/CharacterTests.cs | 16 ++++++- source/icu.net.tests/LocaleTests.cs | 47 +++++++++++++++++-- 4 files changed, 56 insertions(+), 79 deletions(-) delete mode 100644 source/icu.net.netstandard.tests/SetCultureAttribute.cs delete mode 100644 source/icu.net.netstandard.tests/SetUICultureAttribute.cs diff --git a/source/icu.net.netstandard.tests/SetCultureAttribute.cs b/source/icu.net.netstandard.tests/SetCultureAttribute.cs deleted file mode 100644 index 8b72d64f..00000000 --- a/source/icu.net.netstandard.tests/SetCultureAttribute.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using NUnit.Framework; -using NUnit.Framework.Interfaces; -using NUnit.Framework.Internal; - -namespace Icu.Tests -{ - /// - /// TODO: Remove this when NUnit adds this to its .NETStandard packages. - /// Taken from: - /// https://github.com/nunit/nunit/blob/master/src/NUnitFramework/framework/Attributes/SetCultureAttribute.cs - /// - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Assembly, AllowMultiple = false, Inherited = true)] - public class SetCultureAttribute : PropertyAttribute, IApplyToContext - { - private string _culture; - - /// - /// Construct given the name of a culture - /// - /// - public SetCultureAttribute(string culture) : base("SetCulture", culture) - { - _culture = culture; - } - - #region IApplyToContext Members - - void IApplyToContext.ApplyToContext(TestExecutionContext context) - { - context.CurrentCulture = new System.Globalization.CultureInfo(_culture); - } - - #endregion - } -} diff --git a/source/icu.net.netstandard.tests/SetUICultureAttribute.cs b/source/icu.net.netstandard.tests/SetUICultureAttribute.cs deleted file mode 100644 index 90234ed8..00000000 --- a/source/icu.net.netstandard.tests/SetUICultureAttribute.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using NUnit.Framework; -using NUnit.Framework.Interfaces; -using NUnit.Framework.Internal; - -namespace Icu.Tests -{ - /// - /// TODO: Remove this when NUnit adds this to its .NETStandard packages. - /// Taken from: - /// https://github.com/nunit/nunit/blob/master/src/NUnitFramework/framework/Attributes/SetUICultureAttribute.cs - /// - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Assembly, AllowMultiple = false, Inherited = true)] - public class SetUICultureAttribute : PropertyAttribute, IApplyToContext - { - private string _culture; - - /// - /// Construct given the name of a culture - /// - /// - public SetUICultureAttribute(string culture) : base("SetUICulture", culture) - { - _culture = culture; - } - - #region IApplyToContext Members - - void IApplyToContext.ApplyToContext(TestExecutionContext context) - { - context.CurrentUICulture = new System.Globalization.CultureInfo(_culture); - } - - #endregion - } -} diff --git a/source/icu.net.tests/CharacterTests.cs b/source/icu.net.tests/CharacterTests.cs index f0de7478..a01757f9 100644 --- a/source/icu.net.tests/CharacterTests.cs +++ b/source/icu.net.tests/CharacterTests.cs @@ -1,7 +1,8 @@ -// Copyright (c) 2013 SIL International +// Copyright (c) 2013 SIL International // This software is licensed under the MIT license (http://opensource.org/licenses/MIT) using System; using NUnit.Framework; +using System.Globalization; namespace Icu.Tests { @@ -126,10 +127,11 @@ public void IsSpace_String() } [Test] - [SetUICulture("en-US")] [Category("Full ICU")] public void GetPrettyICUCharName() { + SetUICulture("en-US"); + Assert.That(Character.GetPrettyICUCharName("a"), Is.EqualTo("Latin Small Letter A")); Assert.That(Character.GetPrettyICUCharName("ab"), Is.Null); Assert.That(Character.GetPrettyICUCharName(string.Empty), Is.Null); @@ -143,5 +145,15 @@ public void GetCharName() Assert.That(Character.GetCharName(65), Is.EqualTo("LATIN CAPITAL LETTER A")); Assert.That(Character.GetCharName(-1), Is.Null); } + + private void SetUICulture(string culture) + { + var cultureInfo = new CultureInfo(culture); +#if NET40 + System.Threading.Thread.CurrentThread.CurrentUICulture = cultureInfo; +#else + CultureInfo.CurrentUICulture = cultureInfo; +#endif + } } } diff --git a/source/icu.net.tests/LocaleTests.cs b/source/icu.net.tests/LocaleTests.cs index 0d9580e6..84448ddd 100644 --- a/source/icu.net.tests/LocaleTests.cs +++ b/source/icu.net.tests/LocaleTests.cs @@ -1,20 +1,36 @@ -// Copyright (c) 2013 SIL International +// Copyright (c) 2013 SIL International // This software is licensed under the MIT license (http://opensource.org/licenses/MIT) using System; using NUnit.Framework; using Icu; +using System.Globalization; namespace Icu.Tests { [TestFixture] - [SetCulture("es-ES")] - [SetUICulture("en-US")] public class LocaleTests { + private readonly CultureInfo DefaultCulture = CultureInfo.CurrentCulture; + private readonly CultureInfo DefaultUICulture = CultureInfo.CurrentUICulture; + + [SetUp] + public void Setup() + { + SetCulture("es-ES"); + SetUICulture("en-US"); + } + + [TearDown] + public void TearDown() + { + SetCulture(DefaultCulture.Name); + SetUICulture(DefaultUICulture.Name); + } + [Test] - [SetUICulture("de-DE")] public void ConstructDefault() { + SetUICulture("de-DE"); Locale locale = new Locale(); Assert.That(locale.Id, Is.EqualTo("de_DE")); } @@ -203,10 +219,11 @@ public void DisplayLanguage() } [Test] - [SetUICulture("de-DE")] [Category("Full ICU")] public void DisplayLanguage_DifferentDefaultLocale() { + SetUICulture("de-DE"); + Locale locale = new Locale("en-US"); Assert.That(locale.DisplayLanguage, Is.EqualTo("Englisch")); } @@ -256,5 +273,25 @@ public void ImplicitCast() Locale locale = "en-US"; Assert.That(locale.Id, Is.EqualTo("en_US")); } + + private void SetUICulture(string culture) + { + var cultureInfo = new CultureInfo(culture); +#if NET40 + System.Threading.Thread.CurrentThread.CurrentUICulture = cultureInfo; +#else + CultureInfo.CurrentUICulture = cultureInfo; +#endif + } + + private void SetCulture(string culture) + { + var cultureInfo = new CultureInfo(culture); +#if NET40 + System.Threading.Thread.CurrentThread.CurrentCulture = cultureInfo; +#else + CultureInfo.CurrentCulture = cultureInfo; +#endif + } } } From dccbb6c2d0c82f6a0ed37743d8ba9cce3c2438d4 Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Thu, 13 Apr 2017 13:18:51 -0700 Subject: [PATCH 25/60] Adding NUnit test runner project due to nunit/dotnet-test-nunit#91 --- source/icu.net.netstandard.sln | 6 ++++++ source/icu.net.netstandard.testrunner/Program.cs | 15 +++++++++++++++ .../icu.net.netstandard.testrunner.csproj | 16 ++++++++++++++++ 3 files changed, 37 insertions(+) create mode 100644 source/icu.net.netstandard.testrunner/Program.cs create mode 100644 source/icu.net.netstandard.testrunner/icu.net.netstandard.testrunner.csproj diff --git a/source/icu.net.netstandard.sln b/source/icu.net.netstandard.sln index 607db8cb..d351c4be 100644 --- a/source/icu.net.netstandard.sln +++ b/source/icu.net.netstandard.sln @@ -7,6 +7,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "icu.net.netstandard", "icu. EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "icu.net.netstandard.tests", "icu.net.netstandard.tests\icu.net.netstandard.tests.csproj", "{9D724A81-8913-45DA-B798-4710DA90BC91}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "icu.net.netstandard.testrunner", "icu.net.netstandard.testrunner\icu.net.netstandard.testrunner.csproj", "{B8D007FE-5102-461C-A10B-11CD9DF57FB4}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -21,6 +23,10 @@ Global {9D724A81-8913-45DA-B798-4710DA90BC91}.Debug|Any CPU.Build.0 = Debug|Any CPU {9D724A81-8913-45DA-B798-4710DA90BC91}.Release|Any CPU.ActiveCfg = Release|Any CPU {9D724A81-8913-45DA-B798-4710DA90BC91}.Release|Any CPU.Build.0 = Release|Any CPU + {B8D007FE-5102-461C-A10B-11CD9DF57FB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B8D007FE-5102-461C-A10B-11CD9DF57FB4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B8D007FE-5102-461C-A10B-11CD9DF57FB4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B8D007FE-5102-461C-A10B-11CD9DF57FB4}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/source/icu.net.netstandard.testrunner/Program.cs b/source/icu.net.netstandard.testrunner/Program.cs new file mode 100644 index 00000000..f1098752 --- /dev/null +++ b/source/icu.net.netstandard.testrunner/Program.cs @@ -0,0 +1,15 @@ +using Icu.Tests; +using NUnitLite; +using System.Reflection; + +namespace icu.net.netstandard.testrunner +{ + class Program + { + public static int Main(string[] args) + { + var assembly = typeof(BreakIteratorTests).GetTypeInfo().Assembly; + return new AutoRun(assembly).Execute(args); + } + } +} \ No newline at end of file diff --git a/source/icu.net.netstandard.testrunner/icu.net.netstandard.testrunner.csproj b/source/icu.net.netstandard.testrunner/icu.net.netstandard.testrunner.csproj new file mode 100644 index 00000000..5f0271a4 --- /dev/null +++ b/source/icu.net.netstandard.testrunner/icu.net.netstandard.testrunner.csproj @@ -0,0 +1,16 @@ + + + + Exe + netcoreapp1.1 + + + + + + + + + + + \ No newline at end of file From ea10e860de3e84228d003719371643429cff9675 Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Thu, 13 Apr 2017 22:24:21 -0700 Subject: [PATCH 26/60] Add lock to NativeMethods class due to possibility of calling LoadIcuLibrary from different threads --- source/icu.net/NativeMethods.cs | 89 ++++++++++++++++++++------------- 1 file changed, 55 insertions(+), 34 deletions(-) diff --git a/source/icu.net/NativeMethods.cs b/source/icu.net/NativeMethods.cs index fd4c3981..4a6aeea0 100644 --- a/source/icu.net/NativeMethods.cs +++ b/source/icu.net/NativeMethods.cs @@ -12,6 +12,8 @@ namespace Icu { internal static class NativeMethods { + private static readonly object _lock = new object(); + private const int MinIcuVersionDefault = 44; private const int MaxIcuVersionDefault = 60; private static int minIcuVersion = MinIcuVersionDefault; @@ -30,8 +32,12 @@ public static void SetMinMaxIcuVersions(int minVersion = MinIcuVersionDefault, throw new ArgumentOutOfRangeException("maxVersion", $"supported ICU versions are between {MinIcuVersionDefault} and {MaxIcuVersionDefault}"); } - minIcuVersion = Math.Min(minVersion, maxVersion); - maxIcuVersion = Math.Max(minVersion, maxVersion); + + lock (_lock) + { + minIcuVersion = Math.Min(minVersion, maxVersion); + maxIcuVersion = Math.Max(minVersion, maxVersion); + } } private static MethodsContainer Methods; @@ -39,14 +45,7 @@ public static void SetMinMaxIcuVersions(int minVersion = MinIcuVersionDefault, static NativeMethods() { Methods = new MethodsContainer(); -#if !NET40 - var icuInfo = NativeMethodsHelper.GetIcuVersionInfoForNetCoreOrWindows(); - if (icuInfo.Success) - { - _IcuPath = icuInfo.IcuPath.FullName; - IcuVersion = icuInfo.IcuVersion; - } -#endif + ResetIcuVersionInfo(); } #region Dynamic method loading @@ -224,16 +223,19 @@ private static IntPtr LoadIcuLibrary(string libraryName) { Trace.WriteLineIf(!IsInitialized, "WARNING: ICU is not initialized."); - if (IcuVersion <= 0) - LocateIcuLibrary(libraryName); - - var handle = GetIcuLibHandle(libraryName, IcuVersion > 0 ? IcuVersion : maxIcuVersion); - if (handle == IntPtr.Zero) + lock(_lock) { - throw new FileLoadException($"Can't load ICU library (version {IcuVersion})", - libraryName); + if (IcuVersion <= 0) + LocateIcuLibrary(libraryName); + + var handle = GetIcuLibHandle(libraryName, IcuVersion > 0 ? IcuVersion : maxIcuVersion); + if (handle == IntPtr.Zero) + { + throw new FileLoadException($"Can't load ICU library (version {IcuVersion})", + libraryName); + } + return handle; } - return handle; } private static IntPtr GetIcuLibHandle(string basename, int icuVersion) @@ -282,26 +284,45 @@ private static IntPtr GetIcuLibHandle(string basename, int icuVersion) public static void Cleanup() { - u_cleanup(); - if (IsWindows) + lock (_lock) { - if (_IcuCommonLibHandle != IntPtr.Zero) - FreeLibrary(_IcuCommonLibHandle); - if (_IcuI18NLibHandle != IntPtr.Zero) - FreeLibrary(_IcuI18NLibHandle); - } - else - { - if (_IcuCommonLibHandle != IntPtr.Zero) - dlclose(_IcuCommonLibHandle); - if (_IcuI18NLibHandle != IntPtr.Zero) - dlclose(_IcuI18NLibHandle); + u_cleanup(); + if (IsWindows) + { + if (_IcuCommonLibHandle != IntPtr.Zero) + FreeLibrary(_IcuCommonLibHandle); + if (_IcuI18NLibHandle != IntPtr.Zero) + FreeLibrary(_IcuI18NLibHandle); + } + else + { + if (_IcuCommonLibHandle != IntPtr.Zero) + dlclose(_IcuCommonLibHandle); + if (_IcuI18NLibHandle != IntPtr.Zero) + dlclose(_IcuI18NLibHandle); + } + _IcuCommonLibHandle = IntPtr.Zero; + _IcuI18NLibHandle = IntPtr.Zero; + + Methods = new MethodsContainer(); + ResetIcuVersionInfo(); } - _IcuCommonLibHandle = IntPtr.Zero; - _IcuI18NLibHandle = IntPtr.Zero; + } + + private static void ResetIcuVersionInfo() + { IcuVersion = 0; _IcuPath = null; - Methods = new MethodsContainer(); + +#if !NET40 + var icuInfo = NativeMethodsHelper.GetIcuVersionInfoForNetCoreOrWindows(); + + if (icuInfo.Success) + { + _IcuPath = icuInfo.IcuPath.FullName; + IcuVersion = icuInfo.IcuVersion; + } +#endif } // This method is thread-safe and idempotent From 23eb440d593a3429ab3ef7c6d37e2d10c1b7e4ae Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Thu, 13 Apr 2017 23:37:49 -0700 Subject: [PATCH 27/60] Hack in ability to build nuget package for .NETStandard due to GitVersion not being on .NET Core --- .../icu.net.netstandard.csproj | 37 ++++++++++++++++--- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/source/icu.net.netstandard/icu.net.netstandard.csproj b/source/icu.net.netstandard/icu.net.netstandard.csproj index cdfdd86f..9965fe6e 100644 --- a/source/icu.net.netstandard/icu.net.netstandard.csproj +++ b/source/icu.net.netstandard/icu.net.netstandard.csproj @@ -3,11 +3,12 @@ netstandard1.6 net40;net451;netstandard1.6 - + netstandard ..\icu.net - + $(MSBuildThisFileDirectory)obj\ + $(BaseIntermediateOutputPath)$(Configuration)\ + Icu icu.net - AllRules.ruleset prompt 4 false @@ -20,7 +21,7 @@ - ..\..\output\$(MSBuildProjectName) + ..\..\output\$(Configuration)\$(MSBuildProjectName) true $(IcuSourceDirectory)\icu.net.snk @@ -35,7 +36,7 @@ - + %(RecursiveDir)%(Filename)%(Extension) @@ -43,4 +44,30 @@ + + + + + $(SolutionDir)NuGetBuild/$(PlatformAlias) + + + + + + + + + + + + + + + + This project references {0} that is missing on this computer. Use NuGet Package Restore on .\source\icu.net.sln. + + + \ No newline at end of file From 2ffb1b28c2cf8f937cee9c2230bc80ad765fa8f9 Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Mon, 17 Apr 2017 16:33:39 -0700 Subject: [PATCH 28/60] Restore .NET Core solution in NuGet.targets --- build/NuGet.targets | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build/NuGet.targets b/build/NuGet.targets index 2d6bdcfa..17408ad9 100644 --- a/build/NuGet.targets +++ b/build/NuGet.targets @@ -61,6 +61,9 @@ Condition="Exists('$(SolutionPath)')"/> + + Date: Mon, 17 Apr 2017 20:40:25 -0700 Subject: [PATCH 29/60] Add building of .NET Standard solution to icu-dotnet.proj --- build/icu-dotnet.proj | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/build/icu-dotnet.proj b/build/icu-dotnet.proj index a14dad5b..3581adcf 100644 --- a/build/icu-dotnet.proj +++ b/build/icu-dotnet.proj @@ -9,6 +9,10 @@ $(excludedCategories)KnownMonoIssue; ReleaseMono Release + + true + icu.net.netstandard.sln + $(SolutionDir)/$(SolutionNetCore) @@ -52,6 +56,11 @@ + + From c1915bde4ceaa5ae5f332e55b5873071cdea7147 Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Mon, 17 Apr 2017 21:21:05 -0700 Subject: [PATCH 30/60] Only load GitVersion if running on MSBuild against full .NET Framework --- source/icu.net.netstandard/icu.net.netstandard.csproj | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/source/icu.net.netstandard/icu.net.netstandard.csproj b/source/icu.net.netstandard/icu.net.netstandard.csproj index 9965fe6e..e91070e5 100644 --- a/source/icu.net.netstandard/icu.net.netstandard.csproj +++ b/source/icu.net.netstandard/icu.net.netstandard.csproj @@ -47,7 +47,8 @@ - + $(SolutionDir)NuGetBuild/$(PlatformAlias) @@ -63,8 +64,9 @@ - - + + This project references {0} that is missing on this computer. Use NuGet Package Restore on .\source\icu.net.sln. From 8019e7f31525cd45063ec014f1d76a4f648b6a6b Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Tue, 18 Apr 2017 16:20:18 -0700 Subject: [PATCH 31/60] Add RunNUnitNetCore target to execute NUnit tests on .NET Core if enabled --- build/icu-dotnet.proj | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/build/icu-dotnet.proj b/build/icu-dotnet.proj index 3581adcf..8df60992 100644 --- a/build/icu-dotnet.proj +++ b/build/icu-dotnet.proj @@ -5,6 +5,7 @@ /var/lib/TeamCity/agent icu.net.sln $(RootDir)/source + $(RootDir)/output ICU50 Deprecated;ByHand; $(excludedCategories)KnownMonoIssue; ReleaseMono @@ -65,7 +66,7 @@ @@ -83,11 +84,11 @@ - + - + - + + OutputXmlFile="$(OutputDir)/$(Configuration)/TestResults.xml"/> - + + + + $(SolutionDir)/icu.net.netstandard.testrunner + + + + \ No newline at end of file From bed0114c359eb92a9f74ec88787b061f20365a95 Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Thu, 27 Apr 2017 10:20:46 -0700 Subject: [PATCH 32/60] Add Copyright header to *.cs files --- source/icu.net.netstandard.testrunner/Program.cs | 4 +++- source/icu.net.netstandard/SortKey.cs | 4 +++- source/icu.net.tests/UnicodeSetTests.cs | 6 ++++-- source/icu.net.tests/VersionInfoTests.cs | 4 +++- source/icu.net/Boundary.cs | 4 +++- source/icu.net/Exceptions/BreakException.cs | 4 +++- source/icu.net/Exceptions/IDNAException.cs | 4 +++- source/icu.net/Exceptions/MissingResourceException.cs | 4 +++- source/icu.net/Exceptions/RegexException.cs | 4 +++- source/icu.net/Exceptions/SyntaxErrorException.cs | 4 +++- source/icu.net/Exceptions/TransliteratorParseException.cs | 4 +++- source/icu.net/Exceptions/WarningException.cs | 4 +++- source/icu.net/NativeMethods.NetCore.cs | 4 +++- source/icu.net/Platform.cs | 4 +++- source/icu.net/UnicodeSet.cs | 4 +++- 15 files changed, 46 insertions(+), 16 deletions(-) diff --git a/source/icu.net.netstandard.testrunner/Program.cs b/source/icu.net.netstandard.testrunner/Program.cs index f1098752..c3de8a4f 100644 --- a/source/icu.net.netstandard.testrunner/Program.cs +++ b/source/icu.net.netstandard.testrunner/Program.cs @@ -1,4 +1,6 @@ -using Icu.Tests; +// Copyright (c) 2013 SIL International +// This software is licensed under the MIT license (http://opensource.org/licenses/MIT) +using Icu.Tests; using NUnitLite; using System.Reflection; diff --git a/source/icu.net.netstandard/SortKey.cs b/source/icu.net.netstandard/SortKey.cs index 2a9ff825..d62970e7 100644 --- a/source/icu.net.netstandard/SortKey.cs +++ b/source/icu.net.netstandard/SortKey.cs @@ -1,4 +1,6 @@ -using System; +// Copyright (c) 2013 SIL International +// This software is licensed under the MIT license (http://opensource.org/licenses/MIT) +using System; using System.Globalization; namespace Icu diff --git a/source/icu.net.tests/UnicodeSetTests.cs b/source/icu.net.tests/UnicodeSetTests.cs index 0e967a41..9a4f1142 100644 --- a/source/icu.net.tests/UnicodeSetTests.cs +++ b/source/icu.net.tests/UnicodeSetTests.cs @@ -1,4 +1,6 @@ -using System; +// Copyright (c) 2013 SIL International +// This software is licensed under the MIT license (http://opensource.org/licenses/MIT) +using System; using System.Collections.Generic; using System.Linq; using NUnit.Framework; @@ -49,7 +51,7 @@ public void SinglePatternToChar() IEnumerable unicodeSet = UnicodeSet.ToCharacters(pattern); IEnumerable expected = "A".Split(' '); Assert.That(unicodeSet, Is.EqualTo(expected)); - + } [Test] diff --git a/source/icu.net.tests/VersionInfoTests.cs b/source/icu.net.tests/VersionInfoTests.cs index 63b4c4f4..ac3b3cb6 100644 --- a/source/icu.net.tests/VersionInfoTests.cs +++ b/source/icu.net.tests/VersionInfoTests.cs @@ -1,4 +1,6 @@ -using NUnit.Framework; +// Copyright (c) 2013 SIL International +// This software is licensed under the MIT license (http://opensource.org/licenses/MIT) +using NUnit.Framework; namespace Icu.Tests { diff --git a/source/icu.net/Boundary.cs b/source/icu.net/Boundary.cs index 4ab90bc3..85155ec4 100644 --- a/source/icu.net/Boundary.cs +++ b/source/icu.net/Boundary.cs @@ -1,4 +1,6 @@ -using System; +// Copyright (c) 2013 SIL International +// This software is licensed under the MIT license (http://opensource.org/licenses/MIT) +using System; namespace Icu { diff --git a/source/icu.net/Exceptions/BreakException.cs b/source/icu.net/Exceptions/BreakException.cs index 6f7dbd7a..c891e650 100644 --- a/source/icu.net/Exceptions/BreakException.cs +++ b/source/icu.net/Exceptions/BreakException.cs @@ -1,4 +1,6 @@ -using System; +// Copyright (c) 2013 SIL International +// This software is licensed under the MIT license (http://opensource.org/licenses/MIT) +using System; namespace Icu { diff --git a/source/icu.net/Exceptions/IDNAException.cs b/source/icu.net/Exceptions/IDNAException.cs index 563b10ed..8622e922 100644 --- a/source/icu.net/Exceptions/IDNAException.cs +++ b/source/icu.net/Exceptions/IDNAException.cs @@ -1,4 +1,6 @@ -using System; +// Copyright (c) 2013 SIL International +// This software is licensed under the MIT license (http://opensource.org/licenses/MIT) +using System; namespace Icu { diff --git a/source/icu.net/Exceptions/MissingResourceException.cs b/source/icu.net/Exceptions/MissingResourceException.cs index 487eff78..562c3d43 100644 --- a/source/icu.net/Exceptions/MissingResourceException.cs +++ b/source/icu.net/Exceptions/MissingResourceException.cs @@ -1,4 +1,6 @@ -using System; +// Copyright (c) 2013 SIL International +// This software is licensed under the MIT license (http://opensource.org/licenses/MIT) +using System; namespace Icu { diff --git a/source/icu.net/Exceptions/RegexException.cs b/source/icu.net/Exceptions/RegexException.cs index cad457e5..73198647 100644 --- a/source/icu.net/Exceptions/RegexException.cs +++ b/source/icu.net/Exceptions/RegexException.cs @@ -1,4 +1,6 @@ -using System; +// Copyright (c) 2013 SIL International +// This software is licensed under the MIT license (http://opensource.org/licenses/MIT) +using System; namespace Icu { diff --git a/source/icu.net/Exceptions/SyntaxErrorException.cs b/source/icu.net/Exceptions/SyntaxErrorException.cs index 3811eb7b..84e202fc 100644 --- a/source/icu.net/Exceptions/SyntaxErrorException.cs +++ b/source/icu.net/Exceptions/SyntaxErrorException.cs @@ -1,4 +1,6 @@ -using System; +// Copyright (c) 2013 SIL International +// This software is licensed under the MIT license (http://opensource.org/licenses/MIT) +using System; namespace Icu { diff --git a/source/icu.net/Exceptions/TransliteratorParseException.cs b/source/icu.net/Exceptions/TransliteratorParseException.cs index 8fa17120..064774a1 100644 --- a/source/icu.net/Exceptions/TransliteratorParseException.cs +++ b/source/icu.net/Exceptions/TransliteratorParseException.cs @@ -1,4 +1,6 @@ -using System; +// Copyright (c) 2013 SIL International +// This software is licensed under the MIT license (http://opensource.org/licenses/MIT) +using System; namespace Icu { diff --git a/source/icu.net/Exceptions/WarningException.cs b/source/icu.net/Exceptions/WarningException.cs index 66d086ec..6bc64e61 100644 --- a/source/icu.net/Exceptions/WarningException.cs +++ b/source/icu.net/Exceptions/WarningException.cs @@ -1,4 +1,6 @@ -using System; +// Copyright (c) 2013 SIL International +// This software is licensed under the MIT license (http://opensource.org/licenses/MIT) +using System; namespace Icu { diff --git a/source/icu.net/NativeMethods.NetCore.cs b/source/icu.net/NativeMethods.NetCore.cs index bdcb1794..c741a4aa 100644 --- a/source/icu.net/NativeMethods.NetCore.cs +++ b/source/icu.net/NativeMethods.NetCore.cs @@ -1,4 +1,6 @@ -using System; +// Copyright (c) 2013 SIL International +// This software is licensed under the MIT license (http://opensource.org/licenses/MIT) +using System; using System.Diagnostics; using System.IO; using System.Linq; diff --git a/source/icu.net/Platform.cs b/source/icu.net/Platform.cs index 160765d1..4cd94c75 100644 --- a/source/icu.net/Platform.cs +++ b/source/icu.net/Platform.cs @@ -1,4 +1,6 @@ -using System; +// Copyright (c) 2013 SIL International +// This software is licensed under the MIT license (http://opensource.org/licenses/MIT) +using System; using System.Runtime.InteropServices; namespace Icu diff --git a/source/icu.net/UnicodeSet.cs b/source/icu.net/UnicodeSet.cs index 031480b6..e1ead498 100644 --- a/source/icu.net/UnicodeSet.cs +++ b/source/icu.net/UnicodeSet.cs @@ -1,4 +1,6 @@ -using System; +// Copyright (c) 2013 SIL International +// This software is licensed under the MIT license (http://opensource.org/licenses/MIT) +using System; using System.Collections.Generic; using System.Globalization; using System.Linq; From 284187ddd07d284518293193303ef60f22c32e5a Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Thu, 27 Apr 2017 11:14:49 -0700 Subject: [PATCH 33/60] Add NuGet package properties to csproj to generate correct package --- source/icu.net.netstandard/icu.net.netstandard.csproj | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/source/icu.net.netstandard/icu.net.netstandard.csproj b/source/icu.net.netstandard/icu.net.netstandard.csproj index e91070e5..3a5db6f1 100644 --- a/source/icu.net.netstandard/icu.net.netstandard.csproj +++ b/source/icu.net.netstandard/icu.net.netstandard.csproj @@ -47,6 +47,16 @@ + + SIL International + Copyright © SIL International 2007-2017 + https://github.com/sillsdev/icu-dotnet/blob/master/LICENSE + https://github.com/sillsdev/icu-dotnet + icu.net icu4c + icu.net is a C# Wrapper around ICU4C. To use this, you need to install the unmanaged binaries to use this library. (e.g. Icu4c.Win.*.nupkg on Windows or official ICU package that comes with the system on Linux). + + This version of icu.net works with (more or less) any version of ICU4C. + From 9c813703054bfaf1d367d00447421d1d3bc91d2b Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Thu, 27 Apr 2017 14:16:02 -0700 Subject: [PATCH 34/60] Make LoadLibraryFlags private --- source/icu.net/NativeMethods.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/icu.net/NativeMethods.cs b/source/icu.net/NativeMethods.cs index 4a6aeea0..39c1a89c 100644 --- a/source/icu.net/NativeMethods.cs +++ b/source/icu.net/NativeMethods.cs @@ -77,7 +77,7 @@ static NativeMethods() private static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName); [Flags] - internal enum LoadLibraryFlags : uint + private enum LoadLibraryFlags : uint { NONE = 0x00000000, DONT_RESOLVE_DLL_REFERENCES = 0x00000001, From 6e0b609f5e95becff6925e046f70b45e4bebf35e Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Thu, 27 Apr 2017 14:22:35 -0700 Subject: [PATCH 35/60] GetLastWin32Error after each native call to get correct error code --- source/icu.net/NativeMethods.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/source/icu.net/NativeMethods.cs b/source/icu.net/NativeMethods.cs index 39c1a89c..906dd024 100644 --- a/source/icu.net/NativeMethods.cs +++ b/source/icu.net/NativeMethods.cs @@ -242,8 +242,11 @@ private static IntPtr GetIcuLibHandle(string basename, int icuVersion) { if (icuVersion < minIcuVersion) return IntPtr.Zero; + IntPtr handle; string libPath; + int lastError = 0; + if (IsWindows) { var libName = $"{basename}{icuVersion}.dll"; @@ -256,7 +259,7 @@ private static IntPtr GetIcuLibHandle(string basename, int icuVersion) loadLibraryFlags |= LoadLibraryFlags.LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LoadLibraryFlags.LOAD_LIBRARY_SEARCH_DEFAULT_DIRS; handle = LoadLibraryEx(libPath, IntPtr.Zero, loadLibraryFlags); - var lastError = Marshal.GetLastWin32Error(); + lastError = Marshal.GetLastWin32Error(); if (handle == IntPtr.Zero && lastError != 0) { @@ -268,13 +271,15 @@ private static IntPtr GetIcuLibHandle(string basename, int icuVersion) { var libName = $"lib{basename}.so.{icuVersion}"; libPath = string.IsNullOrEmpty(_IcuPath) ? libName : Path.Combine(_IcuPath, libName); + handle = dlopen(libPath, RTLD_NOW); + lastError = Marshal.GetLastWin32Error(); } if (handle == IntPtr.Zero) { Trace.TraceWarning("{0} of {1} failed with error {2}", - IsWindows ? "LoadLibrary" : "dlopen", - libPath, Marshal.GetLastWin32Error()); + IsWindows ? "LoadLibraryEx" : "dlopen", + libPath, lastError); return GetIcuLibHandle(basename, icuVersion - 1); } From 83745cd5646beb960bfc18a471be1d2716ba0346 Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Thu, 27 Apr 2017 14:31:33 -0700 Subject: [PATCH 36/60] Split IcuVersionInfo into its own file --- source/icu.net/IcuVersionInfo.cs | 33 +++++++++++++++++++++++++ source/icu.net/NativeMethods.NetCore.cs | 26 ------------------- 2 files changed, 33 insertions(+), 26 deletions(-) create mode 100644 source/icu.net/IcuVersionInfo.cs diff --git a/source/icu.net/IcuVersionInfo.cs b/source/icu.net/IcuVersionInfo.cs new file mode 100644 index 00000000..88b97514 --- /dev/null +++ b/source/icu.net/IcuVersionInfo.cs @@ -0,0 +1,33 @@ +// Copyright (c) 2013 SIL International +// This software is licensed under the MIT license (http://opensource.org/licenses/MIT) +using System; +using System.IO; + +namespace Icu +{ + /// + /// Returns the result of trying to resolve the icu binary paths. + /// + internal class IcuVersionInfo + { + public IcuVersionInfo() + { + Success = false; + } + + public IcuVersionInfo(DirectoryInfo icuPath, int icuVersion) + { + if (icuVersion <= 0) + throw new ArgumentOutOfRangeException(nameof(icuVersion), "IcuVersion should be greater than 0"); + + IcuPath = icuPath; + IcuVersion = icuVersion; + Success = true; + } + + public bool Success { get; } + + public readonly DirectoryInfo IcuPath; + public readonly int IcuVersion; + } +} \ No newline at end of file diff --git a/source/icu.net/NativeMethods.NetCore.cs b/source/icu.net/NativeMethods.NetCore.cs index c741a4aa..8432d653 100644 --- a/source/icu.net/NativeMethods.NetCore.cs +++ b/source/icu.net/NativeMethods.NetCore.cs @@ -305,31 +305,5 @@ private static string GetDefaultPackageDirectory(OperatingSystemType osPlatform) } return Path.Combine(basePath, ".nuget", "packages"); } - - /// - /// Returns the result of trying to resolve the icu binary paths. - /// - internal class IcuVersionInfo - { - public IcuVersionInfo() - { - Success = false; - } - - public IcuVersionInfo(DirectoryInfo icuPath, int icuVersion) - { - if (icuVersion <= 0) - throw new ArgumentOutOfRangeException(nameof(icuVersion), "IcuVersion should be greater than 0"); - - IcuPath = icuPath; - IcuVersion = icuVersion; - Success = true; - } - - public bool Success { get; } - - public readonly DirectoryInfo IcuPath; - public readonly int IcuVersion; - } } } From 52ecfc73ed04babcd0814c550f126d973ad93ae3 Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Thu, 27 Apr 2017 14:33:49 -0700 Subject: [PATCH 37/60] Collator: Fix whitespace back to tabs --- source/icu.net/Collation/Collator.cs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/source/icu.net/Collation/Collator.cs b/source/icu.net/Collation/Collator.cs index 8841646c..b1554572 100644 --- a/source/icu.net/Collation/Collator.cs +++ b/source/icu.net/Collation/Collator.cs @@ -31,7 +31,7 @@ public abstract class Collator : IComparer, IDisposable public abstract NormalizationMode NormalizationMode{ get; set; } /// - /// Gets or sets the FrenchCollation. Attribute for direction of + /// Gets or sets the FrenchCollation. Attribute for directionCollof /// secondary weights - used in Canadian French. /// public abstract FrenchCollation FrenchCollation{ get; set; } @@ -192,21 +192,21 @@ static public SortKey CreateSortKey(string originalString, byte[] keyData, int k throw new ArgumentOutOfRangeException("keyDataLength"); } - CompareOptions options = CompareOptions.None; + CompareOptions options = CompareOptions.None; #if NETSTANDARD1_6 - SortKey sortKey = new SortKey(CultureInfo.InvariantCulture.Name, originalString, options, keyData); + SortKey sortKey = new SortKey(CultureInfo.InvariantCulture.Name, originalString, options, keyData); #else - SortKey sortKey = CultureInfo.InvariantCulture.CompareInfo.GetSortKey(string.Empty, options); - SetInternalOriginalStringField(sortKey, originalString); + SortKey sortKey = CultureInfo.InvariantCulture.CompareInfo.GetSortKey(string.Empty, options); + SetInternalOriginalStringField(sortKey, originalString); SetInternalKeyDataField(sortKey, keyData, keyDataLength); #endif - return sortKey; + return sortKey; } #if !NETSTANDARD1_6 - private static void SetInternalKeyDataField(SortKey sortKey, byte[] keyData, int keyDataLength) + private static void SetInternalKeyDataField(SortKey sortKey, byte[] keyData, int keyDataLength) { byte[] keyDataCopy = new byte[keyDataLength]; Array.Copy(keyData, keyDataCopy, keyDataLength); @@ -258,17 +258,17 @@ private static void SetInternalFieldForPublicProperty( fieldInfo.SetValue(instance, value); } - + private static bool IsRunningOnMono() { return Type.GetType("Mono.Runtime") != null; } #endif - /// - /// Simple class to allow passing collation error info back to the caller of CheckRules. - /// - public class CollationRuleErrorInfo + /// + /// Simple class to allow passing collation error info back to the caller of CheckRules. + /// + public class CollationRuleErrorInfo { /// Line number (1-based) containing the error public int Line; From cef03ed3c58e65f6151862a00e2b364baf891294 Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Mon, 24 Apr 2017 10:26:20 -0700 Subject: [PATCH 38/60] Fix casing for NuGet.targets for building on Linux --- build/NuGet.targets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/NuGet.targets b/build/NuGet.targets index 17408ad9..6ced0a86 100644 --- a/build/NuGet.targets +++ b/build/NuGet.targets @@ -62,7 +62,7 @@ - From 65f6efbf8272607a60a1d5322fe79b36e6af90cd Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Mon, 24 Apr 2017 10:57:16 -0700 Subject: [PATCH 39/60] Use DotNet CLI when building .NET Core projects. Fixing configuration value for building on Linux --- build/NuGet.targets | 4 ++-- build/icu-dotnet.proj | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/build/NuGet.targets b/build/NuGet.targets index 6ced0a86..1b321569 100644 --- a/build/NuGet.targets +++ b/build/NuGet.targets @@ -62,8 +62,8 @@ - + ReleaseMono Release + dotnet true icu.net.netstandard.sln $(SolutionDir)/$(SolutionNetCore) @@ -54,13 +55,14 @@ + + $(Configuration.Replace('Mono','')) + - @@ -116,7 +118,7 @@ $(SolutionDir)/icu.net.netstandard.testrunner - \ No newline at end of file From 1c25e738e778882f3743d524ba7b746db08229dc Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Thu, 27 Apr 2017 15:08:47 -0700 Subject: [PATCH 40/60] Assembly signing does not work on Linux in .NET Core msbuild targets --- source/icu.net.netstandard/icu.net.netstandard.csproj | 4 +++- source/icu.net/icu.net.csproj | 7 +++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/source/icu.net.netstandard/icu.net.netstandard.csproj b/source/icu.net.netstandard/icu.net.netstandard.csproj index 3a5db6f1..11485e42 100644 --- a/source/icu.net.netstandard/icu.net.netstandard.csproj +++ b/source/icu.net.netstandard/icu.net.netstandard.csproj @@ -20,7 +20,9 @@ - + + ..\..\output\$(Configuration)\$(MSBuildProjectName) true $(IcuSourceDirectory)\icu.net.snk diff --git a/source/icu.net/icu.net.csproj b/source/icu.net/icu.net.csproj index d2b75bdf..88507e97 100644 --- a/source/icu.net/icu.net.csproj +++ b/source/icu.net/icu.net.csproj @@ -119,9 +119,12 @@ ..\..\lib\icu ..\..\output\$(Configuration) $(DefineConstants);FEATURE_ICLONEABLE;NET40 - true - + + + + true icu.net.snk From 889e307471323dbdfdbb39a657453d72fac65dfd Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Thu, 27 Apr 2017 17:10:03 -0700 Subject: [PATCH 41/60] Unify common msbuild properties: IsOnWindows and IsOnTeamCity --- build/icu-dotnet.proj | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/build/icu-dotnet.proj b/build/icu-dotnet.proj index 54c8199a..7399906e 100644 --- a/build/icu-dotnet.proj +++ b/build/icu-dotnet.proj @@ -1,15 +1,18 @@ - $(MSBuildProjectDirectory)\.. - $(teamcity_build_checkoutDir) - /var/lib/TeamCity/agent + true + true + + $(MSBuildProjectDirectory)\.. + $(teamcity_build_checkoutDir) + /var/lib/TeamCity/agent icu.net.sln $(RootDir)/source $(RootDir)/output ICU50 Deprecated;ByHand; - $(excludedCategories)KnownMonoIssue; - ReleaseMono - Release + $(excludedCategories)KnownMonoIssue; + ReleaseMono + Release dotnet true @@ -23,10 +26,10 @@ + Condition=" '$(IsOnTeamCity)'=='true' And '$(IsOnWindows)'=='true'"/> + Condition=" '$(IsOnTeamCity)'=='true' And '$(IsOnWindows)'!='true'"/> @@ -61,9 +64,15 @@ + + + + + /t:Build;Pack /p:Configuration=$(ConfigurationNetCore) "$(SolutionNetCorePath)" + - + @@ -75,9 +84,9 @@ - - @@ -88,7 +97,7 @@ - + @@ -99,7 +108,7 @@ NUnitVersion="NUnit-2.6.4" /> - + From b69181a9f230c7c9d60cd19951d2838e865cd8ec Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Thu, 27 Apr 2017 20:41:42 -0700 Subject: [PATCH 42/60] Split Compile targets into 3 targets. Fix compilation calls for Linux and Windows --- build/icu-dotnet.proj | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/build/icu-dotnet.proj b/build/icu-dotnet.proj index 7399906e..ceba0928 100644 --- a/build/icu-dotnet.proj +++ b/build/icu-dotnet.proj @@ -16,8 +16,7 @@ dotnet true - icu.net.netstandard.sln - $(SolutionDir)/$(SolutionNetCore) + $(SolutionDir)/icu.net.netstandard.sln @@ -57,22 +56,43 @@ - - - $(Configuration.Replace('Mono','')) - + + + + + + - /t:Build;Pack /p:Configuration=$(ConfigurationNetCore) "$(SolutionNetCorePath)" + $(Configuration.Replace('Mono','')) + Configuration=$(ConfigurationNetCore) + Build;Pack - + + + + From 823f0b550af1e5146a814c2bc0b4b935680fa2cb Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Fri, 28 Apr 2017 11:36:25 -0700 Subject: [PATCH 43/60] Fix NUnit on .NET Core to run the specified configuration --- build/icu-dotnet.proj | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/build/icu-dotnet.proj b/build/icu-dotnet.proj index ceba0928..e6720c6d 100644 --- a/build/icu-dotnet.proj +++ b/build/icu-dotnet.proj @@ -11,8 +11,10 @@ $(RootDir)/output ICU50 Deprecated;ByHand; $(excludedCategories)KnownMonoIssue; + ReleaseMono Release + $(Configuration.Replace('Mono','')) dotnet true @@ -77,7 +79,6 @@ - $(Configuration.Replace('Mono','')) Configuration=$(ConfigurationNetCore) Build;Pack @@ -97,18 +98,16 @@ + Include="$(OutputDir)/$(Configuration)/**/*;$(RootDir)/**/obj/**/*;$(RootDir)/**/bin/**/*;$(RootDir)/**/test-results/**/*" + Exclude="$(RootDir)/.hg/**/*;$(RootDir)/.git/**/*" /> - + @@ -147,7 +146,7 @@ $(SolutionDir)/icu.net.netstandard.testrunner - \ No newline at end of file From bd0d74f973fd0d16c5813a9233e657d6445b24a1 Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Fri, 28 Apr 2017 11:38:06 -0700 Subject: [PATCH 44/60] Move ExistingObjectFiles into target so it can be evaluated at Target runtime --- build/icu-dotnet.proj | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/build/icu-dotnet.proj b/build/icu-dotnet.proj index e6720c6d..dd93e9e3 100644 --- a/build/icu-dotnet.proj +++ b/build/icu-dotnet.proj @@ -96,18 +96,14 @@ Condition="'$(IsOnWindows)' == 'true'" /> - - - - + + + + - From 78a39d6e0142e90dcc1c402339792ca760cd420d Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Fri, 28 Apr 2017 15:31:54 -0700 Subject: [PATCH 45/60] Consolidate all .NET Core related build properties together --- build/icu-dotnet.proj | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/build/icu-dotnet.proj b/build/icu-dotnet.proj index dd93e9e3..f9e4dc5a 100644 --- a/build/icu-dotnet.proj +++ b/build/icu-dotnet.proj @@ -14,11 +14,16 @@ ReleaseMono Release - $(Configuration.Replace('Mono','')) - dotnet true - $(SolutionDir)/icu.net.netstandard.sln + + + + + $(Configuration.Replace('Mono','')) + dotnet + $(HOME)/.dotnet/sdk/1.0.3 + $(SolutionDir)/icu.net.netstandard.sln From 22ff79ddeab8e2d7d1ed505e83e7f9438ec0b275 Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Fri, 28 Apr 2017 16:01:19 -0700 Subject: [PATCH 46/60] (FIXUP) Do nto split .net core compile into two different execs --- build/icu-dotnet.proj | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/build/icu-dotnet.proj b/build/icu-dotnet.proj index f9e4dc5a..22b7a3a1 100644 --- a/build/icu-dotnet.proj +++ b/build/icu-dotnet.proj @@ -83,22 +83,9 @@ Creates NuGet package that works against all three frameworks. --> - - Configuration=$(ConfigurationNetCore) - Build;Pack - - - - - + Targets="Build;Pack" + Properties="Configuration=$(ConfigurationNetCore)" /> From 97f75fd5ddf4dfa905c5c13d46d73ade12e03ff6 Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Mon, 24 Jul 2017 16:24:58 -0700 Subject: [PATCH 47/60] Update to newest version of GitVersionTask --- .../icu.net.netstandard.csproj | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/source/icu.net.netstandard/icu.net.netstandard.csproj b/source/icu.net.netstandard/icu.net.netstandard.csproj index 11485e42..54e1cae5 100644 --- a/source/icu.net.netstandard/icu.net.netstandard.csproj +++ b/source/icu.net.netstandard/icu.net.netstandard.csproj @@ -1,7 +1,6 @@  - netstandard1.6 net40;net451;netstandard1.6 netstandard ..\icu.net @@ -28,7 +27,7 @@ $(IcuSourceDirectory)\icu.net.snk - + @@ -37,13 +36,17 @@ + + + + %(RecursiveDir)%(Filename)%(Extension) - + @@ -73,15 +76,4 @@ - - - - - - This project references {0} that is missing on this computer. Use NuGet Package Restore on .\source\icu.net.sln. - - - \ No newline at end of file From 9fe6642d79634def0dcbc8bf985206ebc4b5518e Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Mon, 24 Jul 2017 16:25:17 -0700 Subject: [PATCH 48/60] Fix .NET Core test runs by not invoking build again --- build/icu-dotnet.proj | 1 - source/icu.net.netstandard/icu.net.netstandard.csproj | 7 +++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/build/icu-dotnet.proj b/build/icu-dotnet.proj index 22b7a3a1..e4b3ff60 100644 --- a/build/icu-dotnet.proj +++ b/build/icu-dotnet.proj @@ -22,7 +22,6 @@ $(Configuration.Replace('Mono','')) dotnet - $(HOME)/.dotnet/sdk/1.0.3 $(SolutionDir)/icu.net.netstandard.sln diff --git a/source/icu.net.netstandard/icu.net.netstandard.csproj b/source/icu.net.netstandard/icu.net.netstandard.csproj index 54e1cae5..1c1f8d29 100644 --- a/source/icu.net.netstandard/icu.net.netstandard.csproj +++ b/source/icu.net.netstandard/icu.net.netstandard.csproj @@ -62,6 +62,13 @@ This version of icu.net works with (more or less) any version of ICU4C. + + + + true + + From 4fd4e14e1c8769df11f66d30b10a5b41063ce096 Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Tue, 25 Jul 2017 14:09:03 -0700 Subject: [PATCH 49/60] Add CreateNuGetPackage target that creates a NuGet package after all the TargetFrameworks have been built. (If I do it after Build, it'll try to build the package 3 times.) --- build/icu-dotnet.proj | 2 +- .../icu.net.netstandard.testrunner.csproj | 2 + .../icu.net.netstandard.tests.csproj | 2 + .../NuGetAssets/icu.net.nuspec | 30 +++++++++ .../icu.net.netstandard.csproj | 63 +++++++++++-------- 5 files changed, 73 insertions(+), 26 deletions(-) create mode 100644 source/icu.net.netstandard/NuGetAssets/icu.net.nuspec diff --git a/build/icu-dotnet.proj b/build/icu-dotnet.proj index e4b3ff60..55b3aeba 100644 --- a/build/icu-dotnet.proj +++ b/build/icu-dotnet.proj @@ -83,7 +83,7 @@ diff --git a/source/icu.net.netstandard.testrunner/icu.net.netstandard.testrunner.csproj b/source/icu.net.netstandard.testrunner/icu.net.netstandard.testrunner.csproj index 5f0271a4..397f3b84 100644 --- a/source/icu.net.netstandard.testrunner/icu.net.netstandard.testrunner.csproj +++ b/source/icu.net.netstandard.testrunner/icu.net.netstandard.testrunner.csproj @@ -13,4 +13,6 @@ + + \ No newline at end of file diff --git a/source/icu.net.netstandard.tests/icu.net.netstandard.tests.csproj b/source/icu.net.netstandard.tests/icu.net.netstandard.tests.csproj index 761c6375..ad048220 100644 --- a/source/icu.net.netstandard.tests/icu.net.netstandard.tests.csproj +++ b/source/icu.net.netstandard.tests/icu.net.netstandard.tests.csproj @@ -24,4 +24,6 @@ + + diff --git a/source/icu.net.netstandard/NuGetAssets/icu.net.nuspec b/source/icu.net.netstandard/NuGetAssets/icu.net.nuspec new file mode 100644 index 00000000..40250dad --- /dev/null +++ b/source/icu.net.netstandard/NuGetAssets/icu.net.nuspec @@ -0,0 +1,30 @@ + + + + $id$ + $version$ + SIL International + https://github.com/sillsdev/icu-dotnet/blob/master/LICENSE + https://github.com/sillsdev/icu-dotnet + false + icu.net is a C# Wrapper around ICU4C + +This version of icu.net works with (more or less) any version of ICU4C. + +NOTE: this package contains the managed wrapper part of icu.net. You'll also have to have the unmanaged binaries of ICU installed. On Linux it is recommended to install the official ICU package that comes with the system. On Windows you can install one of the binary nuget packages, e.g. Icu4c.Win. + en-US + + + + + + + + + + + + + + + diff --git a/source/icu.net.netstandard/icu.net.netstandard.csproj b/source/icu.net.netstandard/icu.net.netstandard.csproj index 1c1f8d29..76a61b21 100644 --- a/source/icu.net.netstandard/icu.net.netstandard.csproj +++ b/source/icu.net.netstandard/icu.net.netstandard.csproj @@ -6,6 +6,7 @@ ..\icu.net $(MSBuildThisFileDirectory)obj\ $(BaseIntermediateOutputPath)$(Configuration)\ + ..\..\output\$(Configuration)\$(MSBuildProjectName) Icu icu.net prompt @@ -18,11 +19,9 @@ $(DefineConstants);FEATURE_ICLONEABLE - - ..\..\output\$(Configuration)\$(MSBuildProjectName) true $(IcuSourceDirectory)\icu.net.snk @@ -37,7 +36,12 @@ - + + all + + + all + @@ -50,37 +54,46 @@ - - - SIL International - Copyright © SIL International 2007-2017 - https://github.com/sillsdev/icu-dotnet/blob/master/LICENSE - https://github.com/sillsdev/icu-dotnet - icu.net icu4c - icu.net is a C# Wrapper around ICU4C. To use this, you need to install the unmanaged binaries to use this library. (e.g. Icu4c.Win.*.nupkg on Windows or official ICU package that comes with the system on Linux). - - This version of icu.net works with (more or less) any version of ICU4C. + + + $(NuGetPackageRoot)pepitapackage\1.21.6 + - + true - + $(SolutionDir)NuGetBuild/$(PlatformAlias) + $(ProjectDir)NuGetAssets + $(NuGetBuildFolder)/lib/net40/icu.net.dll + $([System.IO.Path]::GetFullPath('$(OutputPath)')) + + + + + + + + + + + + - - - - - - - + + + + \ No newline at end of file From 9c443a7f725ba0464db491308f874c6400a1d551 Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Tue, 25 Jul 2017 15:07:35 -0700 Subject: [PATCH 50/60] Remove UpdateAssemblyInfo=false and individually not generate items already specified in AssemblyInfo.cs --- .../icu.net.netstandard/icu.net.netstandard.csproj | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/source/icu.net.netstandard/icu.net.netstandard.csproj b/source/icu.net.netstandard/icu.net.netstandard.csproj index 76a61b21..2197acb2 100644 --- a/source/icu.net.netstandard/icu.net.netstandard.csproj +++ b/source/icu.net.netstandard/icu.net.netstandard.csproj @@ -11,7 +11,13 @@ icu.net prompt 4 - false + + false + false + false + false + false + false @@ -75,7 +81,6 @@ $(SolutionDir)NuGetBuild/$(PlatformAlias) $(ProjectDir)NuGetAssets $(NuGetBuildFolder)/lib/net40/icu.net.dll - $([System.IO.Path]::GetFullPath('$(OutputPath)')) @@ -87,13 +92,11 @@ - - - + \ No newline at end of file From 990f16074a16227bf36d765b4e3e387c50568c2c Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Tue, 25 Jul 2017 15:20:43 -0700 Subject: [PATCH 51/60] Change xbuild to msbuild because it is deprecated in latest releases of Mono --- Jenkinsfile | 4 ++-- build/TestBuild.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 93ae1d6c..b6a94a5c 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -91,8 +91,8 @@ MONO_GAC_PREFIX="$MONO_PREFIX:/usr" export LD_LIBRARY_PATH PKG_CONFIG_PATH MONO_GAC_PREFIX -xbuild /t:Compile /property:Configuration=Release build/icu-dotnet.proj -xbuild /t:TestOnly /property:Configuration=Release build/icu-dotnet.proj +msbuild /t:Compile /property:Configuration=Release build/icu-dotnet.proj +msbuild /t:TestOnly /property:Configuration=Release build/icu-dotnet.proj ''' } diff --git a/build/TestBuild.sh b/build/TestBuild.sh index a06630fd..ec4b504a 100755 --- a/build/TestBuild.sh +++ b/build/TestBuild.sh @@ -5,4 +5,4 @@ # (version 53 released April 2014, version 54 scheduled for October 2014) ICUVER=$(icu-config --version|tr -d .|cut -c -2) cd "$(dirname "$0")" -xbuild /t:${2:-Test} /p:icu_ver=$ICUVER /p:Configuration=${1:-DebugMono} /p:Platform="Any CPU" /p:BUILD_NUMBER="0.1.0.abcd" icu-dotnet.proj +msbuild /t:${2:-Test} /p:icu_ver=$ICUVER /p:Configuration=${1:-DebugMono} /p:Platform="Any CPU" /p:BUILD_NUMBER="0.1.0.abcd" icu-dotnet.proj From 3608738d92eebc3fe9e52dde2d672b10e591a0e3 Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Sat, 6 Jan 2018 12:13:49 -0800 Subject: [PATCH 52/60] Add Platform abstraction --- source/icu.net/NativeMethods.cs | 5 +++-- source/icu.net/Platform.cs | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/source/icu.net/NativeMethods.cs b/source/icu.net/NativeMethods.cs index 906dd024..5779133e 100644 --- a/source/icu.net/NativeMethods.cs +++ b/source/icu.net/NativeMethods.cs @@ -5,6 +5,7 @@ using System.Diagnostics; using System.IO; using System.Linq; +using System.Reflection; using System.Runtime.InteropServices; using Icu.Collation; @@ -100,7 +101,7 @@ private enum LoadLibraryFlags : uint private static IntPtr _IcuCommonLibHandle; private static IntPtr _IcuI18NLibHandle; - private static bool IsWindows => Environment.OSVersion.Platform != PlatformID.Unix; + private static bool IsWindows => Platform.OperatingSystem == OperatingSystemType.Windows; private static IntPtr IcuCommonLibHandle { @@ -139,7 +140,7 @@ internal static string DirectoryOfThisAssembly } } - private static bool IsRunning64Bit => Environment.Is64BitProcess; + private static bool IsRunning64Bit => Platform.ProcessArchitecture == Platform.x64; private static bool IsInitialized { get; set; } diff --git a/source/icu.net/Platform.cs b/source/icu.net/Platform.cs index 4cd94c75..917d61b0 100644 --- a/source/icu.net/Platform.cs +++ b/source/icu.net/Platform.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2013 SIL International +// Copyright (c) 2013 SIL International // This software is licensed under the MIT license (http://opensource.org/licenses/MIT) using System; using System.Runtime.InteropServices; @@ -24,11 +24,12 @@ internal enum OperatingSystemType /// internal static class Platform { + public const string x64 = nameof(x64); + public const string x86 = nameof(x86); + public static string ProcessArchitecture { get { - const string x86 = "x86"; - const string x64 = "x64"; #if NETSTANDARD1_6 // Workaround described here since the API does not exist: From 35bfebb2298ad4f7feefa89bd5cb5ceca782782c Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Sat, 6 Jan 2018 12:34:01 -0800 Subject: [PATCH 53/60] Updating NuGet packages --- .../icu.net.netstandard.testrunner.csproj | 2 +- .../icu.net.netstandard.tests.csproj | 9 +++++---- source/icu.net.netstandard/icu.net.netstandard.csproj | 10 ++++------ 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/source/icu.net.netstandard.testrunner/icu.net.netstandard.testrunner.csproj b/source/icu.net.netstandard.testrunner/icu.net.netstandard.testrunner.csproj index 397f3b84..24fe712e 100644 --- a/source/icu.net.netstandard.testrunner/icu.net.netstandard.testrunner.csproj +++ b/source/icu.net.netstandard.testrunner/icu.net.netstandard.testrunner.csproj @@ -6,7 +6,7 @@ - + diff --git a/source/icu.net.netstandard.tests/icu.net.netstandard.tests.csproj b/source/icu.net.netstandard.tests/icu.net.netstandard.tests.csproj index ad048220..a37306b6 100644 --- a/source/icu.net.netstandard.tests/icu.net.netstandard.tests.csproj +++ b/source/icu.net.netstandard.tests/icu.net.netstandard.tests.csproj @@ -7,10 +7,11 @@ - - - - + + + + + diff --git a/source/icu.net.netstandard/icu.net.netstandard.csproj b/source/icu.net.netstandard/icu.net.netstandard.csproj index 2197acb2..49683876 100644 --- a/source/icu.net.netstandard/icu.net.netstandard.csproj +++ b/source/icu.net.netstandard/icu.net.netstandard.csproj @@ -37,7 +37,7 @@ - + @@ -66,8 +66,7 @@ $(NuGetPackageRoot)pepitapackage\1.21.6 - + @@ -194,7 +193,6 @@ - - $(DefineConstants);NET40 + $(DefineConstants);NET40;NUNIT2 ..\..\output\$(Configuration) From 7d269ca359c03293cf6bf634f8dd51e3882e64ab Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Sat, 6 Jan 2018 21:04:27 -0800 Subject: [PATCH 59/60] Updating dependencies --- source/icu.net.netstandard/NuGetAssets/icu.net.nuspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/icu.net.netstandard/NuGetAssets/icu.net.nuspec b/source/icu.net.netstandard/NuGetAssets/icu.net.nuspec index 40250dad..d60aa7f3 100644 --- a/source/icu.net.netstandard/NuGetAssets/icu.net.nuspec +++ b/source/icu.net.netstandard/NuGetAssets/icu.net.nuspec @@ -16,13 +16,13 @@ NOTE: this package contains the managed wrapper part of icu.net. You'll also hav - + + - From 5c8806a8688fe26b1e974d7146dfbb9e40f3d916 Mon Sep 17 00:00:00 2001 From: Connie Yau Date: Sat, 6 Jan 2018 22:22:52 -0800 Subject: [PATCH 60/60] Checking for *{processorarch}* to locate native libraries --- source/icu.net/NativeMethods.NetCore.cs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/source/icu.net/NativeMethods.NetCore.cs b/source/icu.net/NativeMethods.NetCore.cs index 8432d653..9d37bf64 100644 --- a/source/icu.net/NativeMethods.NetCore.cs +++ b/source/icu.net/NativeMethods.NetCore.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2013 SIL International +// Copyright (c) 2013 SIL International // This software is licensed under the MIT license (http://opensource.org/licenses/MIT) using System; using System.Diagnostics; @@ -120,12 +120,18 @@ private static bool TryGetPathFromAssemblyDirectory() return true; } - // 2. Check in {assemblyDirectory}/lib/{architecture}/ - var libPath = new DirectoryInfo(Path.Combine(assemblyDirectory.FullName, "lib", Platform.ProcessArchitecture)); - if (TryGetIcuVersionNumber(libPath, out version)) + // 2. Check in {assemblyDirectory}/lib/*{architecture}*/ + var libDirectory = Path.Combine(assemblyDirectory.FullName, "lib"); + var candidateDirectories = Directory.EnumerateDirectories(libDirectory, $"*{Platform.ProcessArchitecture}*") + .Select(x => new DirectoryInfo(x)); + + foreach (var directory in candidateDirectories) { - IcuVersion = new IcuVersionInfo(libPath, version); - return true; + if (TryGetIcuVersionNumber(directory, out version)) + { + IcuVersion = new IcuVersionInfo(directory, version); + return true; + } } string[] nativeAssetPaths = null;