1/*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use rollupObject file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import mocha from 'mocha';
17import fs from 'fs';
18import path from 'path';
19import { expect } from 'chai';
20import * as ts from 'typescript';
21
22import { EXPECT_INDEX_ETS } from './mock/rollup_mock/path_config';
23import RollUpPluginMock from './mock/rollup_mock/rollup_plugin_mock';
24import {
25  addLocalPackageSet,
26  compilerOptions,
27  localPackageSet,
28  needReCheckForChangedDepUsers,
29  resetEtsCheck,
30  serviceChecker,
31} from '../../lib/ets_checker';
32import { TS_BUILD_INFO_SUFFIX } from '../../lib/pre_define'
33import {
34  globalProgram,
35  projectConfig
36} from '../../main';
37
38mocha.describe('test ets_checker file api', function () {
39    mocha.before(function () {
40        this.rollup = new RollUpPluginMock();
41    });
42
43    mocha.after(() => {
44        delete this.rollup;
45        const cacheFile: string = path.resolve(projectConfig.cachePath, '../.ts_checker_cache');
46        if (fs.existsSync(cacheFile)) {
47            fs.unlinkSync(cacheFile);
48        }
49        const tsBuildInfoFilePath: string = path.resolve(projectConfig.cachePath, '..', TS_BUILD_INFO_SUFFIX);
50        if (fs.existsSync(tsBuildInfoFilePath)) {
51            fs.unlinkSync(tsBuildInfoFilePath);
52        }
53        const tsBuildInfoLinterFilePath: string = tsBuildInfoFilePath + '.linter';
54        if (fs.existsSync(tsBuildInfoLinterFilePath)) {
55            fs.unlinkSync(tsBuildInfoLinterFilePath);
56        }
57    });
58
59    mocha.it('1-1: test addLocalPackageSet for original ohmurl', function () {
60        this.rollup.build();
61        const rollupObject = this.rollup;
62        const rollupFileList = rollupObject.getModuleIds();
63        projectConfig.useNormalizedOHMUrl = false;
64        for (const moduleId of rollupFileList) {
65            if (fs.existsSync(moduleId)) {
66                addLocalPackageSet(moduleId, rollupObject);
67            }
68        }
69        expect(localPackageSet.has('entry')).to.be.true;
70        localPackageSet.clear();
71    });
72
73    mocha.it('1-2: test addLocalPackageSet for normalized ohmurl', function () {
74        this.rollup.build();
75        const rollupObject = this.rollup;
76        const rollupFileList = rollupObject.getModuleIds();
77        projectConfig.useNormalizedOHMUrl = true;
78        for (const moduleId of rollupFileList) {
79            const moduleInfo: Object = rollupObject.getModuleInfo(moduleId);
80            if (moduleInfo) {
81                const metaInfo: Object = moduleInfo.meta;
82                metaInfo.pkgName = 'pkgname';
83            }
84            if (fs.existsSync(moduleId)) {
85                addLocalPackageSet(moduleId, rollupObject);
86            }
87        }
88        expect(localPackageSet.has('pkgname')).to.be.true;
89    });
90
91    mocha.it('1-3: test getOrCreateLanguageService when dependency in oh-package.json change', function () {
92        this.timeout(10000);
93        this.rollup.build();
94        let rollupObject = this.rollup;
95        expect(needReCheckForChangedDepUsers).to.be.false;
96
97        interface MockCacheStore {
98            service: Object | undefined;
99            pkgJsonFileHash: string;
100            targetESVersion: number;
101        }
102        const mockServiceCache = {
103            service: undefined,
104            pkgJsonFileHash: '9f07917d395682c73a90af8f5796a2c6',
105            targetESVersion: 8
106        }
107        let mockCache = new Map<string, MockCacheStore>();
108        mockCache.set('service', mockServiceCache);
109        rollupObject.share.cache = mockCache;
110        rollupObject.share.depInfo = {enableIncre: true};
111        rollupObject.share.projectConfig.pkgJsonFileHash = '26bde0f30dda53b0afcbf39428ec9851';
112        Object.assign(projectConfig, rollupObject.share.projectConfig);
113
114        // The current hash and the hash in cache of the dependency differs, should recheck
115        serviceChecker([EXPECT_INDEX_ETS], null, null, null, rollupObject.share);
116        expect(needReCheckForChangedDepUsers).to.be.true;
117        expect(globalProgram.program != null).to.be.true;
118
119        resetEtsCheck();
120        expect(needReCheckForChangedDepUsers).to.be.false;
121        expect(globalProgram.program == null).to.be.true;
122
123        // The current hash and the hash in cache of the dependency are the same, no need to recheck
124        serviceChecker([EXPECT_INDEX_ETS], null, null, null, rollupObject.share);
125        expect(needReCheckForChangedDepUsers).to.be.false;
126        expect(globalProgram.program != null).to.be.true;
127
128        resetEtsCheck();
129        expect(needReCheckForChangedDepUsers).to.be.false;
130        expect(globalProgram.program == null).to.be.true;
131    });
132
133    mocha.it('1-4: test getOrCreateLanguageService when paths in compilerOptions change', function () {
134        this.timeout(10000);
135        this.rollup.build();
136        let rollupObject = this.rollup;
137        process.env.compileTool = 'rollup';
138
139        Object.assign(projectConfig, rollupObject.share.projectConfig);
140        serviceChecker([EXPECT_INDEX_ETS], null, null, null, rollupObject.share);
141        expect(JSON.stringify(compilerOptions.paths) === '{"*":["*","../../../../*","../*"]}').to.be.true;
142        expect(needReCheckForChangedDepUsers).to.be.false;
143        expect(globalProgram.program != null).to.be.true;
144        expect(compilerOptions.skipPathsInKeyForCompilationSettings).to.be.true;
145
146        resetEtsCheck();
147        expect(needReCheckForChangedDepUsers).to.be.false;
148        expect(globalProgram.program == null).to.be.true;
149        expect(compilerOptions.skipPathsInKeyForCompilationSettings).to.be.true;
150
151        interface MockCacheStore {
152            service: Object | undefined;
153            pkgJsonFileHash: string;
154            targetESVersion: number;
155        }
156        const mockServiceCache = {
157            service: undefined,
158            pkgJsonFileHash: '9f07917d395682c73a90af8f5796a2c6',
159            targetESVersion: 8
160        }
161        let mockCache = new Map<string, MockCacheStore>();
162        mockCache.set('service', mockServiceCache);
163        rollupObject.share.cache = mockCache;
164        rollupObject.share.depInfo = {enableIncre: true};
165        rollupObject.share.projectConfig.pkgJsonFileHash = '26bde0f30dda53b0afcbf39428ec9851';
166
167        // The current hash of the dependency differs, and the paths in compilerOptions will change since resolveModulePaths change
168        const resolveModulePaths = ['../testdata/expect'];
169        serviceChecker([EXPECT_INDEX_ETS], null, resolveModulePaths, null, rollupObject.share);
170        expect(JSON.stringify(compilerOptions.paths) === '{"*":["*","../../../../../../../testdata/expect/*"]}').to.be.true;
171        expect(needReCheckForChangedDepUsers).to.be.true;
172        expect(globalProgram.program != null).to.be.true;
173        expect(compilerOptions.skipPathsInKeyForCompilationSettings).to.be.true;
174
175        resetEtsCheck();
176        expect(needReCheckForChangedDepUsers).to.be.false;
177        expect(globalProgram.program == null).to.be.true;
178        expect(compilerOptions.skipPathsInKeyForCompilationSettings).to.be.true;
179    });
180    mocha.it('1-5: test GetEmitHost of program', function () {
181        const compilerOptions: ts.CompilerOptions = {
182            target: ts.ScriptTarget.ES2021
183        };
184        const fileNames: string[] = ['../testdata/testfiles/testGetEmitHost.ts'];
185        let program: ts.Program = ts.createProgram(fileNames, compilerOptions);
186        expect(program.getEmitHost()).to.not.be.undefined;
187    });
188});