1# Copyright (c) Meta Platforms, Inc. and affiliates.
2#
3# This source code is licensed under the MIT license found in the
4# LICENSE file in the root directory of this source tree.
5
6require "test/unit"
7require_relative "../codegen.rb"
8require_relative "./test_utils/PodMock.rb"
9require_relative "./test_utils/PathnameMock.rb"
10require_relative "./test_utils/FileMock.rb"
11require_relative "./test_utils/DirMock.rb"
12require_relative "./test_utils/systemUtils.rb"
13require_relative "./test_utils/CodegenUtilsMock.rb"
14
15class CodegenTests < Test::Unit::TestCase
16    :third_party_provider_header
17    :third_party_provider_implementation
18    :base_path
19    :prefix
20    :tmp_schema_list_file
21
22    def setup
23        Pod::Config.reset()
24
25        @prefix = "../.."
26        @third_party_provider_header = "RCTThirdPartyFabricComponentsProvider.h"
27        @third_party_provider_implementation = "RCTThirdPartyFabricComponentsProvider.mm"
28        @base_path = "~/app/ios"
29        @tmp_schema_list_file = "tmpSchemaList.txt"
30        Pathname.pwd!(@base_path)
31        Pod::Config.instance.installation_root.relative_path_from = @base_path
32    end
33
34    def teardown
35        system_reset_commands()
36        Pod::UI.reset()
37        Pod::Executable.reset()
38        Pathname.reset()
39        FileMock.reset()
40        DirMock.reset()
41    end
42
43    # ============================================== #
44    # Test - setup_fabric #
45    # ============================================== #
46    def testCheckAndGenerateEmptyThirdPartyProvider_whenFileAlreadyExists_doNothing()
47
48        # Arrange
49        FileMock.mocked_existing_files([
50            @prefix + "/React/Fabric/" + @third_party_provider_header,
51            @prefix + "/React/Fabric/" + @third_party_provider_implementation,
52        ])
53
54        # Act
55        checkAndGenerateEmptyThirdPartyProvider!(@prefix, false, dir_manager: DirMock, file_manager: FileMock)
56
57        # Assert
58        assert_equal(Pathname.pwd_invocation_count, 1)
59        assert_equal(Pod::Config.instance.installation_root.relative_path_from_invocation_count, 1)
60        assert_equal(FileMock.exist_invocation_params, [
61            @prefix + "/React/Fabric/" + @third_party_provider_header,
62            @prefix + "/React/Fabric/" + @third_party_provider_implementation,
63        ])
64        assert_equal(DirMock.exist_invocation_params, [])
65        assert_equal(Pod::UI.collected_messages, [])
66        assert_equal($collected_commands, [])
67        assert_equal(FileMock.open_files.length, 0)
68        assert_equal(Pod::Executable.executed_commands.length, 0)
69    end
70
71    def testCheckAndGenerateEmptyThirdPartyProvider_whenHeaderMissingAndCodegenMissing_raiseError()
72
73        # Arrange
74        FileMock.mocked_existing_files([
75            @base_path + "/build/" + @third_party_provider_implementation,
76        ])
77
78        # Act
79        assert_raise {
80            checkAndGenerateEmptyThirdPartyProvider!(@prefix, false, dir_manager: DirMock, file_manager: FileMock)
81        }
82
83        # Assert
84        assert_equal(Pathname.pwd_invocation_count, 1)
85        assert_equal(Pod::Config.instance.installation_root.relative_path_from_invocation_count, 1)
86        assert_equal(FileMock.exist_invocation_params, [
87            @prefix + "/React/Fabric/" + @third_party_provider_header
88        ])
89        assert_equal(DirMock.exist_invocation_params, [
90            @base_path + "/"+ @prefix + "/../react-native-codegen",
91            @base_path + "/"+ @prefix + "/../@react-native/codegen",
92        ])
93        assert_equal(Pod::UI.collected_messages, [])
94        assert_equal($collected_commands, [])
95        assert_equal(FileMock.open_files.length, 0)
96        assert_equal(Pod::Executable.executed_commands.length, 0)
97    end
98
99    def testCheckAndGenerateEmptyThirdPartyProvider_whenImplementationMissingAndCodegenrepoExists_dontBuildCodegen()
100
101        # Arrange
102        FileMock.mocked_existing_files([
103            @prefix + "/React/Fabric/" + @third_party_provider_header,
104            @prefix + "/React/Fabric/tmpSchemaList.txt"
105        ])
106
107        DirMock.mocked_existing_dirs([
108            @base_path + "/"+ @prefix + "/../react-native-codegen",
109            @base_path + "/"+ @prefix + "/../react-native-codegen/lib"
110        ])
111
112        # Act
113        checkAndGenerateEmptyThirdPartyProvider!(@prefix, false, dir_manager: DirMock, file_manager: FileMock)
114
115        # Assert
116        assert_equal(Pathname.pwd_invocation_count, 1)
117        assert_equal(Pod::Config.instance.installation_root.relative_path_from_invocation_count, 1)
118        assert_equal(FileMock.exist_invocation_params, [
119            @prefix + "/React/Fabric/" + @third_party_provider_header,
120            @prefix + "/React/Fabric/" + @third_party_provider_implementation,
121            @prefix + "/React/Fabric/tmpSchemaList.txt",
122        ])
123        assert_equal(DirMock.exist_invocation_params, [
124            @base_path + "/"+ @prefix + "/../react-native-codegen",
125            @base_path + "/"+ @prefix + "/../react-native-codegen/lib",
126        ])
127        assert_equal(Pod::UI.collected_messages, ["[Codegen] generating an empty RCTThirdPartyFabricComponentsProvider"])
128        assert_equal($collected_commands, [])
129        assert_equal(FileMock.open_invocation_count, 1)
130        assert_equal(FileMock.open_files_with_mode[@prefix + "/React/Fabric/tmpSchemaList.txt"], 'w')
131        assert_equal(FileMock.open_files[0].collected_write, ["[]"])
132        assert_equal(FileMock.open_files[0].fsync_invocation_count, 1)
133        assert_equal(Pod::Executable.executed_commands[0], {
134            "command" => "node",
135            "arguments" => [
136                @base_path + "/" + @prefix + "/scripts/generate-provider-cli.js",
137                "--platform", 'ios',
138                "--schemaListPath", @prefix + "/React/Fabric/tmpSchemaList.txt",
139                "--outputDir", @prefix + "/React/Fabric"
140            ]
141        })
142        assert_equal(FileMock.delete_invocation_count, 1)
143        assert_equal(FileMock.deleted_files, [ @prefix + "/React/Fabric/tmpSchemaList.txt"])
144    end
145
146    def testCheckAndGenerateEmptyThirdPartyProvider_whenBothMissing_buildCodegen()
147        # Arrange
148        codegen_cli_path = @base_path + "/" + @prefix + "/../@react-native/codegen"
149        DirMock.mocked_existing_dirs([
150            codegen_cli_path,
151        ])
152        # Act
153        checkAndGenerateEmptyThirdPartyProvider!(@prefix, false, dir_manager: DirMock, file_manager: FileMock)
154
155        # Assert
156        assert_equal(Pathname.pwd_invocation_count, 1)
157        assert_equal(Pod::Config.instance.installation_root.relative_path_from_invocation_count, 1)
158        assert_equal(FileMock.exist_invocation_params, [
159            @prefix + "/React/Fabric/" + @third_party_provider_header,
160            @prefix + "/React/Fabric/" + @tmp_schema_list_file
161        ])
162        assert_equal(DirMock.exist_invocation_params, [
163            @base_path + "/" + @prefix + "/../react-native-codegen",
164            codegen_cli_path,
165            codegen_cli_path + "/lib",
166        ])
167        assert_equal(Pod::UI.collected_messages, [
168            "[Codegen] building #{codegen_cli_path}.",
169            "[Codegen] generating an empty RCTThirdPartyFabricComponentsProvider"
170        ])
171        assert_equal($collected_commands, ["~/app/ios/../../../@react-native/codegen/scripts/oss/build.sh"])
172        assert_equal(FileMock.open_files[0].collected_write, ["[]"])
173        assert_equal(FileMock.open_files[0].fsync_invocation_count, 1)
174        assert_equal(Pod::Executable.executed_commands[0], {
175            "command" => "node",
176            "arguments" => [
177                @base_path + "/" + @prefix + "/scripts/generate-provider-cli.js",
178                "--platform", 'ios',
179                "--schemaListPath", @prefix + "/React/Fabric/" + @tmp_schema_list_file,
180                "--outputDir", @prefix + "/React/Fabric"
181            ]
182        })
183    end
184
185    # ================= #
186    # Test - RunCodegen #
187    # ================= #
188    def testRunCodegen_whenNewArchEnabled_runsCodegen
189        # Arrange
190        app_path = "~/app"
191        config_file = ""
192        codegen_utils_mock = CodegenUtilsMock.new()
193
194        # Act
195        run_codegen!(app_path, config_file, :new_arch_enabled => true, :codegen_utils => codegen_utils_mock)
196
197        # Assert
198        assert_equal(codegen_utils_mock.use_react_native_codegen_discovery_params, [{
199            :app_path=>"~/app",
200            :codegen_disabled=>false,
201            :codegen_output_dir=>"build/generated/ios",
202            :config_file_dir=>"",
203            :fabric_enabled=>false,
204            :folly_version=>"2021.07.22.00",
205            :react_native_path=>"../node_modules/react-native"
206        }])
207        assert_equal(codegen_utils_mock.get_react_codegen_spec_params, [])
208        assert_equal(codegen_utils_mock.generate_react_codegen_spec_params, [])
209    end
210
211    def testRunCodegen_whenNewArchDisabled_runsCodegen
212        # Arrange
213        app_path = "~/app"
214        config_file = ""
215        package_json_file = "~/app/package.json"
216        codegen_specs = { "name" => "ABI49_0_0React-Codegen" }
217        codegen_utils_mock = CodegenUtilsMock.new(:react_codegen_spec => codegen_specs)
218
219        # Act
220        run_codegen!(
221            app_path,
222            config_file,
223            :new_arch_enabled => false,
224            :fabric_enabled => true,
225            :package_json_file => package_json_file,
226            :codegen_utils => codegen_utils_mock)
227
228        # Assert
229        assert_equal(codegen_utils_mock.use_react_native_codegen_discovery_params, [])
230        assert_equal(codegen_utils_mock.get_react_codegen_spec_params, [{
231            :fabric_enabled => true,
232            :folly_version=>"2021.07.22.00",
233            :package_json_file => "~/app/package.json",
234            :script_phases => nil
235        }])
236        assert_equal(codegen_utils_mock.generate_react_codegen_spec_params, [{
237            :codegen_output_dir=>"build/generated/ios",
238            :react_codegen_spec=>{"name"=>"ABI49_0_0React-Codegen"}
239        }])
240
241    end
242end
243