├── .gitignore
├── CoreFramework
├── Characters.cs
├── ISlug.cs
├── SlugGenerator.CoreFramework.csproj
├── SlugGenerator.cs
└── Unidecoder.cs
├── Framework
├── Characters.cs
├── ISlug.cs
├── Properties
│ └── AssemblyInfo.cs
├── SlugGenerator.Framework.csproj
├── SlugGenerator.cs
└── Unidecoder.cs
├── LICENSE
├── README.md
├── SlugGenerator.Tests
├── Properties
│ └── AssemblyInfo.cs
├── Slug.cs
├── SlugGenerator.Tests.csproj
├── SlugGeneratorTests.cs
├── app.config
└── packages.config
└── SlugGenerator.sln
/.gitignore:
--------------------------------------------------------------------------------
1 | # Build Folders (you can keep bin if you'd like, to store dlls and pdbs)
2 | [Bb]in/
3 | [Oo]bj/
4 |
5 | # mstest test results
6 | TestResults
7 |
8 | ## Ignore Visual Studio temporary files, build results, and
9 | ## files generated by popular Visual Studio add-ons.
10 |
11 | # User-specific files
12 | *.suo
13 | *.user
14 | *.vs
15 | *.sln.docstates
16 |
17 | # Build results
18 | [Dd]ebug/
19 | [Rr]elease/
20 | x64/
21 | *_i.c
22 | *_p.c
23 | *.ilk
24 | *.meta
25 | *.obj
26 | *.pch
27 | *.pdb
28 | *.pgc
29 | *.pgd
30 | *.rsp
31 | *.sbr
32 | *.tlb
33 | *.tli
34 | *.tlh
35 | *.tmp
36 | *.log
37 | *.vspscc
38 | *.vssscc
39 | .builds
40 |
41 | # Visual C++ cache files
42 | ipch/
43 | *.aps
44 | *.ncb
45 | *.opensdf
46 | *.sdf
47 |
48 | # Visual Studio profiler
49 | *.psess
50 | *.vsp
51 | *.vspx
52 |
53 | # Guidance Automation Toolkit
54 | *.gpState
55 |
56 | # ReSharper is a .NET coding add-in
57 | _ReSharper*
58 |
59 | # NCrunch
60 | *.ncrunch*
61 | .*crunch*.local.xml
62 |
63 | # Installshield output folder
64 | [Ee]xpress
65 |
66 | # DocProject is a documentation generator add-in
67 | DocProject/buildhelp/
68 | DocProject/Help/*.HxT
69 | DocProject/Help/*.HxC
70 | DocProject/Help/*.hhc
71 | DocProject/Help/*.hhk
72 | DocProject/Help/*.hhp
73 | DocProject/Help/Html2
74 | DocProject/Help/html
75 |
76 | # Click-Once directory
77 | publish
78 |
79 | # Publish Web Output
80 | *.Publish.xml
81 |
82 | # NuGet Packages Directory
83 | packages
84 |
85 | # Windows Azure Build Output
86 | csx
87 | *.build.csdef
88 |
89 | # Windows Store app package directory
90 | AppPackages/
91 |
92 | # Others
93 | [Bb]in
94 | [Oo]bj
95 | sql
96 | TestResults
97 | [Tt]est[Rr]esult*
98 | *.Cache
99 | ClientBin
100 | [Ss]tyle[Cc]op.*
101 | ~$*
102 | *.dbmdl
103 | Generated_Code #added for RIA/Silverlight projects
104 |
105 | # Backup & report files from converting an old project file to a newer
106 | # Visual Studio version. Backup files are not needed, because we have git ;-)
107 | _UpgradeReport_Files/
108 | Backup*/
109 | UpgradeLog*.XML
110 |
--------------------------------------------------------------------------------
/CoreFramework/ISlug.cs:
--------------------------------------------------------------------------------
1 | namespace SlugGenerator
2 | {
3 | public interface ISlug
4 | {
5 | string Slug { get; set; }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/CoreFramework/SlugGenerator.CoreFramework.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.1
5 | SlugGenerator
6 | SlugGenerator
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/CoreFramework/SlugGenerator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Linq.Expressions;
5 | using System.Reflection;
6 | using System.Text.RegularExpressions;
7 |
8 | namespace SlugGenerator
9 | {
10 | public static class SlugGenerator
11 | {
12 | ///
13 | /// Method generate slug by text (multiple languages)
14 | ///
15 | /// Text for slug
16 | /// Slug separator, example "-" or "_"
17 | /// Slug for url
18 | public static string GenerateSlug(this string incomingString, string slugSeparator = "-")
19 | {
20 | incomingString = incomingString.UniDecode();
21 | var alphaNum = Regex.Replace(incomingString, @"[^a-zA-Z0-9\s]", string.Empty);
22 | alphaNum = Regex.Replace(alphaNum, @"\s+", slugSeparator);
23 | return alphaNum.ToLower();
24 | }
25 |
26 | ///
27 | /// Method generate unique slug by text and list of exist slugs (multiple languages)
28 | ///
29 | /// Text for slug
30 | /// list of slugs
31 | ///
32 | /// Slug for url
33 | public static string GenerateUniqueSlug(this string incomingString, List items, string slugSeparator = "-") where T : ISlug
34 | {
35 | var slug = GenerateSlug(incomingString, slugSeparator);
36 | if (items.Any(m => m.Slug == slug))
37 | {
38 | slug += slug.GetHashCode();
39 | if (items.Any(m => m.Slug == slug))
40 | {
41 | slug += Guid.NewGuid();
42 | }
43 | }
44 | return slug;
45 | }
46 |
47 | ///
48 | /// Method generate slug by text (multiple languages)
49 | ///
50 | /// Text for slug
51 | ///
52 | /// Slug separator, example "-" or "_"
53 | /// list of exist items
54 | /// Slug for url
55 | public static string GenerateUniqueSlug(this string incomingString, List items, Expression> expression, string slugSeparator = "-")
56 | {
57 | var propInfo = ((MemberExpression)expression.Body).Member as PropertyInfo;
58 | var slug = GenerateSlug(incomingString, slugSeparator);
59 | if (items.Any(m => propInfo?.GetValue(m)?.ToString() == slug))
60 | {
61 | slug += slug.GetHashCode();
62 | if (items.Any(m => propInfo?.GetValue(m)?.ToString() == slug))
63 | {
64 | slug += Guid.NewGuid();
65 | }
66 | }
67 | return slug;
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/CoreFramework/Unidecoder.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using System.Text;
3 |
4 | namespace SlugGenerator
5 | {
6 | ///
7 | /// ASCII transliterations of Unicode text
8 | ///
9 | internal static partial class UniDecoder
10 | {
11 | ///
12 | /// Transliterate Unicode string to ASCII string.
13 | ///
14 | /// String you want to transliterate into ASCII
15 | ///
16 | /// If you know the length of the result,
17 | /// pass the value for StringBuilder capacity.
18 | /// InputString.Length*2 is used by default.
19 | ///
20 | ///
21 | /// ASCII string. There are [?] (3 characters) in places of some unknown(?) unicode characters.
22 | /// It is this way in Python code as well.
23 | ///
24 | public static string UniDecode(this string input, int? tempStringBuilderCapacity = null)
25 | {
26 | if (string.IsNullOrEmpty(input))
27 | {
28 | return "";
29 | }
30 |
31 | if (input.All(x => x < 0x80))
32 | {
33 | return input;
34 | }
35 |
36 | var sb = new StringBuilder(tempStringBuilderCapacity ?? input.Length * 2);
37 | foreach (char c in input)
38 | {
39 | if (c < 0x80)
40 | {
41 | sb.Append(c);
42 | }
43 | else
44 | {
45 | int high = c >> 8;
46 | int low = c & 0xff;
47 | string[] transliterations;
48 | if (characters.TryGetValue(high, out transliterations))
49 | {
50 | sb.Append(transliterations[low]);
51 | }
52 | }
53 | }
54 |
55 | return sb.ToString();
56 | }
57 |
58 | ///
59 | /// Transliterate Unicode character to ASCII string.
60 | ///
61 | /// Character you want to transliterate into ASCII
62 | ///
63 | /// ASCII string. Unknown(?) unicode characters will return [?] (3 characters).
64 | /// It is this way in Python code as well.
65 | ///
66 | public static string UniDecode(this char c)
67 | {
68 | string result;
69 | if (c < 0x80)
70 | {
71 | result = new string(c, 1);
72 | }
73 | else
74 | {
75 | int high = c >> 8;
76 | int low = c & 0xff;
77 | string[] transliterations;
78 | if (characters.TryGetValue(high, out transliterations))
79 | {
80 | result = transliterations[low];
81 | }
82 | else
83 | {
84 | result = "";
85 | }
86 | }
87 |
88 | return result;
89 | }
90 | }
91 | }
--------------------------------------------------------------------------------
/Framework/ISlug.cs:
--------------------------------------------------------------------------------
1 | namespace SlugGenerator
2 | {
3 | public interface ISlug
4 | {
5 | string Slug { get; set; }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/Framework/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Framework")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Framework")]
13 | [assembly: AssemblyCopyright("Copyright © 2018")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("5760fab1-f3a1-493d-83e6-f7d76e6a6069")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/Framework/SlugGenerator.Framework.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {5760FAB1-F3A1-493D-83E6-F7D76E6A6069}
8 | Library
9 | Properties
10 | SlugGenerator
11 | SlugGenerator
12 | v4.5
13 | 512
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\Debug\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 |
24 |
25 | pdbonly
26 | true
27 | bin\Release\
28 | TRACE
29 | prompt
30 | 4
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/Framework/SlugGenerator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Linq.Expressions;
5 | using System.Reflection;
6 | using System.Text.RegularExpressions;
7 |
8 | namespace SlugGenerator
9 | {
10 | public static class SlugGenerator
11 | {
12 | ///
13 | /// Method generate slug by text (multiple languages)
14 | ///
15 | /// Text for slug
16 | /// Slug separator, example "-" or "_"
17 | /// Slug for url
18 | public static string GenerateSlug(this string incomingString, string slugSeparator = "-")
19 | {
20 | incomingString = incomingString.UniDecode();
21 | var alphaNum = Regex.Replace(incomingString, @"[^a-zA-Z0-9\s]", string.Empty);
22 | alphaNum = Regex.Replace(alphaNum, @"\s+", slugSeparator);
23 | return alphaNum.ToLower();
24 | }
25 |
26 | ///
27 | /// Method generate unique slug by text and list of exist slugs (multiple languages)
28 | ///
29 | /// Text for slug
30 | /// list of slugs
31 | ///
32 | /// Slug for url
33 | public static string GenerateUniqueSlug(this string incomingString, List items, string slugSeparator = "-") where T : ISlug
34 | {
35 | var slug = GenerateSlug(incomingString, slugSeparator);
36 | if (items.Any(m => m.Slug == slug))
37 | {
38 | slug += slug.GetHashCode();
39 | if (items.Any(m => m.Slug == slug))
40 | {
41 | slug += Guid.NewGuid();
42 | }
43 | }
44 | return slug;
45 | }
46 |
47 | ///
48 | /// Method generate slug by text (multiple languages)
49 | ///
50 | /// Text for slug
51 | ///
52 | /// Slug separator, example "-" or "_"
53 | /// list of exist items
54 | /// Slug for url
55 | public static string GenerateUniqueSlug(this string incomingString, List items, Expression> expression, string slugSeparator = "-")
56 | {
57 | var propInfo = ((MemberExpression)expression.Body).Member as PropertyInfo;
58 | var slug = GenerateSlug(incomingString, slugSeparator);
59 | if (items.Any(m => propInfo?.GetValue(m)?.ToString() == slug))
60 | {
61 | slug += slug.GetHashCode();
62 | if (items.Any(m => propInfo?.GetValue(m)?.ToString() == slug))
63 | {
64 | slug += Guid.NewGuid();
65 | }
66 | }
67 | return slug;
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/Framework/Unidecoder.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using System.Text;
3 |
4 | namespace SlugGenerator
5 | {
6 | ///
7 | /// ASCII transliterations of Unicode text
8 | ///
9 | internal static partial class UniDecoder
10 | {
11 | ///
12 | /// Transliterate Unicode string to ASCII string.
13 | ///
14 | /// String you want to transliterate into ASCII
15 | ///
16 | /// If you know the length of the result,
17 | /// pass the value for StringBuilder capacity.
18 | /// InputString.Length*2 is used by default.
19 | ///
20 | ///
21 | /// ASCII string. There are [?] (3 characters) in places of some unknown(?) unicode characters.
22 | /// It is this way in Python code as well.
23 | ///
24 | public static string UniDecode(this string input, int? tempStringBuilderCapacity = null)
25 | {
26 | if (string.IsNullOrEmpty(input))
27 | {
28 | return "";
29 | }
30 |
31 | if (input.All(x => x < 0x80))
32 | {
33 | return input;
34 | }
35 |
36 | var sb = new StringBuilder(tempStringBuilderCapacity ?? input.Length * 2);
37 | foreach (char c in input)
38 | {
39 | if (c < 0x80)
40 | {
41 | sb.Append(c);
42 | }
43 | else
44 | {
45 | int high = c >> 8;
46 | int low = c & 0xff;
47 | string[] transliterations;
48 | if (characters.TryGetValue(high, out transliterations))
49 | {
50 | sb.Append(transliterations[low]);
51 | }
52 | }
53 | }
54 |
55 | return sb.ToString();
56 | }
57 |
58 | ///
59 | /// Transliterate Unicode character to ASCII string.
60 | ///
61 | /// Character you want to transliterate into ASCII
62 | ///
63 | /// ASCII string. Unknown(?) unicode characters will return [?] (3 characters).
64 | /// It is this way in Python code as well.
65 | ///
66 | public static string UniDecode(this char c)
67 | {
68 | string result;
69 | if (c < 0x80)
70 | {
71 | result = new string(c, 1);
72 | }
73 | else
74 | {
75 | int high = c >> 8;
76 | int low = c & 0xff;
77 | string[] transliterations;
78 | if (characters.TryGetValue(high, out transliterations))
79 | {
80 | result = transliterations[low];
81 | }
82 | else
83 | {
84 | result = "";
85 | }
86 | }
87 |
88 | return result;
89 | }
90 | }
91 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Artem Polischuk
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # What is SlugGenerator?
2 | SlugGenerator it's simple Slug and clean URL generator. Supports multiple languages such as:
3 | Cyrillic, Latin, Chinese and other languages encodings
4 |
5 | ## Where can I get it?
6 | Install from the package manager console:
7 |
8 | PM> Install-Package SlugGenerator
9 |
10 | ## Slug generation
11 | ### Simple usage
12 | ```cs
13 | using SlugGenerator;
14 |
15 | "my test text".GenerateSlug(); // return my-test-text
16 | ```
17 | ### Using Custom space separator
18 | ```cs
19 | using SlugGenerator;
20 |
21 | "my test text".GenerateSlug("_"); // set "_" as separator and return "my_test_text" string
22 | ```
23 |
24 | ## Multilanguage feature
25 | Slug generator transliteration all basic languages to english charters
26 |
27 | ```cs
28 | using SlugGenerator;
29 |
30 | // Russian language
31 | "привет как дела".GenerateSlug(); // return privet-kak-dela
32 | "你好你怎麼樣".GenerateSlug(); // return ni-hao-ni-zen-mo-yang-
33 | ```
34 | ## Generate Unique slug
35 | This method help u Generate unique slug, if slug already exist on list, method generate slug with additional numbers or guid.
36 | ```cs
37 | using SlugGenerator;
38 | public class ConcreteSlug : ISlug
39 | {
40 | public string Slug { get; set; }
41 | }
42 |
43 |
44 | var slug = item.Text.GenerateUniqueSlug(items);
45 | var itemsList = new List
46 | {
47 | new ConcreteSlug
48 | {
49 | Slug = "test"
50 | },
51 | new ConcreteSlug
52 | {
53 | Slug = "test2"
54 | }
55 | };
56 | var slug = "test".GenerateUniqueSlug(itemsList); // return slug which is not in an itemsList
57 | ```
58 |
--------------------------------------------------------------------------------
/SlugGenerator.Tests/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("SlugGenerator.Tests")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("SlugGenerator.Tests")]
13 | [assembly: AssemblyCopyright("Copyright © 2016")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("f1d33ba0-a8d8-44b3-a5c4-ffad344e96f4")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/SlugGenerator.Tests/Slug.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace SlugGenerator.Tests
8 | {
9 |
10 | public class ConcreteSlug : ISlug
11 | {
12 | public string Text { get; set; }
13 | public string Slug { get; set; }
14 | }
15 | public class Entity
16 | {
17 | public string Text { get; set; }
18 | public string SlugProperty { get; set; }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/SlugGenerator.Tests/SlugGenerator.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | {F1D33BA0-A8D8-44B3-A5C4-FFAD344E96F4}
7 | Library
8 | Properties
9 | SlugGenerator.Tests
10 | SlugGenerator.Tests
11 | v4.7.1
12 | 512
13 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
14 | 10.0
15 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
16 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages
17 | False
18 | UnitTest
19 |
20 |
21 |
22 | true
23 | full
24 | false
25 | bin\Debug\
26 | DEBUG;TRACE
27 | prompt
28 | 4
29 |
30 |
31 | pdbonly
32 | true
33 | bin\Release\
34 | TRACE
35 | prompt
36 | 4
37 |
38 |
39 |
40 | ..\packages\NUnit.3.6.1\lib\net45\nunit.framework.dll
41 |
42 |
43 | ..\packages\AutoFixture.3.50.2\lib\net40\Ploeh.AutoFixture.dll
44 |
45 |
46 | ..\packages\AutoFixture.NUnit3.3.50.2\lib\net40\Ploeh.AutoFixture.NUnit3.dll
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | {5760fab1-f3a1-493d-83e6-f7d76e6a6069}
77 | SlugGenerator.Framework
78 |
79 |
80 |
81 |
82 |
83 |
84 | False
85 |
86 |
87 | False
88 |
89 |
90 | False
91 |
92 |
93 | False
94 |
95 |
96 |
97 |
98 |
99 |
100 |
107 |
--------------------------------------------------------------------------------
/SlugGenerator.Tests/SlugGeneratorTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using NUnit.Framework;
5 | using Ploeh.AutoFixture;
6 | using Ploeh.AutoFixture.NUnit3;
7 | using Assert = Microsoft.VisualStudio.TestTools.UnitTesting.Assert;
8 |
9 | namespace SlugGenerator.Tests
10 | {
11 | [TestFixture]
12 | public class SlugGeneratorTests
13 | {
14 | [Test, TestCaseSource(nameof(GenerateSlugTestCases))]
15 | public void GenerateSlug_WithValidData_ShouldReturnSlugString(string text)
16 | {
17 | var slug = text.GenerateSlug();
18 | Assert.IsNotNull(slug);
19 | Console.WriteLine(slug);
20 | }
21 | [Test, TestCaseSource(nameof(GenerateSlugTestCases))]
22 | public void GenerateSlug_WithValidDataAndOtherSlugSeparator_ShouldReturnSlugString(string text)
23 | {
24 | var slug = text.GenerateSlug("_");
25 | Assert.IsNotNull(slug);
26 | Console.WriteLine(slug);
27 | }
28 | [Test, TestCaseSource(nameof(GenerateUniqueSlugTestCases))]
29 | public void GenerateUniqueSlug_WithValidData_ShouldReturnUniqueSlugString(List items)
30 | {
31 | foreach (var item in items)
32 | {
33 | item.Slug = item.Text.GenerateUniqueSlug(items);
34 | Assert.IsNotNull(item.Slug);
35 | Console.WriteLine(item.Slug);
36 | var count = items.Count(concreteSlug => concreteSlug.Slug == item.Slug);
37 | Assert.IsTrue(count == 1);
38 | }
39 | }
40 | [Test, AutoData]
41 | public void GenerateUniqueSlugAndCustomProperty_WithRandomText_ShouldReturnSlugString(List items)
42 | {
43 | foreach (var item in items)
44 | {
45 | item.SlugProperty = item.Text.GenerateUniqueSlug(items, i => i.SlugProperty);
46 | Assert.IsNotNull(item.SlugProperty);
47 | Console.WriteLine(item.SlugProperty);
48 | var count = items.Count(concreteSlug => concreteSlug.SlugProperty == item.SlugProperty);
49 | Assert.IsTrue(count == 1);
50 | }
51 | }
52 | [Test, TestCaseSource(nameof(GenerateEntityListUniqueSlugTestCases))]
53 | public void GenerateUniqueSlugAndCustomProperty_WithSameText_ShouldReturnUniqueSlugString(List items)
54 | {
55 | foreach (var item in items)
56 | {
57 | item.SlugProperty = item.Text.GenerateUniqueSlug(items, i => i.SlugProperty);
58 | Assert.IsNotNull(item.SlugProperty);
59 | Console.WriteLine(item.SlugProperty);
60 | var count = items.Count(concreteSlug => concreteSlug.SlugProperty == item.SlugProperty);
61 | Assert.IsTrue(count == 1);
62 | }
63 | }
64 | private static IEnumerable GenerateSlugTestCases
65 | {
66 | get
67 | {
68 | var testCaseData = new List
69 | {
70 | new TestCaseData(null),
71 | new TestCaseData("The quick brown fox jumps over the lazy dog"),
72 | new TestCaseData("Тёмно-рыжая лиса прыг через лентяя-пса"),
73 | new TestCaseData("Дует на море циклон, попадает на Цейлон"),
74 | new TestCaseData("My test article title"),
75 | new TestCaseData("Der schnelle braune Fuchs springt über den faulen Hund"),
76 | new TestCaseData("빠른 갈색 여우가 게으른 개 점프"),
77 | new TestCaseData("Тестируем223 разную КІРїЛЁЦґ"),
78 | new TestCaseData("So so long spaces in string")
79 | };
80 | return testCaseData;
81 | }
82 | }
83 | private static IEnumerable GenerateUniqueSlugTestCases
84 | {
85 | get
86 | {
87 | var slugListItems = new List
88 | {
89 | new ConcreteSlug
90 | {
91 | Text = "Дуетhg на море циклон, попадает на Цейлон"
92 | },
93 | new ConcreteSlug
94 | {
95 | Text = "Дует на море циклон, попадает на Цейлон"
96 | },
97 | new ConcreteSlug
98 | {
99 | Text = "Дует на море циклон, попадает на Цейлон"
100 | },
101 | new ConcreteSlug
102 | {
103 | Text = "Дует на море циклон, попадает на Цейлон"
104 | },
105 | new ConcreteSlug
106 | {
107 | Text = "Дует на море циклон123, попадает на Цейлон"
108 | }
109 | };
110 | var testCaseData = new List
111 | {
112 | new TestCaseData(slugListItems)
113 | };
114 | return testCaseData;
115 | }
116 | }
117 | private static IEnumerable GenerateEntityListUniqueSlugTestCases
118 | {
119 | get
120 | {
121 | var slugListItems = new List
122 | {
123 | new Entity
124 | {
125 | Text = "Дует на море циклон, попадает на Цейлон"
126 | },
127 | new Entity
128 | {
129 | Text = "Дует на море циклон, попадает на Цейлон"
130 | },
131 | new Entity
132 | {
133 | Text = "Дует на море циклон, попадает на Цейлон"
134 | }
135 | };
136 | var testCaseData = new List
137 | {
138 | new TestCaseData(slugListItems)
139 | };
140 | return testCaseData;
141 | }
142 | }
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/SlugGenerator.Tests/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/SlugGenerator.Tests/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/SlugGenerator.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27428.2037
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SlugGenerator.Tests", "SlugGenerator.Tests\SlugGenerator.Tests.csproj", "{F1D33BA0-A8D8-44B3-A5C4-FFAD344E96F4}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SlugGenerator.Framework", "Framework\SlugGenerator.Framework.csproj", "{5760FAB1-F3A1-493D-83E6-F7D76E6A6069}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SlugGenerator.CoreFramework", "CoreFramework\SlugGenerator.CoreFramework.csproj", "{EB160978-BF7F-45B7-8A03-3A5F894B543A}"
11 | EndProject
12 | Global
13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
14 | Debug|Any CPU = Debug|Any CPU
15 | Release|Any CPU = Release|Any CPU
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {F1D33BA0-A8D8-44B3-A5C4-FFAD344E96F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19 | {F1D33BA0-A8D8-44B3-A5C4-FFAD344E96F4}.Debug|Any CPU.Build.0 = Debug|Any CPU
20 | {F1D33BA0-A8D8-44B3-A5C4-FFAD344E96F4}.Release|Any CPU.ActiveCfg = Release|Any CPU
21 | {F1D33BA0-A8D8-44B3-A5C4-FFAD344E96F4}.Release|Any CPU.Build.0 = Release|Any CPU
22 | {5760FAB1-F3A1-493D-83E6-F7D76E6A6069}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23 | {5760FAB1-F3A1-493D-83E6-F7D76E6A6069}.Debug|Any CPU.Build.0 = Debug|Any CPU
24 | {5760FAB1-F3A1-493D-83E6-F7D76E6A6069}.Release|Any CPU.ActiveCfg = Release|Any CPU
25 | {5760FAB1-F3A1-493D-83E6-F7D76E6A6069}.Release|Any CPU.Build.0 = Release|Any CPU
26 | {EB160978-BF7F-45B7-8A03-3A5F894B543A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {EB160978-BF7F-45B7-8A03-3A5F894B543A}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {EB160978-BF7F-45B7-8A03-3A5F894B543A}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {EB160978-BF7F-45B7-8A03-3A5F894B543A}.Release|Any CPU.Build.0 = Release|Any CPU
30 | EndGlobalSection
31 | GlobalSection(SolutionProperties) = preSolution
32 | HideSolutionNode = FALSE
33 | EndGlobalSection
34 | GlobalSection(ExtensibilityGlobals) = postSolution
35 | SolutionGuid = {339FF00B-747A-4484-94E8-0D8362367056}
36 | EndGlobalSection
37 | EndGlobal
38 |
--------------------------------------------------------------------------------