| 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
 | RSpec.describe ComplianceControlSetCloner do
  subject{ described_class.new }
  let( :new_organisation ){ create :organisation }
  let( :source_set ){ create :compliance_control_set }
  let( :set_prefix ){ I18n.t('compliance_control_sets.clone.prefix') }
  let( :block_prefix ){ I18n.t('compliance_control_blocks.clone.prefix') }
  context 'Copying empty set' do
    context 'correct organisation' do
      #
      #
      #
      #
      #
      #
      #
      #                                                 +-------------------+
      #          +---------------------+----------------| Control (direct0) |
      #          |                     |                +-------------------+
      #          |                     |
      #          |                     |                +-------------------+
      #          +---------------------)------------+---| Control (direct1) |
      #          |                     |            |   +-------------------+
      #          |                     |            |
      #          |                     |            |   +-------------------+
      #          +---------------------)------------)---| Control (direct2) |
      #          |                     |            |   +-------------------+
      #          |                     |            |
      #          |                     |            |
      #          |                     |            |
      #          v                     v            |
      #   +------------+          +--------------+  |  +---------------------+
      #   | ControlSet |<----+----| ControlBlock |<-)--| Control (indirect0) |
      #   +------------+     |    +--------------+  |  +---------------------+
      #                      |                      |
      #                      |    +--------------+<-+  +---------------------+
      #                      |<---| ControlBlock |<----| Control (indirect1) |
      #                      |    +--------------+     +---------------------+
      #                      |
      #                      |    +--------------+     +---------------------+
      #                      +----| ControlBlock |<----| Control (indirect2) |
      #                           +--------------+     +---------------------+
      context 'Directed Acyclic Graph is copied correctly' do
        let(:source_blox){
          3.times.map{ |n| create :compliance_control_block, compliance_control_set: source_set, transport_mode: StifTransportModeEnumerations.transport_modes[n], transport_submode: StifTransportSubmodeEnumerations.transport_submodes[n]   }
        }
        let(:direct_ccs){
          3.times.map{ |n| create :generic_attribute_control_min_max, compliance_control_set: source_set, name: "direct #{n.succ}", code: "direct-#{n.succ}" }
        }
        # Needed to check we do not dulicate a node (compliance_control) twice
        let(:indirect_ccs){
          # Create 1 child for each block and also associate first of the direct ccs to the first block
          #                                                  seconf of the direct css to the second block
          source_blox.take(2).zip(direct_ccs.take(2)).each do | source_block, cc |
            cc.update compliance_control_block_id: source_block.id
          end
          source_blox.each_with_index.map{ | source_block, n |
            create(:generic_attribute_control_min_max, compliance_control_set: source_set, compliance_control_block: source_block, name: "indirect #{n.succ}", code: "indirect-#{n.succ}")
          }
        }
        let( :sources ){ source_set.compliance_controls.order(:id) }
        let( :target_set ){ ComplianceControlSet.last }
        let( :target_blox ){ ComplianceControlBlock.last 3 }
        let( :targets ){ target_set.compliance_controls.order(:id) }
        before do
          direct_ccs
          indirect_ccs
        end
        it 'correctly creates a set for a complete DAG' do
          # Slowness of tests constrains us to create a minimum of objects in the DB,
          # hence only one example :(
          #
          #  Execute copy and keep count
          counts = object_counts
          subject.copy(source_set.id, new_organisation.id)
          delta  = count_diff counts, object_counts
          # Check correctly copied set
          expect(target_set.organisation).to eq(new_organisation)
          expect(target_set.name).to eq( [set_prefix, source_set.name].join(' ') )
          # Check correctly copied controls
          targets.zip(sources).each do | target, source |
            expect( target.code ).to eq(source.code )
            expect( target.comment ).to eq(source.comment )
            expect( target.compliance_control_set ).to eq( target_set )
            expect( target.control_attributes ).to eq(source.control_attributes)
            expect( target.criticity ).to eq(source.criticity )
            expect( target.name ).to eq(source.name)
            expect( target.origin_code ).to eq(source.origin_code )
            expect( target.type ).to eq(source.type)
          end
          # Check correctly copied blocks
          target_blox.zip(source_blox).each do | target_block, source_block |
            expect( target_block.compliance_control_set ).to eq(target_set)
            expect( target_block.name ).to eq(source_block.name)
            expect( target_block.condition_attributes ).to eq( source_block.condition_attributes )
          end
          # Check correct block associations
          # See diagram above to understand the meaning of this:
          #   - The first two controls have been assigned to the first two blocks accordingly
          #   - The third has no block
          #   - The last three controls have been created from the three blocks in order
          expected_block_ids = target_blox.take(2).map(&:id) + [ nil ] + target_blox.map(&:id)
          expect( targets.pluck(:compliance_control_block_id) ).to eq( expected_block_ids )
          # Check overall counts (no additional creations)
          expect( delta ).to eq(counts)
        end
      end
    end
    def object_counts
      {
        source_set_count: ComplianceControlSet.count,
        cc_block_count: ComplianceControlBlock.count,
        cc_count: ComplianceControl.count,
        cck_set_count: ComplianceCheckSet.count,
        cck_block_count: ComplianceCheckBlock.count,
        cck_count: ComplianceCheck.count
      }
    end
    def count_diff count1, count2
      count1.inject({}){ |h, (k,v)|
        h.merge( k => count2[k] - v )
      }
    end
  end
end
 |