|
14 | 14 | */ |
15 | 15 |
|
16 | 16 | using NUnit.Framework; |
| 17 | +using Python.Runtime; |
17 | 18 | using QuantConnect.Statistics; |
18 | 19 | using System.Collections.Generic; |
| 20 | +using System.Linq; |
19 | 21 |
|
20 | 22 | namespace QuantConnect.Tests.Common |
21 | 23 | { |
@@ -58,5 +60,98 @@ public void RunPythonDictionaryFeatureRegressionAlgorithm() |
58 | 60 | parameter.ExpectedFinalStatus, |
59 | 61 | initialCash: 100000); |
60 | 62 | } |
| 63 | + |
| 64 | + [Test] |
| 65 | + public void ExtendedDictionaryBehavesAsPythonDictionary() |
| 66 | + { |
| 67 | + using var _ = Py.GIL(); |
| 68 | + |
| 69 | + var module = PyModule.FromString("ExtendedDictionaryBehavesAsPythonDictionary", |
| 70 | + @" |
| 71 | +from QuantConnect.Tests.Common import ExtendedDictionaryTests |
| 72 | +
|
| 73 | +def contains(dictionary, key): |
| 74 | + return key in dictionary |
| 75 | +
|
| 76 | +def get(dictionary, key): |
| 77 | + return dictionary.get(key) |
| 78 | +
|
| 79 | +def keys(dictionary): |
| 80 | + return dictionary.keys() |
| 81 | +
|
| 82 | +def values(dictionary): |
| 83 | + return dictionary.values() |
| 84 | +
|
| 85 | +def pop(dictionary, key): |
| 86 | + return dictionary.pop(key) |
| 87 | +"); |
| 88 | + |
| 89 | + var dict = new TestDictionary |
| 90 | + { |
| 91 | + ["a"] = 1, |
| 92 | + ["b"] = 2, |
| 93 | + ["c"] = 3 |
| 94 | + }; |
| 95 | + using var pyDict = dict.ToPython(); |
| 96 | + |
| 97 | + var expectedKeys = new[] { "a", "b", "c" }; |
| 98 | + var keys = module.InvokeMethod("keys", pyDict).GetAndDispose<List<string>>(); |
| 99 | + CollectionAssert.AreEquivalent(expectedKeys, keys); |
| 100 | + |
| 101 | + var expectedValues = new[] { 1, 2, 3 }; |
| 102 | + var values = module.InvokeMethod("values", pyDict).GetAndDispose<List<int>>(); |
| 103 | + CollectionAssert.AreEquivalent(expectedValues, values); |
| 104 | + |
| 105 | + foreach (var (key, value) in keys.Zip(values)) |
| 106 | + { |
| 107 | + using var pyKey = key.ToPython(); |
| 108 | + Assert.IsTrue(module.InvokeMethod("contains", pyDict, pyKey).As<bool>()); |
| 109 | + Assert.AreEqual(value, module.InvokeMethod("get", pyDict, pyKey).As<int>()); |
| 110 | + } |
| 111 | + |
| 112 | + using var pyNonExistingKey = "d".ToPython(); |
| 113 | + Assert.IsFalse(module.InvokeMethod("contains", pyDict, pyNonExistingKey).As<bool>()); |
| 114 | + Assert.IsFalse(module.InvokeMethod("contains", pyDict, PyObject.None).As<bool>()); |
| 115 | + |
| 116 | + using var pyExistingKey = keys[0].ToPython(); |
| 117 | + using var pyExistingValue = values[0].ToPython(); |
| 118 | + var popped = module.InvokeMethod("pop", pyDict, pyExistingKey).As<int>(); |
| 119 | + Assert.AreEqual(1, popped); |
| 120 | + Assert.IsFalse(module.InvokeMethod("contains", pyDict, pyExistingKey).As<bool>()); |
| 121 | + } |
| 122 | + |
| 123 | + public class TestDictionary : ExtendedDictionary<string, int> |
| 124 | + { |
| 125 | + private readonly Dictionary<string, int> _data = new(); |
| 126 | + |
| 127 | + public override int Count => _data.Count; |
| 128 | + |
| 129 | + public override bool IsReadOnly => false; |
| 130 | + |
| 131 | + public override int this[string key] |
| 132 | + { |
| 133 | + get => _data[key]; |
| 134 | + set => _data[key] = value; |
| 135 | + } |
| 136 | + |
| 137 | + protected override IEnumerable<string> GetKeys => _data.Keys; |
| 138 | + |
| 139 | + protected override IEnumerable<int> GetValues => _data.Values; |
| 140 | + |
| 141 | + public override bool TryGetValue(string key, out int value) |
| 142 | + { |
| 143 | + return _data.TryGetValue(key, out value); |
| 144 | + } |
| 145 | + |
| 146 | + public override bool ContainsKey(string key) |
| 147 | + { |
| 148 | + return _data.ContainsKey(key); |
| 149 | + } |
| 150 | + |
| 151 | + public override bool Remove(string key) |
| 152 | + { |
| 153 | + return _data.Remove(key); |
| 154 | + } |
| 155 | + } |
61 | 156 | } |
62 | 157 | } |
0 commit comments