Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/HeuristicLab.Tests/HeuristicLab-3.3/DeepCloneableCloningTest.cs @ 17021

Last change on this file since 17021 was 17021, checked in by mkommend, 5 years ago

#2520: Adapted all unit tests to use attic instead of the xml persistence. This affects all sample unit tests, the test resources, script unit tests and some general unit tests.

File size: 7.1 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2019 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.Linq;
25using HEAL.Attic;
26using HeuristicLab.Common;
27using HeuristicLab.Core;
28using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
29using HeuristicLab.Optimization;
30using HeuristicLab.PluginInfrastructure;
31using Microsoft.VisualStudio.TestTools.UnitTesting;
32
33namespace HeuristicLab.Tests {
34  [TestClass]
35  public class DeepCloneableCloningTest {
36    private static readonly ProtoBufSerializer serializer = new ProtoBufSerializer();
37
38    private TestContext testContextInstance;
39    public TestContext TestContext {
40      get { return testContextInstance; }
41      set { testContextInstance = value; }
42    }
43
44    public DeepCloneableCloningTest() {
45      excludedTypes = new HashSet<Type> {
46        typeof (HeuristicLab.Problems.DataAnalysis.Dataset),
47        typeof (HeuristicLab.Problems.TravelingSalesman.DistanceMatrix),
48        typeof (HeuristicLab.Problems.DataAnalysis.ClassificationEnsembleSolution),
49        typeof (HeuristicLab.Problems.DataAnalysis.RegressionEnsembleSolution),
50        typeof (HeuristicLab.Problems.Orienteering.DistanceMatrix),
51        typeof (HeuristicLab.Problems.PTSP.DistanceMatrix)
52      };
53      excludedTypes.Add(typeof(SymbolicExpressionGrammar).Assembly.GetType("HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.EmptySymbolicExpressionTreeGrammar"));
54
55      foreach (var symbolType in ApplicationManager.Manager.GetTypes(typeof(HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Symbol)))
56        excludedTypes.Add(symbolType);
57      // SimpleSymbol is a non-discoverable type and thus needs to be added manually
58      excludedTypes.Add(typeof(HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.SimpleSymbol));
59      foreach (var grammarType in ApplicationManager.Manager.GetTypes(typeof(HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.SymbolicExpressionGrammarBase)))
60        excludedTypes.Add(grammarType);
61    }
62
63    private readonly HashSet<Type> excludedTypes;
64
65    [TestMethod]
66    [TestCategory("General")]
67    [TestCategory("Essential")]
68    [TestProperty("Time", "long")]
69    public void TestCloningFinishedExperiment() {
70      Experiment experiment = (Experiment)serializer.Deserialize(@"Test Resources\SamplesExperimentFinished.hl");
71
72      Experiment clone = (Experiment)experiment.Clone(new Cloner());
73      var intersections = CheckTotalInequality(experiment, clone).Where(x => x.GetType().FullName.StartsWith("HeuristicLab"));
74
75      Assert.IsTrue(ProcessEqualObjects(experiment, intersections));
76    }
77
78    [TestMethod]
79    [TestCategory("General")]
80    [TestCategory("Essential")]
81    [TestProperty("Time", "long")]
82    public void TestCloningAllDeepCloneables() {
83      PluginLoader.Assemblies.ToArray();
84      bool success = true;
85      foreach (Type deepCloneableType in ApplicationManager.Manager.GetTypes(typeof(IDeepCloneable))) {
86        // skip types that explicitely choose not to deep-clone every member
87        if (excludedTypes.Contains(deepCloneableType)) continue;
88        // test only types contained in HL plugin assemblies
89        if (!PluginLoader.Assemblies.Contains(deepCloneableType.Assembly)) continue;
90        // test only instantiable types
91        if (deepCloneableType.IsAbstract || !deepCloneableType.IsClass) continue;
92
93        IDeepCloneable item = null;
94        try {
95          item = (IDeepCloneable)Activator.CreateInstance(deepCloneableType, nonPublic: false);
96        } catch { continue; } // no default constructor
97
98        IDeepCloneable clone = null;
99        try {
100          clone = (IDeepCloneable)item.Clone(new Cloner());
101        } catch (Exception e) {
102          TestContext.WriteLine(Environment.NewLine + deepCloneableType.FullName + ":");
103          TestContext.WriteLine("ERROR! " + e.GetType().Name + @" was thrown during cloning.
104All IDeepCloneable items with a default constructor should be cloneable when using that constructor!");
105          success = false;
106          continue;
107        }
108        var intersections = CheckTotalInequality(item, clone).Where(x => x.GetType().FullName.StartsWith("HeuristicLab"));
109        if (!intersections.Any()) continue;
110
111        if (!ProcessEqualObjects(item, intersections))
112          success = false;
113      }
114      Assert.IsTrue(success, "There are potential errors in deep cloning objects.");
115    }
116
117    private IEnumerable<object> CheckTotalInequality(object original, object clone) {
118      var originalObjects = new HashSet<object>(original.GetObjectGraphObjects(excludeStaticMembers: true).Where(x => !x.GetType().IsValueType), new ReferenceEqualityComparer());
119      var clonedObjects = new HashSet<object>(clone.GetObjectGraphObjects(excludeStaticMembers: true).Where(x => !x.GetType().IsValueType), new ReferenceEqualityComparer());
120
121      return originalObjects.Intersect(clonedObjects, new ReferenceEqualityComparer());
122    }
123
124    private bool ProcessEqualObjects(IDeepCloneable item, IEnumerable<object> intersections) {
125      bool success = true;
126      bool headerWritten = false;
127
128      foreach (object o in intersections) {
129        string typeName = o.GetType().FullName;
130        if (excludedTypes.Contains(o.GetType())) {
131          //TestContext.WriteLine("Skipping excluded type " + typeName);
132        } else if (o is IDeepCloneable) {
133          string info = (o is IItem) ? ((IItem)o).ItemName + ((o is INamedItem) ? ", " + ((INamedItem)o).Name : String.Empty) : String.Empty;
134          if (!headerWritten) {
135            TestContext.WriteLine(Environment.NewLine + item.GetType().FullName + ":");
136            headerWritten = true;
137          }
138          TestContext.WriteLine("POTENTIAL ERROR! A DEEPCLONEABLE WAS NOT DEEP CLONED (" + info + "): " + typeName);
139          success = false;
140        } else {
141          Array array = o as Array;
142          if (array != null && array.Length == 0) continue; //arrays of length 0 are used inside empty collections
143          if (!headerWritten) {
144            TestContext.WriteLine(Environment.NewLine + item.GetType().FullName + ":");
145            headerWritten = true;
146          }
147          TestContext.WriteLine("WARNING: An object of type " + typeName + " is referenced in the original and in the clone.");
148        }
149      }
150      return success;
151    }
152  }
153}
Note: See TracBrowser for help on using the repository browser.