Skip to content

Commit 20f8cc5

Browse files
VS-96: Fake Data Class Generators (#45)
1 parent 2f8db4e commit 20f8cc5

File tree

13 files changed

+772
-23
lines changed

13 files changed

+772
-23
lines changed

src/MongoDB.Analyzer/Core/Poco/Data/data.json

Lines changed: 612 additions & 0 deletions
Large diffs are not rendered by default.

src/MongoDB.Analyzer/Core/Poco/PocoDataFiller.cs

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,30 +12,64 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
using System.Text.RegularExpressions;
16+
using Newtonsoft.Json;
17+
1518
namespace MongoDB.Analyzer.Core.Poco;
1619

1720
public static class PocoDataFiller
1821
{
1922
private const string CollectionNamespace = "System.Collections.Generic";
23+
private const string JsonDataResource = "MongoDB.Analyzer.Core.Poco.Data.Data.json";
2024
private const int MaxDepth = 3;
2125

26+
private static readonly ConcurrentDictionary<string, string[]> s_jsonData;
27+
private static readonly Regex s_jsonDataRegexPattern;
28+
private static readonly HashSet<string> s_supportedSystemTypes = new()
29+
{
30+
"System.DateTime",
31+
"System.TimeSpan"
32+
};
33+
34+
static PocoDataFiller()
35+
{
36+
s_jsonData = LoadJsonData();
37+
s_jsonDataRegexPattern = new Regex(string.Join("|", s_jsonData.Keys.OrderBy(key => key)), RegexOptions.IgnoreCase | RegexOptions.Compiled);
38+
}
39+
2240
public static void PopulatePoco(object poco) =>
2341
SetPropertiesAndFields(poco, MaxDepth);
2442

43+
private static string GetJsonDataValue(string memberName)
44+
{
45+
var match = s_jsonDataRegexPattern.Match(memberName);
46+
if (match.Success)
47+
{
48+
var jsonData = s_jsonData[match.Value];
49+
return jsonData[memberName.Length % jsonData.Length];
50+
}
51+
52+
return null;
53+
}
54+
2555
private static object GetPropertyOrFieldValue(Type memberType, string memberName, int levelsLeft)
2656
{
2757
if (memberType.IsPrimitive)
2858
{
29-
return Convert.ChangeType(memberName.Length % 10, memberType);
59+
return HandlePrimitive(memberName, memberType);
3060
}
3161
else if (memberType.IsString())
3262
{
33-
return $"{memberName}_val";
63+
return HandleString(memberName);
3464
}
3565
else if (memberType.IsArray)
3666
{
3767
return HandleArray(memberType);
3868
}
69+
else if (memberType.IsSupportedSystemType())
70+
{
71+
return HandleSystemType(memberType, memberName);
72+
}
3973
else if (memberType.IsSupportedCollection())
4074
{
4175
return Activator.CreateInstance(typeof(List<>)
@@ -62,16 +96,50 @@ private static object HandleClass(Type memberType, int levelsLeft)
6296
private static Array HandleMultiDimensionalArray(Type arrayType) =>
6397
Array.CreateInstance(arrayType.GetElementType(), Enumerable.Repeat(0, arrayType.GetArrayRank()).ToArray());
6498

99+
private static object HandlePrimitive(string memberName, Type memberType)
100+
{
101+
var jsonDataValue = GetJsonDataValue(memberName);
102+
if (jsonDataValue != null)
103+
{
104+
return Convert.ChangeType(jsonDataValue, memberType);
105+
}
106+
107+
return Convert.ChangeType(memberName.Length % 10, memberType);
108+
}
109+
65110
private static Array HandleSingleDimensionalArray(Type arrayType) =>
66111
Array.CreateInstance(arrayType.GetElementType(), 0);
67112

113+
private static object HandleString(string memberName) =>
114+
GetJsonDataValue(memberName) ?? $"{memberName}_val";
115+
116+
private static object HandleSystemType(Type systemType, string memberName) =>
117+
systemType.FullName switch
118+
{
119+
"System.DateTime" => new DateTime(memberName.Length * 100, memberName.Length % 12, memberName.Length % 30),
120+
"System.TimeSpan" => new TimeSpan(memberName.Length % 24, memberName.Length % 60, memberName.Length % 60),
121+
_ => throw new ArgumentOutOfRangeException(nameof(systemType), systemType, "Unsupported system type")
122+
};
123+
68124
private static bool IsString(this Type type) =>
69125
type == typeof(string);
70126

71127
private static bool IsSupportedCollection(this Type type) =>
72128
CollectionNamespace == type.Namespace &&
73129
type.GenericTypeArguments.Length == 1;
74130

131+
private static bool IsSupportedSystemType(this Type type) =>
132+
s_supportedSystemTypes.Contains(type.FullName);
133+
134+
private static ConcurrentDictionary<string, string[]> LoadJsonData()
135+
{
136+
using (var resourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(JsonDataResource))
137+
using (var streamReader = new StreamReader(resourceStream))
138+
{
139+
return JsonConvert.DeserializeObject<ConcurrentDictionary<string, string[]>>(streamReader.ReadToEnd());
140+
}
141+
}
142+
75143
private static void SetPropertiesAndFields(object poco, int levelsLeft)
76144
{
77145
var pocoType = poco.GetType();

src/MongoDB.Analyzer/Core/Utilities/SymbolExtensions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ internal static class SymbolExtensions
6262

6363
private static readonly HashSet<string> s_supportedSystemTypes = new()
6464
{
65+
"System.DateTime",
6566
"System.DateTimeKind",
6667
"System.DateTimeOffset",
6768
"System.TimeSpan",

src/MongoDB.Analyzer/MongoDB.Analyzer.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
<EmbeddedResource Include="..\MongoDB.Analyzer.Helpers\Linq\*.cs" LinkBase="Core\HelperResources\Linq" />
2323
<EmbeddedResource Include="..\MongoDB.Analyzer.Helpers\Builders\*.cs" LinkBase="Core\HelperResources\Builders" />
2424
<EmbeddedResource Include="..\MongoDB.Analyzer.Helpers\Poco\*.cs" LinkBase="Core\HelperResources\Poco" />
25+
<EmbeddedResource Include="Core\Poco\Data\Data.json" />
2526
</ItemGroup>
2627

2728
<ItemGroup>

tests/MongoDB.Analyzer.Tests.Common.TestCases/Poco/PocoBasic.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@ namespace MongoDB.Analyzer.Tests.Common.TestCases.Poco
1616
{
1717
public sealed class PocoBasic : TestCasesBase
1818
{
19-
[PocoJson("{ \"City\" : \"City_val\", \"Province\" : \"Province_val\", \"ZipCode\" : \"ZipCode_val\" }")]
19+
[PocoJson("{ \"City\" : \"Dallas\", \"Province\" : \"Lombardy\", \"ZipCode\" : \"60601\" }")]
2020
public void Address()
2121
{
2222
}
2323

24-
[PocoJson("{ \"AirportName\" : \"AirportName_val\", \"AirportCode\" : \"AirportCode_val\" }")]
24+
[PocoJson("{ \"AirportName\" : \"Jomo Kenyatta International Airport\", \"AirportCode\" : \"LAX\" }")]
2525
public void Airport()
2626
{
2727
}
@@ -31,7 +31,7 @@ public void Car()
3131
{
3232
}
3333

34-
[PocoJson("{ \"CustomerID\" : 0, \"Name\" : \"Name_val\", \"Address\" : \"Address_val\" }")]
34+
[PocoJson("{ \"CustomerID\" : 0, \"Name\" : \"Benjamin\", \"Address\" : \"444 Oakwood Avenue, Summitville, OH 43002\" }")]
3535
public void Customer()
3636
{
3737
}

tests/MongoDB.Analyzer.Tests.Common.TestCases/Poco/PocoBsonAttributes.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,16 @@ public void House()
2626
{
2727
}
2828

29-
[PocoJson("{ \"ExpiryDate\" : ISODate(\"0001-01-01T00:00:00Z\"), \"Name\" : \"Name_val\", \"InStock\" : true, \"price\" : \"0\", \"Pair\" : { \"StringA\" : null, \"StringB\" : null }, \"Length\" : 6, \"Width\" : 5, \"SaleTime\" : \"00:00:00\" }")]
29+
#if NET472
30+
[PocoJson("{ \"ExpiryDate\" : ISODate(\"1000-10-10T00:00:00Z\"), \"Name\" : \"Benjamin\", \"InStock\" : false, \"price\" : \"0\", \"Pair\" : { \"StringA\" : null, \"StringB\" : null }, \"Length\" : 6, \"Width\" : 5, \"SaleTime\" : \"08:08:08\" }")]
31+
#else
32+
[PocoJson("{ \"ExpiryDate\" : ISODate(\"1000-10-10T04:57:00Z\"), \"Name\" : \"Benjamin\", \"InStock\" : false, \"price\" : \"0\", \"Pair\" : { \"StringA\" : null, \"StringB\" : null }, \"Length\" : 6, \"Width\" : 5, \"SaleTime\" : \"08:08:08\" }")]
33+
#endif
3034
public void Clothing()
3135
{
3236
}
3337

34-
[PocoJson("{ \"VegetableCost\" : 3.0 }")]
38+
[PocoJson("{ \"VegetableCost\" : 0.0 }")]
3539
public void Vegetable()
3640
{
3741
}

tests/MongoDB.Analyzer.Tests.Common.TestCases/Poco/PocoFields.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public void PrimitiveTypeHolderWithFields()
2323
{
2424
}
2525

26-
[PocoJson("{ \"Address\" : { \"City\" : \"City_val\", \"Province\" : \"Province_val\", \"ZipCode\" : \"ZipCode_val\" }, \"Person\" : { \"Name\" : \"Name_val\", \"LastName\" : \"LastName_val\", \"Address\" : { \"City\" : \"City_val\", \"Province\" : \"Province_val\", \"ZipCode\" : \"ZipCode_val\" }, \"Vehicle\" : { \"LicenceNumber\" : \"LicenceNumber_val\", \"VehicleType\" : { \"VehicleMake\" : null, \"Type\" : 0, \"Category\" : \"Category_val\", \"MPG\" : 3.0 } }, \"SiblingsCount\" : 3, \"TicksSinceBirth\" : NumberLong(5), \"IsRetired\" : true }, \"Tree\" : { \"Root\" : { \"Data\" : 4, \"Left\" : { \"Data\" : 4, \"Left\" : null, \"Right\" : null, \"Tree\" : null }, \"Right\" : { \"Data\" : 4, \"Left\" : null, \"Right\" : null, \"Tree\" : null }, \"Tree\" : { \"Root\" : null } } }, \"User\" : { \"Name\" : \"Name_val\", \"LastName\" : \"LastName_val\", \"Address\" : \"Address_val\", \"Age\" : 3, \"Height\" : 6, \"Scores\" : [] }, \"Vehicle\" : { \"LicenceNumber\" : \"LicenceNumber_val\", \"VehicleType\" : { \"VehicleMake\" : { \"Name\" : \"Name_val\" }, \"Type\" : 0, \"Category\" : \"Category_val\", \"MPG\" : 3.0 } }, \"EnumInt16\" : 0, \"EnumInt32\" : 0, \"EnumInt64\" : NumberLong(0), \"Pair\" : { \"StringA\" : null, \"StringB\" : null } }")]
26+
[PocoJson("{ \"Address\" : { \"City\" : \"Dallas\", \"Province\" : \"Lombardy\", \"ZipCode\" : \"60601\" }, \"Person\" : { \"Name\" : \"Benjamin\", \"LastName\" : \"Martin\", \"Address\" : { \"City\" : \"Dallas\", \"Province\" : \"Lombardy\", \"ZipCode\" : \"60601\" }, \"Vehicle\" : { \"LicenceNumber\" : \"N48-OPQ\", \"VehicleType\" : { \"VehicleMake\" : null, \"Type\" : 0, \"Category\" : \"Category_val\", \"MPG\" : 3.0 } }, \"SiblingsCount\" : 3, \"TicksSinceBirth\" : NumberLong(5), \"IsRetired\" : true }, \"Tree\" : { \"Root\" : { \"Data\" : 4, \"Left\" : { \"Data\" : 4, \"Left\" : null, \"Right\" : null, \"Tree\" : null }, \"Right\" : { \"Data\" : 4, \"Left\" : null, \"Right\" : null, \"Tree\" : null }, \"Tree\" : { \"Root\" : null } } }, \"User\" : { \"Name\" : \"Benjamin\", \"LastName\" : \"Martin\", \"Address\" : \"444 Oakwood Avenue, Summitville, OH 43002\", \"Age\" : 3, \"Height\" : 6, \"Scores\" : [] }, \"Vehicle\" : { \"LicenceNumber\" : \"N48-OPQ\", \"VehicleType\" : { \"VehicleMake\" : { \"Name\" : \"Benjamin\" }, \"Type\" : 0, \"Category\" : \"Category_val\", \"MPG\" : 3.0 } }, \"EnumInt16\" : 0, \"EnumInt32\" : 0, \"EnumInt64\" : NumberLong(0), \"Pair\" : { \"StringA\" : null, \"StringB\" : null } }")]
2727
public void NestedTypeHolderWithFields()
2828
{
2929
}

tests/MongoDB.Analyzer.Tests.Common.TestCases/Poco/PocoIgnoredBsonAttributes.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,11 @@ namespace MongoDB.Analyzer.Tests.Common.TestCases.Poco
2222
{
2323
public sealed class PocoIgnoredBsonAttributes : TestCasesBase
2424
{
25-
[PocoJson("{ \"ExpiryDate\" : ISODate(\"0001-01-01T00:00:00Z\"), \"DictionaryField\" : { }, \"Name\" : \"Name_val\", \"InStock\" : true, \"Price\" : \"0\", \"Pair\" : { \"StringA\" : null, \"StringB\" : null }, \"Length\" : 6, \"Width\" : 5, \"SaleTime\" : \"00:00:00\" }")]
25+
#if NET472
26+
[PocoJson("{ \"ExpiryDate\" : ISODate(\"1000-10-10T00:00:00Z\"), \"DictionaryField\" : { }, \"Name\" : \"Benjamin\", \"InStock\" : false, \"Price\" : \"0\", \"Pair\" : { \"StringA\" : null, \"StringB\" : null }, \"Length\" : 6, \"Width\" : 5, \"SaleTime\" : \"08:08:08\" }")]
27+
#else
28+
[PocoJson("{ \"ExpiryDate\" : ISODate(\"1000-10-10T04:57:00Z\"), \"DictionaryField\" : { }, \"Name\" : \"Benjamin\", \"InStock\" : false, \"Price\" : \"0\", \"Pair\" : { \"StringA\" : null, \"StringB\" : null }, \"Length\" : 6, \"Width\" : 5, \"SaleTime\" : \"08:08:08\" }")]
29+
#endif
2630
public void UnsupportedBsonAttributes()
2731
{
2832
}

tests/MongoDB.Analyzer.Tests.Common.TestCases/Poco/PocoNestedTypes.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ namespace MongoDB.Analyzer.Tests.Common.TestCases.Poco
1818
{
1919
public sealed class PocoNestedTypes : TestCasesBase
2020
{
21-
[PocoJson("{ \"Address\" : { \"City\" : \"City_val\", \"Province\" : \"Province_val\", \"ZipCode\" : \"ZipCode_val\" }, \"Person\" : { \"Name\" : \"Name_val\", \"LastName\" : \"LastName_val\", \"Address\" : { \"City\" : \"City_val\", \"Province\" : \"Province_val\", \"ZipCode\" : \"ZipCode_val\" }, \"Vehicle\" : { \"LicenceNumber\" : \"LicenceNumber_val\", \"VehicleType\" : { \"VehicleMake\" : null, \"Type\" : 0, \"Category\" : \"Category_val\", \"MPG\" : 3.0 } }, \"SiblingsCount\" : 3, \"TicksSinceBirth\" : NumberLong(5), \"IsRetired\" : true }, \"Tree\" : { \"Root\" : { \"Data\" : 4, \"Left\" : { \"Data\" : 4, \"Left\" : null, \"Right\" : null, \"Tree\" : null }, \"Right\" : { \"Data\" : 4, \"Left\" : null, \"Right\" : null, \"Tree\" : null }, \"Tree\" : { \"Root\" : null } } }, \"User\" : { \"Name\" : \"Name_val\", \"LastName\" : \"LastName_val\", \"Address\" : \"Address_val\", \"Age\" : 3, \"Height\" : 6, \"Scores\" : [] }, \"Vehicle\" : { \"LicenceNumber\" : \"LicenceNumber_val\", \"VehicleType\" : { \"VehicleMake\" : { \"Name\" : \"Name_val\" }, \"Type\" : 0, \"Category\" : \"Category_val\", \"MPG\" : 3.0 } }, \"EnumInt16\" : 0, \"EnumInt32\" : 0, \"EnumInt64\" : NumberLong(0), \"Pair\" : { \"StringA\" : null, \"StringB\" : null } }")]
21+
[PocoJson("{ \"Address\" : { \"City\" : \"Dallas\", \"Province\" : \"Lombardy\", \"ZipCode\" : \"60601\" }, \"Person\" : { \"Name\" : \"Benjamin\", \"LastName\" : \"Martin\", \"Address\" : { \"City\" : \"Dallas\", \"Province\" : \"Lombardy\", \"ZipCode\" : \"60601\" }, \"Vehicle\" : { \"LicenceNumber\" : \"N48-OPQ\", \"VehicleType\" : { \"VehicleMake\" : null, \"Type\" : 0, \"Category\" : \"Category_val\", \"MPG\" : 3.0 } }, \"SiblingsCount\" : 3, \"TicksSinceBirth\" : NumberLong(5), \"IsRetired\" : true }, \"Tree\" : { \"Root\" : { \"Data\" : 4, \"Left\" : { \"Data\" : 4, \"Left\" : null, \"Right\" : null, \"Tree\" : null }, \"Right\" : { \"Data\" : 4, \"Left\" : null, \"Right\" : null, \"Tree\" : null }, \"Tree\" : { \"Root\" : null } } }, \"User\" : { \"Name\" : \"Benjamin\", \"LastName\" : \"Martin\", \"Address\" : \"444 Oakwood Avenue, Summitville, OH 43002\", \"Age\" : 3, \"Height\" : 6, \"Scores\" : [] }, \"Vehicle\" : { \"LicenceNumber\" : \"N48-OPQ\", \"VehicleType\" : { \"VehicleMake\" : { \"Name\" : \"Benjamin\" }, \"Type\" : 0, \"Category\" : \"Category_val\", \"MPG\" : 3.0 } }, \"EnumInt16\" : 0, \"EnumInt32\" : 0, \"EnumInt64\" : NumberLong(0), \"Pair\" : { \"StringA\" : null, \"StringB\" : null } }")]
2222
public void NestedTypeHolder()
2323
{
2424
}

tests/MongoDB.Analyzer.Tests.Common.TestCases/Poco/PocoSystemTypes.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@ namespace MongoDB.Analyzer.Tests.Common.TestCases.Poco
1818
{
1919
public sealed class PocoSystemTypes : TestCasesBase
2020
{
21-
[PocoJson("{ \"DateTimeKindField\" : 0, \"DateTimeOffsetField\" : [NumberLong(0), 0], \"TimeSpanField\" : \"00:00:00\", \"TypeField\" : null }")]
21+
#if NET472
22+
[PocoJson("{ \"DateTimeField\" : ISODate(\"1300-01-13T00:00:00Z\"), \"DateTimeKindField\" : 0, \"DateTimeOffsetField\" : [NumberLong(0), 0], \"TimeSpanField\" : \"13:13:13\", \"TypeField\" : null }")]
23+
#else
24+
[PocoJson("{ \"DateTimeField\" : ISODate(\"1300-01-13T04:57:00Z\"), \"DateTimeKindField\" : 0, \"DateTimeOffsetField\" : [NumberLong(0), 0], \"TimeSpanField\" : \"13:13:13\", \"TypeField\" : null }")]
25+
#endif
2226
public void SystemTypeContainer()
2327
{
2428
}
@@ -27,6 +31,7 @@ public class TestClasses
2731
{
2832
public class SystemTypeContainer
2933
{
34+
public DateTime DateTimeField { get; set; }
3035
public DateTimeKind DateTimeKindField { get; set; }
3136
public DateTimeOffset DateTimeOffsetField { get; set; }
3237
public TimeSpan TimeSpanField { get; set; }

0 commit comments

Comments
 (0)