1 // 2 // Copyright (c) 2010-2025 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 using System; 8 using System.Linq; 9 using Antmicro.Renode.Core; 10 using Antmicro.Renode.PlatformDescription; 11 using NUnit.Framework; 12 using Antmicro.Renode.UnitTests.Mocks; 13 using static Antmicro.Renode.PlatformDescription.UserInterface.PlatformDescriptionMachineExtensions; 14 15 namespace Antmicro.Renode.UnitTests.PlatformDescription 16 { 17 [TestFixture] 18 public class UsingTests 19 { 20 [Test] ShouldFindVariableFromUsing()21 public void ShouldFindVariableFromUsing() 22 { 23 var a = @" 24 cpu1: Antmicro.Renode.UnitTests.Mocks.MockCPU"; 25 26 var source = @" 27 using ""A"" 28 cpu2: Antmicro.Renode.UnitTests.Mocks.MockCPU 29 OtherCpu: cpu1"; 30 31 ProcessSource(null, source, a); 32 } 33 34 [Test] ShouldNotFindLocalVariableFromUsing()35 public void ShouldNotFindLocalVariableFromUsing() 36 { 37 var a = @" 38 local cpu1: Antmicro.Renode.UnitTests.Mocks.MockCPU"; 39 40 var source = @" 41 using ""A"" 42 cpu2: Antmicro.Renode.UnitTests.Mocks.MockCPU 43 OtherCpu: cpu1"; 44 45 var exception = Assert.Throws<ParsingException>(() => ProcessSource(null, source, a)); 46 Assert.AreEqual(ParsingError.MissingReference, exception.Error); 47 } 48 49 [Test] ShouldFindVariableFromNestedUsing()50 public void ShouldFindVariableFromNestedUsing() 51 { 52 var source = @" 53 using ""A"" 54 cpu3: Antmicro.Renode.UnitTests.Mocks.MockCPU 55 OtherCpu: cpu2"; 56 57 var a = @" 58 using ""B"" 59 cpu2: Antmicro.Renode.UnitTests.Mocks.MockCPU 60 OtherCpu: cpu1"; 61 62 var b = @" 63 cpu1: Antmicro.Renode.UnitTests.Mocks.MockCPU"; 64 65 ProcessSource(null, source, a, b); 66 } 67 68 [Test] ShouldAllowReverseVariableDependency()69 public void ShouldAllowReverseVariableDependency() 70 { 71 var source = @" 72 using ""A"" 73 otherCpu: Antmicro.Renode.UnitTests.Mocks.MockCPU"; 74 75 var a = @" 76 cpu: Antmicro.Renode.UnitTests.Mocks.MockCPU 77 OtherCpu: otherCpu"; 78 79 ProcessSource(null, source, a); 80 } 81 82 [Test] ShouldFindPrefixedVariable()83 public void ShouldFindPrefixedVariable() 84 { 85 var source = @" 86 using ""A"" prefixed ""a_"" 87 cpu: Antmicro.Renode.UnitTests.Mocks.MockCPU 88 OtherCpu: a_cpu"; 89 90 var a = @" 91 cpu: Antmicro.Renode.UnitTests.Mocks.MockCPU"; 92 93 ProcessSource(null, source, a); 94 } 95 96 [Test] ShouldFindNestedPrefixedVariable()97 public void ShouldFindNestedPrefixedVariable() 98 { 99 var source = @" 100 using ""A"" prefixed ""a_"" 101 using ""B"" 102 someCpu: Antmicro.Renode.UnitTests.Mocks.MockCPU 103 OtherCpu: a_b_cpu 104 105 oneMoreCpu: Antmicro.Renode.UnitTests.Mocks.MockCPU { OtherCpu: cpu } 106 "; 107 108 var a = @" 109 using ""B"" prefixed ""b_"""; 110 111 var b = @" 112 cpu: Antmicro.Renode.UnitTests.Mocks.MockCPU"; 113 114 ProcessSource(null, source, a, b); 115 } 116 117 [Test] ShouldFollowAttributeOverrideOrder0()118 public void ShouldFollowAttributeOverrideOrder0() 119 { 120 var source = @" 121 using ""A"" 122 using ""B"" 123 cpu: Antmicro.Renode.UnitTests.Mocks.MockCPU @ sysbus 0x0 124 Placeholder: ""set by source first"" 125 126 cpu: 127 Placeholder: ""set by source second"" 128 "; 129 130 var a = @" 131 cpu: 132 Placeholder: ""set by A"" 133 "; 134 135 var b = @" 136 using ""C"" 137 cpu: 138 Placeholder: ""set by B"" 139 "; 140 141 var c = @" 142 cpu: 143 Placeholder: ""set by C"" 144 "; 145 146 var machine = new Machine(); 147 ProcessSource(machine, source, a, b, c); 148 MockCPU mock; 149 Assert.IsTrue(machine.TryGetByName("sysbus.cpu", out mock)); 150 Assert.AreEqual("set by source second", mock.Placeholder); 151 } 152 153 [Test] ShouldFollowAttributeOverrideOrder1()154 public void ShouldFollowAttributeOverrideOrder1() 155 { 156 var source = @" 157 using ""A"" 158 using ""B"" 159 cpu: Antmicro.Renode.UnitTests.Mocks.MockCPU @ sysbus 160 "; 161 162 var a = @" 163 cpu: 164 Placeholder: ""set by A first"" 165 cpu: 166 Placeholder: ""set by A second"" 167 "; 168 169 var b = @" 170 using ""C"" 171 cpu: 172 Placeholder: ""set by B first"" 173 cpu: 174 Placeholder: ""set by B second"" 175 "; 176 177 var c = @" 178 cpu: 179 Placeholder: ""set by C first"" 180 cpu: 181 Placeholder: ""set by C second"" 182 "; 183 184 var machine = new Machine(); 185 ProcessSource(machine, source, a, b, c); 186 MockCPU mock; 187 Assert.IsTrue(machine.TryGetByName("sysbus.cpu", out mock)); 188 Assert.AreEqual("set by B second", mock.Placeholder); 189 } 190 191 [Test] ShouldFollowAttributeOverrideOrder2()192 public void ShouldFollowAttributeOverrideOrder2() 193 { 194 var source = @" 195 using ""A"" 196 cpu: Antmicro.Renode.UnitTests.Mocks.MockCPU @ sysbus 0x0 197 "; 198 199 var a = @" 200 using ""B"" 201 cpu: 202 Placeholder: ""set by A"" 203 "; 204 205 var b = @" 206 cpu: 207 Placeholder: ""set by B"" 208 "; 209 210 var machine = new Machine(); 211 ProcessSource(machine, source, a, b); 212 MockCPU mock; 213 Assert.IsTrue(machine.TryGetByName("sysbus.cpu", out mock)); 214 Assert.AreEqual("set by A", mock.Placeholder); 215 } 216 217 [Test] ShouldFollowAttributeOverrideOrder3()218 public void ShouldFollowAttributeOverrideOrder3() 219 { 220 var source = @" 221 using ""A"" 222 using ""B"" 223 using ""C"" 224 cpu: Antmicro.Renode.UnitTests.Mocks.MockCPU @ sysbus 225 "; 226 227 var a = @" 228 cpu: 229 Placeholder: ""set by A first"" 230 cpu: 231 Placeholder: ""set by A second"" 232 "; 233 234 var b = @" 235 cpu: 236 Placeholder: ""set by B first"" 237 cpu: 238 Placeholder: ""set by B second"" 239 "; 240 var c = @" 241 using ""A""; 242 "; 243 244 var machine = new Machine(); 245 ProcessSource(machine, source, a, b, c); 246 MockCPU mock; 247 Assert.IsTrue(machine.TryGetByName("sysbus.cpu", out mock)); 248 Assert.AreEqual("set by A second", mock.Placeholder); 249 } 250 251 [Test] ShouldFollowAttributeOverrideOrder4()252 public void ShouldFollowAttributeOverrideOrder4() 253 { 254 var source = @" 255 using ""A"" 256 using ""B"" 257 cpu: Antmicro.Renode.UnitTests.Mocks.MockCPU @ sysbus 258 "; 259 260 var a = @" 261 cpu: 262 Placeholder: ""set by A first"" 263 cpu: 264 Placeholder: ""set by A second"" 265 "; 266 267 var b = @" 268 using ""A"" 269 cpu: 270 Placeholder: ""set by B first"" 271 cpu: 272 Placeholder: ""set by B second"" 273 "; 274 275 var machine = new Machine(); 276 ProcessSource(machine, source, a, b); 277 MockCPU mock; 278 Assert.IsTrue(machine.TryGetByName("sysbus.cpu", out mock)); 279 Assert.AreEqual("set by B second", mock.Placeholder); 280 } 281 282 [Test] ShouldFailOnDuplicateUsingEntry()283 public void ShouldFailOnDuplicateUsingEntry() 284 { 285 var source = @" 286 using ""A"" 287 using ""B"" 288 using ""A"" 289 cpu: Antmicro.Renode.UnitTests.Mocks.MockCPU @ sysbus 290 "; 291 292 var a = @" 293 cpu: 294 Placeholder: ""set by A first"" 295 cpu: 296 Placeholder: ""set by A second"" 297 "; 298 299 var b = @" 300 cpu: 301 Placeholder: ""set by B first"" 302 cpu: 303 Placeholder: ""set by B second"" 304 "; 305 306 var exception = Assert.Throws<ParsingException>(() => ProcessSource(null, source, a, b)); 307 Assert.AreEqual(ParsingError.DuplicateUsing, exception.Error); 308 } 309 310 [Test] ShouldHandleIrqDestinationOnPrefixing()311 public void ShouldHandleIrqDestinationOnPrefixing() 312 { 313 var a = @" 314 cpu: Antmicro.Renode.UnitTests.Mocks.MockReceiver 315 sender: Antmicro.Renode.UnitTests.Mocks.MockIrqSender 316 Irq -> cpu@0"; 317 318 var source = @" 319 using ""A"" prefixed ""sth_"""; 320 321 ProcessSource(null, source, a); 322 } 323 324 [Test] ShouldFailOnRecurringUsings()325 public void ShouldFailOnRecurringUsings() 326 { 327 var b = @" 328 using ""A"" 329 p: Antmicro.Renode.UnitTests.Mocks.EmptyPeripheral"; 330 331 var a = @" 332 using ""B"" 333 p2: Antmicro.Renode.UnitTests.Mocks.EmptyPeripheral"; 334 335 var source = @" 336 using ""B"" 337 p3: Antmicro.Renode.UnitTests.Mocks.EmptyPeripheral"; 338 339 var exception = Assert.Throws<ParsingException>(() => ProcessSource(null, source, a, b)); 340 Assert.AreEqual(ParsingError.RecurringUsing, exception.Error); 341 } 342 343 [Test] ShouldFailOnDirectlyRecurringUsings()344 public void ShouldFailOnDirectlyRecurringUsings() 345 { 346 var a = @" 347 using ""A"" 348 p: Antmicro.Renode.UnitTests.Mocks.EmptyPeripheral"; 349 350 var source = @" 351 using ""A"" 352 p2: Antmicro.Renode.UnitTests.Mocks.EmptyPeripheral"; 353 354 var exception = Assert.Throws<ParsingException>(() => ProcessSource(null, source, a)); 355 Assert.AreEqual(ParsingError.RecurringUsing, exception.Error); 356 } 357 358 [Test] ShouldFailOnNonExistingUsingFile()359 public void ShouldFailOnNonExistingUsingFile() 360 { 361 var source = @" 362 using ""A"""; 363 364 var exception = Assert.Throws<ParsingException>(() => ProcessSource(null, source)); 365 Assert.AreEqual(ParsingError.UsingFileNotFound, exception.Error); 366 } 367 368 #if PLATFORM_WINDOWS 369 [Test] ShouldHandleAbsolutePath()370 public void ShouldHandleAbsolutePath() 371 { 372 // On Windows, both \ and / should work as path component separators in the path to be resolved 373 // and the returned path should always use the preferred \ separator 374 Assert.AreEqual(@"C:\tmp\platform.repl", ResolvePath(@"C:\tmp\platform.repl", @"C:\tmp\includer.repl")); 375 Assert.AreEqual(@"C:\tmp\platform.repl", ResolvePath(@"C:/tmp/platform.repl", @"C:\tmp\includer.repl")); 376 } 377 378 [Test] ShouldHandleRelativePathInSameDirectory()379 public void ShouldHandleRelativePathInSameDirectory() 380 { 381 Assert.AreEqual(@"C:\tmp\platform.repl", ResolvePath(@".\platform.repl", @"C:\tmp\includer.repl")); 382 Assert.AreEqual(@"C:\tmp\platform.repl", ResolvePath(@"./platform.repl", @"C:\tmp\includer.repl")); 383 } 384 385 [Test] ShouldHandleRelativePathInParentDirectory()386 public void ShouldHandleRelativePathInParentDirectory() 387 { 388 Assert.AreEqual(@"C:\abc\platform.repl", ResolvePath(@"..\abc\platform.repl", @"C:\tmp\includer.repl")); 389 Assert.AreEqual(@"C:\abc\platform.repl", ResolvePath(@"../abc/platform.repl", @"C:\tmp\includer.repl")); 390 } 391 #else 392 [Test] ShouldHandleAbsolutePath()393 public void ShouldHandleAbsolutePath() 394 { 395 Assert.AreEqual("/tmp/platform.repl", ResolvePath("/tmp/platform.repl", "/tmp/includer.repl")); 396 } 397 398 [Test] ShouldHandleRelativePathInSameDirectory()399 public void ShouldHandleRelativePathInSameDirectory() 400 { 401 Assert.AreEqual("/tmp/platform.repl", ResolvePath("./platform.repl", "/tmp/includer.repl")); 402 } 403 404 [Test] ShouldHandleRelativePathInParentDirectory()405 public void ShouldHandleRelativePathInParentDirectory() 406 { 407 Assert.AreEqual("/abc/platform.repl", ResolvePath("../abc/platform.repl", "/tmp/includer.repl")); 408 } 409 410 [Test] BackslashShouldNotBePathSeparatorOnUnix()411 public void BackslashShouldNotBePathSeparatorOnUnix() 412 { 413 // Backslashes are a valid filename character on Unix 414 Assert.AreEqual(@"/tmp/plat\form.repl", ResolvePath(@"./plat\form.repl", "/tmp/includer.repl")); 415 } 416 #endif 417 418 [SetUp] SetUp()419 public void SetUp() 420 { 421 resolver = new UsingResolver(Enumerable.Empty<string>()); 422 } 423 ProcessSource(Machine machine, params string[] sources)424 private static void ProcessSource(Machine machine, params string[] sources) 425 { 426 var letters = Enumerable.Range(0, sources.Length - 1).Select(x => (char)('A' + x)).ToArray(); 427 var usingResolver = new FakeUsingResolver(); 428 for(var i = 1; i < sources.Length; i++) 429 { 430 usingResolver.With(letters[i - 1].ToString(), sources[i]); 431 } 432 var creationDriver = new CreationDriver(machine ?? new Machine(), usingResolver, new FakeInitHandler()); 433 creationDriver.ProcessDescription(sources[0]); 434 } 435 ResolvePath(string path, string includingPath)436 private string ResolvePath(string path, string includingPath) 437 { 438 return resolver.Resolve(path, includingPath); 439 } 440 441 private UsingResolver resolver; 442 } 443 } 444