File: TestConfig.pm

package info (click to toggle)
sqitch 1.1.0000-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 3,576 kB
  • sloc: perl: 35,035; sql: 2,340; makefile: 4
file content (148 lines) | stat: -rw-r--r-- 4,955 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package TestConfig;
use strict;
use warnings;
use base 'App::Sqitch::Config';
use Path::Class;

# Creates and returns a new TestConfig, which inherits from
# App::Sqitch::Config. Sets nonexistent values for the file locations and
# calls update() on remaining args.
#
#   my $config = TestConfig->new(
#      'core.engine'      => 'sqlite',
#      'add.all'          => 1,
#      'deploy.variables' => { _prefix => 'test_', user => 'bob' }
#      'foo.bar'          => [qw(one two three)],
#  );
sub new {
    my $self = shift->SUPER::new;
    $self->{test_local_file}  = 'nonexistent.local';
    $self->{test_user_file}   = 'nonexistent.user';
    $self->{test_system_file} = 'nonexistent.system';
    $self->update(@_);
    return $self;
}

# Pass in key/value pairs to set the data. Does not clear existing data. Keys
# should be "$section.$name". Values can be scalars, arrays, or hashes.
# Scalars are simply set as-is, unless the value is `undef`, in which case the
# key is deleted. Arrays are set as multiple values for the key. Hashes have
# each of their keys appended as "$section.$name.$key", with the values
# assigned as-is. Existing keys will be replaced with the new values.
#
#   my $config->update(
#      'core.engine'      => 'sqlite',
#      'add.all'          => 1,
#      'deploy.variables' => { _prefix => 'test_', user => 'bob' }
#      'foo.bar'          => [qw(one two three)],
#  );
sub update {
    my $self = shift;
    my %p = @_ or return;
    $self->data({}) unless $self->is_loaded;
    # Set a unique origin to be sure to override any previous values for each key.
    my @args = (origin => ('update_' . ++$self->{__update}));

    while (my ($k, $v) = each %p) {
        my $ref = ref $v;
        if ($ref eq '') {
            if (defined $v) {
                $k =~ s/[.]([^.]+)$//;
                $self->define(@args, section => $k, name => $1, value => $v);
            } else {
                $self->set_multiple( $k, 0 ) if $self->is_multiple( $k );
                $k = lc $k;
                delete $_->{$k} for ($self->origins, $self->data, $self->casing);
            }
        } elsif ($ref eq 'HASH') {
            $self->define(@args, section => $k, name => $_, value => $v->{$_} )
                for keys %{ $v };
        } elsif ($ref eq 'ARRAY') {
            $k =~ s/[.]([^.]+)$//;
            $self->define(@args, section => $k, name => $1, value => $_)
                for @{ $v };
        } else {
            require Carp;
            Carp::confess("Cannot set config value of type $ref");
        }
    }
}

# Like update(), but replaces all existing data with new data.
sub replace {
    my $self = shift;
    $self->data({});
    $self->multiple({});
    $self->origins({});
    $self->casing({});
    $self->config_files([]);
    $self->update(@_);
}

# Creates and returns a new TestConfig, which inherits from
# App::Sqitch::Config. Parameters specify files to load using the keys "local",
# "user", and "system". Any file not specified will be set to a nonexistent
# value. Once the files are set, the data is loaded from the files and the
# TestObject returned.
#
#   my $config = TestObject->from(
#      local  => 'test.conf',
#      user   => 'user.conf',
#      system => 'system.conf',
#   );
sub from {
    my ($class, %p) = @_;
    my $self = shift->SUPER::new;
    for my $level (qw(local user system)) {
        $self->{"test_${level}_file"} = $p{$level} || "nonexistent.$level";
    }
    $self->load;
    return $self;
}

# Creates and returns a Test::MockModule object that can be used to mock
# methods on the TestConfig class. Pass pairs of parameters to be passed on to
# the mock() method of the Test::MockModule object before returning.
#
# my $sysdir = dir 'nonexistent';
# my $usrdir = dir 'nonexistent';
# my $mock = TestConfig->mock(
#     system_dir => sub { $sysdir },
#     user_dir   => sub { $usrdir },
# );
sub mock {
    my $class = shift;
    require Test::MockModule;
    my $mocker = Test::MockModule->new($class);
    $mocker->mock(shift, shift) while @_;
    return $mocker;
}

# Returns the test local file.
sub local_file  { file $_[0]->{test_local_file}  }

# Returns the test user file.
sub user_file   { file $_[0]->{test_user_file}   }

# Returns the test system file.
sub system_file { file $_[0]->{test_system_file} }

# Overrides the parent implementation to load only the local file, to avoid
# inadvertent loading of configuration files in parent directories. Unlikely
# to be called directly by tests.
sub load_dirs   {
    my $self = shift;
    # Exclude files in parent directories.
    $self->load_file($self->local_file);
}

# Parses the specified configuration file and returns a hash reference. May be
# called as either a class or instance method; in neither case is the data
# stored anywhere other than the returned hash reference.
sub data_from {
    my $conf = shift->SUPER::new;
    $conf->load_file(shift);
    $conf->data;
}

1;