5

I need to test a feature that includes this line:

if $translate-nl && $*DISTRO.is-win

I have tried to reassign a value to $*DISTRO,

$*DISTRO='Windows 10';

but it says:

Cannot modify an immutable Distro (debian (9.stretch))␤

$*DISTRO is a dynamic variable, and it makes sense that it's not modified. That said, is there any other way that code can be tested (other than going to Windows, of course)

Scimon Proctor
  • 4,558
  • 23
  • 22
jjmerelo
  • 22,578
  • 8
  • 40
  • 86

3 Answers3

6
my $*DISTRO = ...

Hopefully modifying the original is unnecessary. It's generally unreasonable action-at-a-distance -- almost certainly so if someone has arranged for it to be an immutable value. This is the reason why global variables got such a bad reputation.

raiph
  • 31,607
  • 3
  • 62
  • 111
6

To elaborate on raiph's answer: the * in $*DISTRO marks it as a dynamic variable. You can re-declare it any scope, and code called from there will see the redeclared value:

{
    my $*DISTRO = ...;
    # coded called from here sees the redeclared value
}
# code called from here sees the original value

Now, the question remains, what do you put in place of these pesky ...?

In the simplest case, a mock that just has whatever the code under test needs:

{
    my class Distro { has $.is-win }
    my $*DISTRO = Distro.new( :is-win );
    # call your test code here
}

If the code needs more attributes in Distro, just add them to the mock Distro class.

If the code needs a "real* Distro object, for some reason, you can instantiate the built-in one. The constructor .new isn't really documented, but the source code makes it pretty obvious what arguments it expects.

moritz
  • 12,710
  • 1
  • 41
  • 63
-2

OK, I got the answer relatively fast. $*DISTRO is actually a read-only alias of PROCESS::<$DISTRO>

So we only need to do:

my $*DISTRO = Distro.new(:is-win,:release<11>,:path-sep('|||'),:auth<unknown>,:name<mswin32>,:desc<Test>,:version<v11>);
say $*DISTRO.is-win; #OUTPUT: «True␤»
jjmerelo
  • 22,578
  • 8
  • 40
  • 86
  • 2
    No, I wouldn't do that as that is the very definition of "action-at-a-distance": this would then apply to *all* code running for all threads. The correct way to do this is by doing `my $*DISTRO = Distro.new(:is-win,:release<11>,:path-sep('|||'),:auth,:name,:desc,:version);` in the scope that you need to have `$*DISTRO` pretend that it's a Windows system. – Elizabeth Mattijsen Aug 08 '18 at 09:44