= (mode: display.FoldDisplayMode) => {
+ // 可折叠设备的显示模式改变时(如展开或者折叠),重新获取屏幕宽度
+ this.screenWidth = this.getCurrentScreenWidth();
+ // 重新计算indicatorLeftMargin
+ if (this.currentIndex === CalendarViewType.YEAR) {
+ this.indicatorLeftMargin = (this.screenWidth - PADDING * 2) / 6 * 1 - COLUMN_WIDTH / 2;
+ } else if (this.currentIndex === CalendarViewType.MONTH) {
+ this.indicatorLeftMargin = (this.screenWidth - PADDING * 2) / 2 - COLUMN_WIDTH / 2;
+ } else if (this.currentIndex === CalendarViewType.WEEK) {
+ this.indicatorLeftMargin = (this.screenWidth - PADDING * 2) / 6 * 5 - COLUMN_WIDTH / 2;
+ }
+ if (mode === display.FoldDisplayMode.FOLD_DISPLAY_MODE_FULL) {
+ // 折叠屏展开态显示
+ CommonData.DEVICE_TYPE = DeviceType.EXPAND_FOLD;
+ } else if (mode === display.FoldDisplayMode.FOLD_DISPLAY_MODE_MAIN) {
+ // 折叠屏折叠态显示
+ CommonData.DEVICE_TYPE = DeviceType.PHONE;
+ }
+ };
+ // 依据cases工程Navigation的mode属性说明,如使用Auto,窗口宽度>=600vp时,采用Split模式显示;窗口宽度<600vp时,采用Stack模式显示。
+ private readonly DEVICESIZE: number = 600;
+ // 不传isPlugin,默认为true。作为插件使用。设置false,适配cases。
+ isPlugin: boolean = true;
+
+ /**
+ * 获取当前屏幕宽度
+ */
+ getCurrentScreenWidth(): number {
+ let screenWidth: number = px2vp(display.getDefaultDisplaySync().width);
+ // 适配cases中Navigation在不同mode时,计算相对需要使用的屏幕宽度。当屏幕宽度大于600vp时,cases工程Navigation的mode采用Split模式显
+ // 示,需要重新计算实际页面所需的屏幕宽度。
+ if (!this.isPlugin && screenWidth >= this.DEVICESIZE) {
+ return screenWidth / 2;
+ } else {
+ return screenWidth;
+ }
+ }
+
+ aboutToAppear() {
+ // 检查设备是否可折叠。false表示不可折叠,true表示可折叠。
+ this.isFoldable = display.isFoldable();
+ CommonData.IS_FOLD = this.isFoldable;
+ if (this.isFoldable) {
+ // 如果是可折叠设备,注册折叠设备屏幕显示模式变化监听
+ display.on('foldDisplayModeChange', this.callback);
+ if (display.getFoldDisplayMode() === display.FoldDisplayMode.FOLD_DISPLAY_MODE_FULL) {
+ // 设置折叠屏展开态
+ CommonData.DEVICE_TYPE = DeviceType.EXPAND_FOLD;
+ }
+ }
+ // 获取屏幕宽度
+ this.screenWidth = this.getCurrentScreenWidth();
+ // 初始化自定义分段按钮白色滑块的位置,本案例默认首次加载显示月视图。由于onAreaChange获取indicatorLeftMargin有延迟,首次加载会出现白色
+ // 滑块跳变,所以这里计算indicatorLeftMargin的初始位置。
+ this.indicatorLeftMargin = (this.screenWidth - COLUMN_WIDTH) / 2 - PADDING;
+ // 判断是否是rk3568。用屏幕宽度480vp来判断
+ if (px2vp(display.getDefaultDisplaySync().width) === 480) {
+ CommonData.DEVICE_TYPE = DeviceType.RK;
+ }
+ }
+
+ aboutToDisappear() {
+ if (this.isFoldable) {
+ // 关闭显示设备变化的监听
+ display.off('foldDisplayModeChange', this.callback);
+ }
+ }
+
+ /**
+ * 年月信息标题。月视图和周视图显示年月信息,年视图只显示年信息。周视图中如果选中了日期,则优先根据选中日期显示年月信息。
+ */
+ @Builder
+ yearMonthTitle() {
+ Row() {
+ Text(`${this.currentShowYear}年 ${this.tabSelectedIndex === CalendarViewType.YEAR ? '' :
+ MONTHS[this.currentShowMonth-1]}`)
+ .fontSize(FONT_SIZE * TEXT_SCALING)
+ .fontWeight(FONT_WEIGHT_FIVE_HUNDRED)
+ // 自定义添加日程组件
+ // monthViewController: 可选项。传入该控制器,添加日程后,对应日程点会刷新到月视图上
+ // weekViewController: 可选项。传入该控制器,添加日程后,对应日程点会刷新到周视图上
+ SchedulePoint({
+ monthViewController: this.calendarMonthController,
+ weekViewController: this.calendarWeekController
+ })
+ }
+ .padding({ left: $r('app.integer.calendar_switch_size_ten'), right: $r('app.integer.calendar_switch_size_ten') })
+ .justifyContent(FlexAlign.SpaceBetween)
+ .width($r('app.string.calendar_switch_full_size'))
+ .height($r('app.integer.calendar_switch_size_thirty'))
+ }
+
+ /**
+ * 自定义分段按钮
+ */
+ @Builder
+ customSegmentButton() {
+ Stack({ alignContent: Alignment.TopStart }) {
+ Row() {
+ }
+ .width($r('app.string.calendar_switch_full_size'))
+ .height($r('app.integer.calendar_switch_size_thirty_five'))
+ .backgroundColor($r('app.color.calendar_switch_segment_button_row_bgcolor'))
+ .borderRadius($r('app.integer.calendar_switch_border_radius'))
+ .layoutWeight(LAYOUT_WEIGHT_THREE)
+
+ Column() {
+ Row() {
+ }
+ .borderRadius($r('app.integer.calendar_switch_border_radius'))
+ .height($r('app.string.calendar_switch_full_size'))
+ .width((this.screenWidth - PADDING * 2) / 3 - GAP_SPACE)
+ .backgroundColor(Color.White)
+ }
+ .height($r('app.integer.calendar_switch_size_thirty_five'))
+ .width(COLUMN_WIDTH)
+ .margin({ left: this.indicatorLeftMargin })
+ .padding({
+ top: $r('app.integer.calendar_switch_size_three'),
+ bottom: $r('app.integer.calendar_switch_size_three')
+ })
+
+ Row() {
+ this.customSegmentButtonItem(CalendarViewType.YEAR, '年')
+ this.customSegmentButtonItem(CalendarViewType.MONTH, '月')
+ this.customSegmentButtonItem(CalendarViewType.WEEK, '周')
+ }
+ .width($r('app.string.calendar_switch_full_size'))
+ .height($r('app.integer.calendar_switch_size_thirty_five'))
+ .borderRadius($r('app.integer.calendar_switch_border_radius'))
+ .backgroundColor(Color.Transparent)
+ .layoutWeight(LAYOUT_WEIGHT_THREE)
+ }
+ .width($r('app.string.calendar_switch_full_size'))
+ .height($r('app.integer.calendar_switch_size_thirty_five'))
+ .margin({
+ top: $r('app.integer.calendar_switch_size_ten'),
+ bottom: $r('app.integer.calendar_switch_margin_size_twelve')
+ })
+ }
+
+ /**
+ * 自定义分段按钮项
+ * @param index 自定义分段按钮索引。这里对应自定义日历视图类型。0:年视图YEAR,1:月视图MONTH,2:周视图WEEK
+ * @param name 自定义分段按钮名。这里对应'年','月','周'
+ */
+ @Builder
+ customSegmentButtonItem(index: number, name: string) {
+ Column() {
+ Text(name)
+ .width(CUSTOM_SEGMENT_BUTTON_MONTH_WIDTH)
+ .textAlign(TextAlign.Center)
+ .height($r('app.integer.calendar_switch_size_thirty_five'))
+ .fontSize($r('app.integer.calendar_switch_size_fourteen'))
+ .fontColor(this.currentIndex === index ? Color.Black :
+ $r('app.color.calendar_switch_segment_button_font_color'))
+ .fontWeight(this.currentIndex === index ? FONT_WEIGHT_FIVE_HUNDRED : FONT_WEIGHT_FOUR_HUNDRED)
+ }
+ .width($r('app.string.calendar_switch_full_size'))
+ .height($r('app.integer.calendar_switch_size_thirty_five'))
+ .layoutWeight(LAYOUT_WEIGHT_ONE)
+ .onClick(() => {
+ if (index === this.tabSelectedIndex) {
+ // 点击同一个自定义分段按钮项,不做切换,避免冗余操作
+ return;
+ }
+ this.tabSelectedIndex = index;
+ this.tabController.changeIndex(index);
+ this.currentShowYear = this.currentSelectDay.year;
+ this.currentShowMonth = this.currentSelectDay.month;
+ // TODO 知识点:点击自定义分段按钮customSegmentButton进行年、月、周视图间切换。使用视图控制器的swiperRefresh方法刷新对应视图数据。
+ if (this.tabSelectedIndex === CalendarViewType.MONTH) {
+ // 刷新月视图
+ this.calendarMonthController.swiperRefresh(CalendarViewType.MONTH);
+ } else if (this.tabSelectedIndex === CalendarViewType.WEEK) {
+ // 刷新周视图
+ this.calendarWeekController.swiperRefresh(CalendarViewType.WEEK);
+ } else if (this.tabSelectedIndex === CalendarViewType.YEAR) {
+ // 刷新年视图
+ this.calendarYearController.swiperRefresh(CalendarViewType.YEAR);
+ }
+ })
+ }
+
+ /**
+ * 自定义分段按钮切换动画
+ * @param duration 动画时长
+ * @param leftMargin 自定义分段按钮左侧边距
+ */
+ startAnimateTo(duration: number, leftMargin: number) {
+ animateTo({
+ duration: duration, // 动画时长
+ curve: Curve.Linear, // 动画曲线
+ iterations: 1, // 播放次数
+ playMode: PlayMode.Normal, // 动画模式
+ }, () => {
+ this.indicatorLeftMargin = leftMargin;
+ })
+ }
+
+ build() {
+ Column() {
+ // 年月信息标题(包含添加日程组件)
+ this.yearMonthTitle()
+ // 自定义分段按钮
+ this.customSegmentButton()
+
+ Tabs({ barPosition: BarPosition.End, index: CalendarViewType.MONTH, controller: this.tabController }) {
+ TabContent() {
+ Column() {
+ // 自定义年视图
+ // calendarViewType: 必选项。自定义日历类型。YEAR年视图 MONTH月视图 WEEK周视图
+ // onMonthClick: 可选项。年视图月份点击回调。返回年视图点击的年月信息。仅用于年视图。
+ // onChangeYearMonth: 可选项。年、月、周视图左右滑动切换回调。返回左右切换年、月、周后的年月信息,其中年视图切换实际只返回切换后年份信息。
+ // calendarSwitch: 可选项。年、月、周视图切换场景的相关设置。
+ // - controller: 可选项。自定义日历控制器,用于视图切换后的数据刷新。
+ // - currentSelectDay: 可选项。记录月、周视图中点击选中的日期信息。
+ // - isYearMonthHidden:可选项。是否隐藏自定义日历年、月、周视图中自带的年月信息标题。
+ CustomCalendar({
+ calendarViewType: CalendarViewType.YEAR,
+ onMonthClick: (year: number, month: number) => {
+ if (this.tabController) {
+ // 切到月视图
+ this.tabController.changeIndex(1);
+ // 刷新年月信息标题
+ this.currentShowYear = year;
+ this.currentShowMonth = month;
+ // 刷新在年视图上点击月后要跳转的月视图数据
+ this.calendarMonthController.swiperYearToMonthRefresh(year, month);
+ }
+ },
+ onChangeYearMonth: (year: number, month: number) => {
+ this.currentShowYear = year;
+ },
+ calendarSwitch: {
+ controller: this.calendarYearController,
+ currentSelectDay: this.currentSelectDay,
+ isYearMonthHidden: this.isYearMonthHidden
+ }
+ })
+ }
+ .width($r('app.string.calendar_switch_full_size'))
+ .height($r('app.string.calendar_switch_full_size'))
+ }
+
+ TabContent() {
+ Column() {
+ // 自定义月视图
+ // calendarViewType: 必选项。自定义日历类型。YEAR年视图 MONTH月视图 WEEK周视图
+ // calendarStyle: 可选项。自定义日历样式。仅用于月、周视图。
+ // - textScaling: 可选项。月视图和周视图中的公历、农历、星期、年月信息标题文字缩放比例。
+ // - backgroundColor: 可选项。今天选中日期的背景色。
+ // - monthDayColor: 可选项。本月公历日期颜色。
+ // - noMonthDayColor: 可选项。非本月公历日期颜色,仅对月视图有效。
+ // - lunarColor: 可选项。本月农历字体颜色。
+ // onDateClick: 可选项。日期点击回调。返回点击日期的年月日信息。仅用于月、周视图。
+ // onChangeYearMonth: 可选项。年、月、周视图左右滑动切换回调,返回左右切换视图后的年月信息,其中年视图切换实际只返回切换后年份信息。
+ // calendarSwitch: 可选项。用于年、月、周视图切换场景的相关设置。
+ // - controller: 可选项。自定义日历控制器,用于视图切换后的数据刷新。
+ // - currentSelectDay: 可选项。记录月、周视图中点击选中的日期信息。
+ // - isYearMonthHidden:可选项。是否隐藏自定义日历年、月、周视图中自带的年月信息标题。
+ CustomCalendar({
+ calendarViewType: CalendarViewType.MONTH,
+ calendarStyle: {
+ textScaling: TEXT_SCALING,
+ backgroundColor: Color.Red,
+ monthDayColor: Color.Black,
+ noMonthDayColor: Color.Gray,
+ lunarColor: Color.Gray
+ },
+ onDateClick: (year: number, month: number, date: number) => {
+ this.currentSelectDay.year = year;
+ this.currentSelectDay.month = month;
+ this.currentSelectDay.date = date;
+ },
+ onChangeYearMonth: (year: number, month: number) => {
+ this.currentShowYear = year;
+ this.currentShowMonth = month;
+ },
+ calendarSwitch: {
+ controller: this.calendarMonthController,
+ currentSelectDay: this.currentSelectDay,
+ isYearMonthHidden: this.isYearMonthHidden,
+ }
+ })
+ }
+ .width($r('app.string.calendar_switch_full_size'))
+ .height($r('app.string.calendar_switch_full_size'))
+ }
+
+ TabContent() {
+ Column() {
+ // 自定义周视图
+ // calendarViewType: 必选项。自定义日历类型。YEAR年视图 MONTH月视图 WEEK周视图
+ // calendarStyle: 可选项。自定义日历样式。仅用于月、周视图。
+ // - textScaling: 可选项。月视图和周视图中的公历、农历、星期、年月信息标题文字缩放比例。
+ // - backgroundColor: 可选项。今天选中日期的背景色。
+ // - monthDayColor: 可选项。本月公历日期颜色。
+ // - noMonthDayColor: 可选项。非本月公历日期颜色,仅对月视图有效。
+ // - lunarColor: 可选项。本月农历字体颜色。
+ // onDateClick: 可选项。日期点击回调。返回点击日期的年月日信息。仅用于月、周视图。
+ // onChangeYearMonth: 可选项。年、月、周视图左右滑动切换回调,返回左右切换视图后的年月信息,其中年视图切换实际只返回切换后年份信息。
+ // calendarSwitch: 可选项。用于年、月、周视图切换场景的相关设置。
+ // - controller: 可选项。自定义日历控制器,用于视图切换后的数据刷新。
+ // - currentSelectDay: 可选项。记录月、周视图中点击选中的日期信息。
+ // - isYearMonthHidden:可选项。是否隐藏自定义日历年、月、周视图中自带的年月信息标题。
+ CustomCalendar({
+ calendarViewType: CalendarViewType.WEEK,
+ calendarStyle: {
+ textScaling: TEXT_SCALING,
+ backgroundColor: Color.Red,
+ monthDayColor: Color.Black,
+ lunarColor: Color.Gray
+ },
+ onDateClick: (year: number, month: number, date: number) => {
+ this.currentSelectDay.year = year;
+ this.currentSelectDay.month = month;
+ this.currentSelectDay.date = date;
+ },
+ onChangeYearMonth: (year: number, month: number) => {
+ this.currentShowYear = year;
+ this.currentShowMonth = month;
+ },
+ calendarSwitch: {
+ controller: this.calendarWeekController,
+ currentSelectDay: this.currentSelectDay,
+ isYearMonthHidden: this.isYearMonthHidden
+ }
+ })
+ }
+ .width($r('app.string.calendar_switch_full_size'))
+ .height($r('app.string.calendar_switch_full_size'))
+ }
+ }
+ .animationDuration(this.animationDuration)
+ .onAnimationStart((index: number, targetIndex: number, event: TabsAnimationEvent) => {
+ // 在年视图中点击月,切换到月视图时,需要显示'年月信息标题'中的的月份信息
+ if (index === CalendarViewType.YEAR && targetIndex === CalendarViewType.MONTH) {
+ this.tabSelectedIndex = CalendarViewType.MONTH;
+ }
+ // 切换动画开始时触发该回调。白色滑块跟着页面一起滑动。
+ this.currentIndex = targetIndex;
+ if (targetIndex === CalendarViewType.YEAR) {
+ // 传入自定义分段按钮左侧边距 点击“年”的分段按钮时,分段按钮白色滑块移动到屏幕1/6位置
+ this.startAnimateTo(this.animationDuration, (this.screenWidth - PADDING * 2) / 6 * 1 - COLUMN_WIDTH / 2);
+ } else if (targetIndex === CalendarViewType.MONTH) {
+ // 传入自定义分段按钮左侧边距 点击“月”的分段按钮时,分段按钮白色滑块移动到屏幕3/6位置
+ this.startAnimateTo(this.animationDuration, (this.screenWidth - PADDING * 2) / 2 - COLUMN_WIDTH / 2);
+ } else if (targetIndex === CalendarViewType.WEEK) {
+ // 传入自定义分段按钮左侧边距 点击“周”的分段按钮时,分段按钮白色滑块移动到屏幕5/6位置
+ this.startAnimateTo(this.animationDuration, (this.screenWidth - PADDING * 2) / 6 * 5 - COLUMN_WIDTH / 2);
+ }
+ })
+ .onAppear(() => {
+ // TODO: 高性能知识点: 组件挂载显示后触发此回调,预加载年视图数据,避免首次切换到年视图时出现卡顿问题
+ // 针对月视图切换周视图场景,需要预加载周视图(索引2),不然在月视图切换月份,选择日期后,再切换到周视图,周视图不会刷新
+ this.tabController.preloadItems([0, 2]); // 索引0对应年视图,索引2对应周视图
+ })
+ .layoutWeight(LAYOUT_WEIGHT_ONE)
+ .scrollable(false)
+ .barHeight($r('app.integer.calendar_switch_zero'))
+ }
+ .width($r('app.string.calendar_switch_full_size'))
+ .height($r('app.string.calendar_switch_full_size'))
+ .padding(PADDING)
+ }
+}
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/entry/oh_modules/calendarswitch/src/main/module.json5 b/code/UI/CalendarViewSwitch/entry/oh_modules/calendarswitch/src/main/module.json5
new file mode 100644
index 0000000000000000000000000000000000000000..76af7397b174333b3589d75d1eb27b68be0f2859
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/entry/oh_modules/calendarswitch/src/main/module.json5
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+{
+ "module": {
+ "name": "calendarswitch",
+ "type": "har",
+ "deviceTypes": [
+ "default",
+ "tablet"
+ ],
+ "requestPermissions":[
+ {
+ "name" : "ohos.permission.READ_CALENDAR",
+ "reason": "$string:app_name",
+ "usedScene": {
+ "abilities": [
+ "FormAbility"
+ ],
+ "when":"always"
+ }
+ },
+ {
+ "name" : "ohos.permission.WRITE_CALENDAR",
+ "reason": "$string:app_name",
+ "usedScene": {
+ "abilities": [
+ "FormAbility"
+ ],
+ "when":"always"
+ }
+ }
+ ]
+ }
+}
diff --git a/code/UI/CalendarViewSwitch/entry/oh_modules/calendarswitch/src/main/resources/base/element/color.json b/code/UI/CalendarViewSwitch/entry/oh_modules/calendarswitch/src/main/resources/base/element/color.json
new file mode 100644
index 0000000000000000000000000000000000000000..508d2817d3c5ca04d0b2ca12994c13c398edd189
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/entry/oh_modules/calendarswitch/src/main/resources/base/element/color.json
@@ -0,0 +1,24 @@
+{
+ "color": [
+ {
+ "name": "calendar_switch_border_color",
+ "value": "#24A844"
+ },
+ {
+ "name": "calendar_switch_segment_button_bgcolor",
+ "value": "#FFFEFEFE"
+ },
+ {
+ "name": "calendar_switch_segment_button_font_color",
+ "value": "#4e4e4e"
+ },
+ {
+ "name": "calendar_switch_segment_button_row_bgcolor",
+ "value": "#e7e7e7"
+ },
+ {
+ "name": "calendar_switch_schedule_point_color",
+ "value": "#ffababab"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/entry/oh_modules/calendarswitch/src/main/resources/base/element/integer.json b/code/UI/CalendarViewSwitch/entry/oh_modules/calendarswitch/src/main/resources/base/element/integer.json
new file mode 100644
index 0000000000000000000000000000000000000000..05210e5f549b42d078e9fc824f24c54a49ffb9c1
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/entry/oh_modules/calendarswitch/src/main/resources/base/element/integer.json
@@ -0,0 +1,124 @@
+{
+ "integer": [
+ {
+ "name": "calendar_switch_size_forty",
+ "value":40
+ },
+ {
+ "name": "calendar_switch_size_ten",
+ "value":10
+ },
+ {
+ "name": "calendar_switch_size_twenty_five",
+ "value":25
+ },
+ {
+ "name": "calendar_switch_size_three",
+ "value":3
+ },
+ {
+ "name": "calendar_switch_size_four",
+ "value":4
+ },
+ {
+ "name": "calendar_switch_size_seven",
+ "value":7
+ },
+ {
+ "name": "calendar_switch_margin_left",
+ "value":6
+ },
+ {
+ "name": "calendar_switch_margin_bottom",
+ "value":5
+ },
+ {
+ "name": "calendar_switch_margin_size_twelve",
+ "value":12
+ },
+ {
+ "name": "calendar_switch_size_fifteen",
+ "value": 15
+ },
+ {
+ "name": "calendar_switch_columns_gap",
+ "value": 0
+ },
+ {
+ "name": "calendar_switch_rows_gap",
+ "value": 10
+ },
+ {
+ "name": "calendar_switch_size_thirty_five",
+ "value": 35
+ },
+ {
+ "name": "calendar_switch_size_fourteen",
+ "value": 14
+ },
+ {
+ "name": "calendar_switch_border_radius",
+ "value": 20
+ },
+ {
+ "name": "calendar_switch_zero",
+ "value": 0
+ },
+ {
+ "name": "calendar_switch_size_eighteen",
+ "value": 18
+ },
+ {
+ "name": "calendar_switch_size_twenty",
+ "value": 20
+ },
+ {
+ "name": "calendar_switch_size_thirty",
+ "value": 30
+ },
+ {
+ "name": "calendar_switch_size_forty_six",
+ "value": 46
+ },
+ {
+ "name": "calendar_switch_size_one",
+ "value": 1
+ },
+ {
+ "name": "calendar_switch_size_forty_eight",
+ "value": 48
+ },
+ {
+ "name": "calendar_switch_size_eighty",
+ "value": 80
+ },
+ {
+ "name": "calendar_switch_size_ninety",
+ "value": 90
+ },
+ {
+ "name": "calendar_switch_size_hundred",
+ "value": 100
+ },
+ {
+ "name": "calendar_switch_size_sixteen",
+ "value": 16
+ },
+ {
+ "name": "calendar_switch_size_twenty_two",
+ "value": 22
+ },
+ {
+ "name": "calendar_switch_size_eight",
+ "value": 8
+ },
+ {
+ "name": "calendar_switch_size_sixty",
+ "value": 60
+ },
+ {
+ "name": "calendar_switch_two_hundred_fifty",
+ "value": 250
+ }
+ ]
+}
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/entry/oh_modules/calendarswitch/src/main/resources/base/element/string.json b/code/UI/CalendarViewSwitch/entry/oh_modules/calendarswitch/src/main/resources/base/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..f03eb0fdd9d5a11fec51e50a7a3a377fdfda3b2f
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/entry/oh_modules/calendarswitch/src/main/resources/base/element/string.json
@@ -0,0 +1,72 @@
+{
+ "string": [
+ {
+ "name": "calendar_switch_full_size",
+ "value": "100%"
+ },
+ {
+ "name": "calendar_switch_size_twenty_three",
+ "value": "23%"
+ },
+ {
+ "name": "calendar_switch_size_twenty_five",
+ "value": "25%"
+ },
+ {
+ "name": "calendar_switch_repeat",
+ "value": "重复"
+ },
+ {
+ "name": "calendar_switch_reminder_time",
+ "value": "提醒时间"
+ },
+ {
+ "name": "calendar_switch_cancel",
+ "value": "取消"
+ },
+ {
+ "name": "calendar_switch_new_schedule",
+ "value": "新建日程"
+ },
+ {
+ "name": "calendar_switch_add",
+ "value": "添加"
+ },
+ {
+ "name": "calendar_switch_title_msg",
+ "value": "请填写标题后再试"
+ },
+ {
+ "name": "calendar_switch_time_msg",
+ "value": "结束时间需要大于开始时间,请修改后再试"
+ },
+ {
+ "name": "calendar_switch_add_completed",
+ "value": "日程已添加,可到系统日历中查看新增日程"
+ },
+ {
+ "name": "calendar_switch_title",
+ "value": "标题"
+ },
+ {
+ "name": "calendar_switch_location",
+ "value": "地点"
+ },
+ {
+ "name": "calendar_switch_start_time",
+ "value": "开始时间"
+ },
+ {
+ "name": "calendar_switch_end_time",
+ "value": "结束时间"
+ },
+ {
+ "name": "calendar_switch_button_style",
+ "value": "20fp"
+ },
+ {
+ "name": "calendar_switch_describe",
+ "value": "说明"
+ }
+ ]
+}
diff --git a/code/UI/CalendarViewSwitch/entry/oh_modules/calendarswitch/src/main/resources/base/media/calendar_switch_add.png b/code/UI/CalendarViewSwitch/entry/oh_modules/calendarswitch/src/main/resources/base/media/calendar_switch_add.png
new file mode 100644
index 0000000000000000000000000000000000000000..ecc6e4ad34737b9c8a25239dba0ee94cbdc6a902
Binary files /dev/null and b/code/UI/CalendarViewSwitch/entry/oh_modules/calendarswitch/src/main/resources/base/media/calendar_switch_add.png differ
diff --git a/code/UI/CalendarViewSwitch/entry/oh_modules/calendarswitch/src/main/resources/base/media/calendar_switch_ok.svg b/code/UI/CalendarViewSwitch/entry/oh_modules/calendarswitch/src/main/resources/base/media/calendar_switch_ok.svg
new file mode 100644
index 0000000000000000000000000000000000000000..d3f2bd7564eb79dd9315599759a68ca285d4c8b9
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/entry/oh_modules/calendarswitch/src/main/resources/base/media/calendar_switch_ok.svg
@@ -0,0 +1,13 @@
+
+
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/entry/oh_modules/calendarswitch/src/main/resources/base/media/calendar_switch_spinner.svg b/code/UI/CalendarViewSwitch/entry/oh_modules/calendarswitch/src/main/resources/base/media/calendar_switch_spinner.svg
new file mode 100644
index 0000000000000000000000000000000000000000..02b175fddf7ec5846b8cfd227ab2c7f6b359685d
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/entry/oh_modules/calendarswitch/src/main/resources/base/media/calendar_switch_spinner.svg
@@ -0,0 +1,13 @@
+
+
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/local.properties b/code/UI/CalendarViewSwitch/local.properties
new file mode 100644
index 0000000000000000000000000000000000000000..9b1429c2fd69d5d4adaa74031cd22995c046929a
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/local.properties
@@ -0,0 +1,8 @@
+# This file is automatically generated by DevEco Studio.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file should *NOT* be checked into Version Control Systems,
+# as it contains information specific to your local configuration.
+#
+# For customization when using a Version Control System, please read the header note.
+sdk.dir=D:/IDE/OH_sdk/OpenHarmony/windows
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh-package-lock.json5 b/code/UI/CalendarViewSwitch/oh-package-lock.json5
new file mode 100644
index 0000000000000000000000000000000000000000..f538ae290f499a46efa12e593420d47f6e9024ff
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh-package-lock.json5
@@ -0,0 +1,19 @@
+{
+ "meta": {
+ "stableOrder": true
+ },
+ "lockfileVersion": 3,
+ "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.",
+ "specifiers": {
+ "@ohos/hypium@1.0.19": "@ohos/hypium@1.0.19"
+ },
+ "packages": {
+ "@ohos/hypium@1.0.19": {
+ "name": "@ohos/hypium",
+ "version": "1.0.19",
+ "integrity": "sha512-cEjDgLFCm3cWZDeRXk7agBUkPqjWxUo6AQeiu0gEkb3J8ESqlduQLSIXeo3cCsm8U/asL7iKjF85ZyOuufAGSQ==",
+ "resolved": "https://ohpm.openharmony.cn/ohpm/@ohos/hypium/-/hypium-1.0.19.har",
+ "registryType": "ohpm"
+ }
+ }
+}
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/BuildProfile.ets b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/BuildProfile.ets
new file mode 100644
index 0000000000000000000000000000000000000000..b054e98af7ad6092740cef28d7dcf6207e514dcb
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/BuildProfile.ets
@@ -0,0 +1,5 @@
+export default class BuildProfile {
+ static readonly HAR_VERSION = '1.0.19';
+ static readonly BUILD_MODE_NAME = 'debug';
+ static readonly DEBUG = true;
+}
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/CHANGELOG.md b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/CHANGELOG.md
new file mode 100644
index 0000000000000000000000000000000000000000..309d707c3d19f506f5582509edf1d0db9011a5b1
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/CHANGELOG.md
@@ -0,0 +1,24 @@
+## 1.0.14
+- 堆栈信息打印到cmd
+## 1.0.15
+- 支持获取测试代码的失败堆栈信息
+- mock代码迁移至harmock包
+- 适配arkts语法
+- 修复覆盖率数据容易截断的bug
+## 1.0.16
+- 修改覆盖率文件生成功能
+- 修改静态方法无法ignoreMock函数
+- ## 1.0.17
+- 修改not断言失败提示日志
+- 自定义错误message信息
+- 添加xdescribe, xit API功能
+- ## 1.0.18
+- 添加全局变量存储API get set
+- 自定义断言功能
+## 1.0.18-rc.0
+添加框架worker执行能力
+## 1.0.18-rc.1
+规范日志格式
+## 1.0.19
+- 规范日志格式
+- 代码规范整改
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/LICENSE b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..4947287f7b5ccb5d1e8b7b2d3aa5d89f322c160d
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/LICENSE
@@ -0,0 +1,177 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/README.md b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..6d795105533a9b3b9949e91d2c3dd14e8f867433
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/README.md
@@ -0,0 +1,219 @@
+Hypium
+A unit test framework for OpenHarmonyOS application
+
+## Hypium是什么?
+***
+- Hypium是OpenHarmony上的测试框架,提供测试用例编写、执行、结果显示能力,用于OpenHarmony系统应用接口以及应用界面测试。
+- Hypium结构化模型:hypium工程主要由List.test.js与TestCase.test.js组成。
+```
+rootProject // Hypium工程根目录
+├── moduleA
+│ ├── src
+│ ├── main // 被测试应用目录
+│ ├── ohosTest // 测试用例目录
+│ ├── js/ets
+│ └── test
+│ └── List.test.js // 测试用例加载脚本,ets目录下为.ets后缀
+│ └── TestCase.test.js // 测试用例脚本,ets目录下为.ets后缀
+└── moduleB
+ ...
+│ └── List.test.js // 测试用例加载脚本,ets目录下为.ets后缀
+│ └── TestCase.test.js // 测试用例脚本,ets目录下为.ets后缀
+```
+
+## 安装使用
+***
+- 在DevEco Studio内使用Hypium
+- 工程级package.json内配置:
+```json
+"dependencies": {
+ "@ohos/hypium": "1.0.19"
+}
+```
+注:
+hypium服务于OpenHarmonyOS应用对外接口测试、系统对外接口测试(SDK中接口),完成HAP自动化测试。详细指导:
+[Deveco Studio](https://developer.harmonyos.com/cn/develop/deveco-studio)
+
+#### 通用语法
+
+- 测试用例采用业内通用语法,describe代表一个测试套, it代表一条用例。
+
+| No. | API | 功能说明 |
+| --- | ---------- | ---------------------------------------------------------------------------------------------------------------------- |
+| 1 | describe | 定义一个测试套,支持两个参数:测试套名称和测试套函数 |
+| 2 | beforeAll | 在测试套内定义一个预置条件,在所有测试用例开始前执行且仅执行一次,支持一个参数:预置动作函数 |
+| 3 | beforeEach | 在测试套内定义一个单元预置条件,在每条测试用例开始前执行,执行次数与it定义的测试用例数一致,支持一个参数:预置动作函数 |
+| 4 | afterEach | 在测试套内定义一个单元清理条件,在每条测试用例结束后执行,执行次数与it定义的测试用例数一致,支持一个参数:清理动作函数 |
+| 5 | afterAll | 在测试套内定义一个清理条件,在所有测试用例结束后执行且仅执行一次,支持一个参数:清理动作函数 |
+| 6 | it | 定义一条测试用例,支持三个参数:用例名称,过滤参数和用例函数 |
+| 7 | expect | 支持bool类型判断等多种断言方法 |
+
+#### 断言库
+
+- 示例代码:
+
+```javascript
+ expect(${actualvalue}).assertX(${expectvalue})
+```
+
+- 断言功能列表:
+
+| No. | API | 功能说明 |
+| :--- | :------------------------------- | ---------------------------------------------------------------------------------------------- |
+| 1 | assertClose | 检验actualvalue和expectvalue(0)的接近程度是否是expectValue(1) |
+| 2 | assertContain | 检验actualvalue中是否包含expectvalue |
+| 3 | assertDeepEquals | @since1.0.4 检验actualvalue和expectvalue(0)是否是同一个对象 |
+| 4 | assertEqual | 检验actualvalue是否等于expectvalue[0] |
+| 5 | assertFail | 抛出一个错误 |
+| 6 | assertFalse | 检验actualvalue是否是false |
+| 7 | assertTrue | 检验actualvalue是否是true |
+| 8 | assertInstanceOf | 检验actualvalue是否是expectvalue类型 |
+| 9 | assertLarger | 检验actualvalue是否大于expectvalue |
+| 10 | assertLess | 检验actualvalue是否小于expectvalue |
+| 11 | assertNaN | @since1.0.4 检验actualvalue是否是NaN |
+| 12 | assertNegUnlimited | @since1.0.4 检验actualvalue是否等于Number.NEGATIVE_INFINITY |
+| 13 | assertNull | 检验actualvalue是否是null |
+| 14 | assertPosUnlimited | @since1.0.4 检验actualvalue是否等于Number.POSITIVE_INFINITY |
+| 15 | assertPromiseIsPending | @since1.0.4 检验actualvalue是否处于Pending状态【actualvalue为promse对象】 |
+| 16 | assertPromiseIsRejected | @since1.0.4 检验actualvalue是否处于Rejected状态【同15】 |
+| 17 | assertPromiseIsRejectedWith | @since1.0.4 检验actualvalue是否处于Rejected状态,并且比较执行的结果值【同15】 |
+| 18 | assertPromiseIsRejectedWithError | @since1.0.4 检验actualvalue是否处于Rejected状态并有异常,同时比较异常的类型和message值【同15】 |
+| 19 | assertPromiseIsResolved | @since1.0.4 检验actualvalue是否处于Resolved状态【同15】 |
+| 20 | assertPromiseIsResolvedWith | @since1.0.4 检验actualvalue是否处于Resolved状态,并且比较执行的结果值【同15】 |
+| 21 | assertThrowError | 检验actualvalue抛出Error内容是否是expectValue |
+| 22 | assertUndefined | 检验actualvalue是否是undefined |
+| 23 | not | @since1.0.4 断言结果取反 |
+
+
+示例代码:
+
+```javascript
+ import { describe, it, expect } from '@ohos/hypium';
+
+ export default async function assertCloseTest() {
+ describe('assertClose', function () {
+ it('assertClose_success', 0, function () {
+ let a = 100;
+ let b = 0.1;
+ expect(a).assertClose(99, b);
+ })
+ })
+ }
+```
+
+#### 公共系统能力
+
+| No. | API | 功能描述 |
+| ---- | ------------------------------------------------------- | ------------------------------------------------------------ |
+| 1 | existKeyword(keyword: string, timeout: number): boolean | @since1.0.3 hilog日志中查找指定字段是否存在,keyword是待查找关键字,timeout为设置的查找时间 |
+| 2 | actionStart(tag: string): void | @since1.0.3 cmd窗口输出开始tag |
+| 3 | actionEnd(tag: string): void | @since1.0.3 cmd窗口输出结束tag |
+
+示例代码:
+
+```javascript
+import { describe, it, expect, SysTestKit} from '@ohos/hypium';
+
+export default function existKeywordTest() {
+ describe('existKeywordTest', function () {
+ it('existKeyword',DEFAULT, async function () {
+ console.info("HelloTest");
+ let isExist = await SysTestKit.existKeyword('HelloTest');
+ console.info('isExist ------>' + isExist);
+ })
+ })
+}
+```
+```javascript
+import { describe, it, expect, SysTestKit} from '@ohos/hypium';
+
+export default function actionTest() {
+ describe('actionTest', function () {
+ it('existKeyword',DEFAULT, async function () {
+ let tag = '[MyTest]';
+ SysTestKit.actionStart(tag);
+ //do something
+ SysTestKit.actionEnd(tag);
+ })
+ })
+}
+```
+
+#### 专项能力
+
+- 测试用例属性筛选能力:hypium支持根据用例属性筛选执行指定测试用例,使用方式是先在测试用例上标记用例属性后,再在测试应用的启动shell命令后新增" -s ${Key} ${Value}"。
+
+| Key | 含义说明 | Value取值范围 |
+| -------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| level | 用例级别 | "0","1","2","3","4", 例如:-s level 1 |
+| size | 用例粒度 | "small","medium","large", 例如:-s size small |
+| testType | 用例测试类型 | "function","performance","power","reliability","security","global","compatibility","user","standard","safety","resilience", 例如:-s testType function |
+
+示例代码
+
+```javascript
+import { describe, it, expect, TestType, Size, Level } from '@ohos/hypium';
+
+export default function attributeTest() {
+ describe('attributeTest', function () {
+ it("testAttributeIt", TestType.FUNCTION | Size.SMALLTEST | Level.LEVEL0, function () {
+ console.info('Hello Test');
+ })
+ })
+}
+```
+
+示例命令
+```shell
+XX -s level 1 -s size small -s testType function
+```
+该命令的作用是:筛选测试应用中同时满足a)用例级别是1 b)用例粒度是small c)用例测试类型是function 三个条件的用例执行。
+
+- 测试套/测试用例名称筛选能力(测试套与用例名称用“#”号连接,多个用“,”英文逗号分隔)
+
+| Key | 含义说明 | Value取值范围 |
+| -------- | ----------------------- | -------------------------------------------------------------------------------------------- |
+| class | 指定要执行的测试套&用例 | ${describeName}#${itName},${describeName} , 例如:-s class attributeTest#testAttributeIt |
+| notClass | 指定不执行的测试套&用例 | ${describeName}#${itName},${describeName} , 例如:-s notClass attributeTest#testAttributeIt |
+
+示例命令
+```shell
+XX -s class attributeTest#testAttributeIt,abilityTest#testAbilityIt
+```
+该命令的作用是:筛选测试应用中attributeTest测试套下的testAttributeIt测试用例,abilityTest测试套下的testAbilityIt测试用例,只执行这两条用例。
+
+- 其他能力
+
+| 能力项 | Key | 含义说明 | Value取值范围 |
+| ------------ | ------- | ---------------------------- | ---------------------------------------------- |
+| 随机执行能力 | random | 测试套&测试用例随机执行 | true, 不传参默认为false, 例如:-s random true |
+| 空跑能力 | dryRun | 显示要执行的测试用例信息全集 | true , 不传参默认为false,例如:-s dryRun true |
+| 异步超时能力 | timeout | 异步用例执行的超时时间 | 正整数 , 单位ms,例如:-s timeout 5000 |
+
+##### 约束限制
+随机执行能力和空跑能力从npm包1.0.3版本开始支持
+
+#### Mock能力
+
+##### 约束限制
+
+单元测试框架Mock能力从npm包[1.0.1版本](https://repo.harmonyos.com/#/cn/application/atomService/@ohos%2Fhypium/v/1.0.1)开始支持
+
+## 约束
+
+***
+ 本模块首批接口从OpenHarmony SDK API version 8开始支持。
+
+## Hypium开放能力隐私声明
+
+- 我们如何收集和使用您的个人信息
+ 您在使用集成了Hypium开放能力的测试应用时,Hypium不会处理您的个人信息。
+- SDK处理的个人信息
+ 不涉及。
+- SDK集成第三方服务声明
+ 不涉及。
+- SDK数据安全保护
+ 不涉及。
+- SDK版本更新声明
+ 为了向您提供最新的服务,我们会不时更新Hypium版本。我们强烈建议开发者集成使用最新版本的Hypium。
+
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/build-profile.json5 b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/build-profile.json5
new file mode 100644
index 0000000000000000000000000000000000000000..312d38eb08629793b3484c7373213f22840c8d82
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/build-profile.json5
@@ -0,0 +1,28 @@
+{
+ "apiType": "stageMode",
+ "buildOption": {
+ },
+ "buildOptionSet": [
+ {
+ "name": "release",
+ "arkOptions": {
+ "obfuscation": {
+ "ruleOptions": {
+ "enable": true,
+ "files": [
+ "./obfuscation-rules.txt"
+ ]
+ },
+ "consumerFiles": [
+ "./consumer-rules.txt"
+ ]
+ }
+ },
+ },
+ ],
+ "targets": [
+ {
+ "name": "default"
+ }
+ ]
+}
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/hvigorfile.ts b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/hvigorfile.ts
new file mode 100644
index 0000000000000000000000000000000000000000..42187071482d292588ad40babeda74f7b8d97a23
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/hvigorfile.ts
@@ -0,0 +1,6 @@
+import { harTasks } from '@ohos/hvigor-ohos-plugin';
+
+export default {
+ system: harTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
+ plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
+}
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/index.d.ts b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/index.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7272b5fa839a2cd510d0c70d517bb6800133dba2
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/index.d.ts
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export const DEFAULT = 0B0000
+
+export const when: when;
+
+export enum TestType {
+ FUNCTION = 0B1,
+ PERFORMANCE = 0B1 << 1,
+ POWER = 0B1 << 2,
+ RELIABILITY = 0B1 << 3,
+ SECURITY = 0B1 << 4,
+ GLOBAL = 0B1 << 5,
+ COMPATIBILITY = 0B1 << 6,
+ USER = 0B1 << 7,
+ STANDARD = 0B1 << 8,
+ SAFETY = 0B1 << 9,
+ RESILIENCE = 0B1 << 10
+}
+
+export enum Size {
+ SMALLTEST = 0B1 << 16,
+ MEDIUMTEST = 0B1 << 17,
+ LARGETEST = 0B1 << 18
+}
+
+export enum Level {
+ LEVEL0 = 0B1 << 24,
+ LEVEL1 = 0B1 << 25,
+ LEVEL2 = 0B1 << 26,
+ LEVEL3 = 0B1 << 27,
+ LEVEL4 = 0B1 << 28
+}
+export { xdescribe, xit, describe, it } from './index';
+
+
+
+export function beforeItSpecified(testCaseNames: Array | string, callback: Function): void
+
+export function afterItSpecified(testCaseNames: Array | string, callback: Function): void
+
+export function beforeEach(callback: Function): void
+
+export function afterEach(callback: Function): void
+
+export function beforeAll(callback: Function): void
+
+export function afterAll(callback: Function): void
+
+
+export interface Assert {
+ assertClose(expectValue: number, precision: number): void
+ assertContain(expectValue: any): void
+ assertEqual(expectValue: any): void
+ assertFail(): void
+ assertFalse(): void
+ assertTrue(): void
+ assertInstanceOf(expectValue: string): void
+ assertLarger(expectValue: number): void
+ assertLess(expectValue: number): void
+ assertNull(): void
+ assertThrowError(expectValue: string | Function): void
+ assertUndefined(): void
+ assertLargerOrEqual(expectValue: number): void
+ assertLessOrEqual(expectValue: number): void
+ assertNaN(): void
+ assertNegUnlimited(): void
+ assertPosUnlimited(): void
+ not(): Assert;
+ assertDeepEquals(expectValue: any): void
+ assertPromiseIsPending(): Promise
+ assertPromiseIsRejected(): Promise
+ assertPromiseIsRejectedWith(expectValue?: any): Promise
+ assertPromiseIsRejectedWithError(...expectValue): Promise
+ assertPromiseIsResolved(): Promise
+ assertPromiseIsResolvedWith(expectValue?: any): Promise
+ message(msg: string): Assert
+}
+
+export function expect(actualValue?: any): Assert
+
+export class ArgumentMatchers {
+ static any;
+ static anyString;
+ static anyBoolean;
+ static anyNumber;
+ static anyObj;
+ static anyFunction;
+ static matchRegexs(Regex: RegExp): void
+}
+
+declare interface when {
+ afterReturn(value: any): any
+ afterReturnNothing(): undefined
+ afterAction(action: any): any
+ afterThrow(e_msg: string): string
+ (argMatchers?: any): when;
+}
+
+export interface VerificationMode {
+ times(count: Number): void
+ never(): void
+ once(): void
+ atLeast(count: Number): void
+ atMost(count: Number): void
+}
+
+export class MockKit {
+ constructor()
+ mockFunc(obj: Object, func: Function): Function
+ mockObject(obj: Object): Object
+ verify(methodName: String, argsArray: Array): VerificationMode
+ ignoreMock(obj: Object, func: Function): void
+ clear(obj: Object): void
+ clearAll(): void
+}
+
+export class SysTestKit {
+ static getDescribeName(): string;
+ static getItName(): string;
+ static getItAttribute(): TestType | Size | Level
+ static actionStart(tag: string): void
+ static actionEnd(tag: string): void
+ static existKeyword(keyword: string, timeout?: number): boolean
+}
+
+export class Hypium {
+ static setData(data: { [key: string]: any }): void
+ static setTimeConfig(systemTime: any)
+ static hypiumTest(abilityDelegator: any, abilityDelegatorArguments: any, testsuite: Function): void
+ static set(key: string, value: any): void
+ static get(key: string): any
+ static registerAssert(customAssertion: Function): void
+ static unregisterAssert(customAssertion: string | Function): void
+ static hypiumWorkerTest(abilityDelegator: Object, abilityDelegatorArguments: Object, testsuite: Function, workerPort: Object): void;
+ static hypiumInitWorkers(abilityDelegator: Object, scriptURL: string, workerNum: number, params: Object): void;
+}
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/index.ets b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/index.ets
new file mode 100644
index 0000000000000000000000000000000000000000..02a237f1c999d1f48b3974b6076d5dae9213245a
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/index.ets
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Core from './src/main/core';
+import {TestType, Size, Level, DEFAULT} from './src/main/Constant';
+import DataDriver from './src/main/module/config/DataDriver';
+import ExpectExtend from './src/main/module/assert/ExpectExtend';
+import OhReport from './src/main/module/report/OhReport';
+export { xdescribe, xit, describe, it } from './index.ts';
+
+export declare class Hypium {
+ static setData(data: Object): void
+ static setTimeConfig(systemTime: Object): void
+ static hypiumTest(abilityDelegator: Object, abilityDelegatorArguments: Object, testsuite: Function): void
+ static set(key: string, value: Object): void
+ static get(key: string): Object
+ static registerAssert(customAssertion: Function): void
+ static unregisterAssert(customAssertion: string | Function): void
+ static hypiumWorkerTest(abilityDelegator: Object, abilityDelegatorArguments: Object,
+ testsuite: Function, workerPort: Object): void;
+ static hypiumInitWorkers(abilityDelegator: Object, scriptURL: string, workerNum: number, params: Object): void;
+}
+
+export {
+ Core,
+ DataDriver,
+ ExpectExtend,
+ OhReport,
+ TestType,
+ Size,
+ Level,
+ DEFAULT
+};
+
+type allExpectType = Object | undefined | null
+
+export declare function beforeItSpecified(testCaseNames: Array | string, callback: Function): void
+
+export declare function afterItSpecified(testCaseNames: Array | string, callback: Function): void
+
+export declare function beforeEach(callback: Function): void
+
+export declare function afterEach(callback: Function): void
+
+export declare function beforeAll(callback: Function): void
+
+export declare function afterAll(callback: Function): void
+
+export declare interface Assert {
+ assertClose(expectValue: number, precision: number): void
+ assertContain(expectValue: allExpectType): void
+ assertEqual(expectValue: allExpectType): void
+ assertFail(): void
+ assertFalse(): void
+ assertTrue(): void
+ assertInstanceOf(expectValue: string): void
+ assertLarger(expectValue: number): void
+ assertLess(expectValue: number): void
+ assertNull(): void
+ assertThrowError(expectValue: string | Function): void
+ assertUndefined(): void
+ assertLargerOrEqual(expectValue: number):void
+ assertLessOrEqual(expectValue: number):void
+ assertNaN():void
+ assertNegUnlimited(): void
+ assertPosUnlimited(): void
+ not(): Assert;
+ assertDeepEquals(expectValue: allExpectType):void
+ assertPromiseIsPending(): Promise
+ assertPromiseIsRejected(): Promise
+ assertPromiseIsRejectedWith(expectValue?: allExpectType): Promise
+ assertPromiseIsRejectedWithError(...expectValue: allExpectType[]): Promise
+ assertPromiseIsResolved(): Promise
+ assertPromiseIsResolvedWith(expectValue?: allExpectType): Promise
+ message(msg: string): Assert
+}
+
+export declare function expect(actualValue?: allExpectType): Assert
+
+export declare class ArgumentMatchers {
+ public static any: allExpectType;
+ public static anyString: string;
+ public static anyBoolean: Boolean;
+ public static anyNumber: Number;
+ public static anyObj: Object;
+ public static anyFunction: Function;
+ public static matchRegexs(regex: RegExp): void
+}
+
+declare interface whenResult {
+ afterReturn: (value: allExpectType) => allExpectType
+ afterReturnNothing: () => undefined
+ afterAction: (action: allExpectType) => allExpectType
+ afterThrow: (e_msg: string) => string
+}
+
+export declare function when(f:Function): (f?: allExpectType | void) => whenResult
+
+export declare interface VerificationMode {
+ times(count: Number): void
+ never(): void
+ once(): void
+ atLeast(count: Number): void
+ atMost(count: Number): void
+}
+
+export declare class MockKit {
+ constructor()
+ mockFunc(obj: Object, func: Function): Function
+ mockObject(obj: Object): Object
+ verify(methodName: String, argsArray: Array): VerificationMode
+ ignoreMock(obj: Object, func: Function): void
+ clear(obj: Object): void
+ clearAll(): void
+}
+
+export declare class SysTestKit {
+ static getDescribeName(): string;
+ static getItName(): string;
+ static getItAttribute(): TestType | Size | Level
+ static actionStart(tag: string): void
+ static actionEnd(tag: string): void
+ static existKeyword(keyword: string, timeout?: number): boolean
+}
+
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/index.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..02d06d9d1b4b478aa2aec70ba3a73a5e123c98db
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/index.js
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License")
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Core from './src/main/core';
+import { DEFAULT, TestType, Size, Level, TAG, PrintTag } from './src/main/Constant';
+import DataDriver from './src/main/module/config/DataDriver';
+import ExpectExtend from './src/main/module/assert/ExpectExtend';
+import OhReport from './src/main/module/report/OhReport';
+import SysTestKit from './src/main/module/kit/SysTestKit';
+import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, beforeItSpecified, afterItSpecified, xdescribe, xit } from './src/main/interface';
+import { MockKit, when } from './src/main/module/mock/MockKit';
+import ArgumentMatchers from './src/main/module/mock/ArgumentMatchers';
+import worker from '@ohos.worker';
+
+class Hypium {
+ static context = new Map();
+ static setData(data) {
+ const core = Core.getInstance();
+ const dataDriver = new DataDriver({ data });
+ core.addService('dataDriver', dataDriver);
+ }
+
+ static setTimeConfig(systemTime) {
+ SysTestKit.systemTime = systemTime;
+ }
+
+ static set(key, value) {
+ Hypium.context.set(key, value);
+ }
+
+ static get(key) {
+ return Hypium.context.get(key);
+ }
+
+ static hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite) {
+ const core = Core.getInstance();
+ const expectExtend = new ExpectExtend({
+ 'id': 'extend'
+ });
+ core.addService('expect', expectExtend);
+ const ohReport = new OhReport({
+ 'delegator': abilityDelegator,
+ 'abilityDelegatorArguments': abilityDelegatorArguments
+ });
+ SysTestKit.delegator = abilityDelegator;
+ core.addService('report', ohReport);
+ core.init();
+ core.subscribeEvent('spec', ohReport);
+ core.subscribeEvent('suite', ohReport);
+ core.subscribeEvent('task', ohReport);
+ const configService = core.getDefaultService('config');
+ if (abilityDelegatorArguments !== null) {
+ let testParameters = configService.translateParams(abilityDelegatorArguments.parameters);
+ console.info(`${TAG}parameters:${JSON.stringify(testParameters)}`);
+ configService.setConfig(testParameters);
+ }
+ testsuite();
+ core.execute(abilityDelegator);
+ }
+ static async hypiumInitWorkers(abilityDelegator, scriptURL, workerNum = 8, params) {
+ console.info(`${TAG}, hypiumInitWorkers call,${scriptURL}`);
+ let workerPromiseArray = [];
+
+ // 开始统计时间
+ let startTime = await SysTestKit.getRealTime();
+ for (let i = 0; i < workerNum; i++) {
+ // 创建worker线程
+ const workerPromise = Hypium.createWorkerPromise(scriptURL, i, params);
+ workerPromiseArray.push(workerPromise);
+ }
+ const ret = {total: 0, failure: 0, error: 0, pass: 0, ignore: 0, duration: 0};
+ Promise.all(workerPromiseArray).then(async (items) => {
+ console.info(`${TAG}, all result from workers, ${JSON.stringify(items)}`);
+ let allItemList = new Array();
+ // 统计执行结果
+ Hypium.handleWorkerTestResult(ret, allItemList, items);
+ console.info(`${TAG}, all it result, ${JSON.stringify(allItemList)}`);
+ // 统计用例执行结果
+ const retResult = {total: 0, failure: 0, error: 0, pass: 0, ignore: 0, duration: 0};
+ // 标记用例执行结果
+ Hypium.configWorkerItTestResult(retResult, allItemList);
+ // 打印用例结果
+ Hypium.printWorkerTestResult(abilityDelegator, allItemList);
+ // 用例执行完成统计时间
+ let endTime = await SysTestKit.getRealTime();
+ const taskConsuming = endTime - startTime;
+ const message =
+ `\n${PrintTag.OHOS_REPORT_ALL_RESULT}: stream=Test run: runTimes: ${ret.total},total: ${retResult.total}, Failure: ${retResult.failure}, Error: ${retResult.error}, Pass: ${retResult.pass}, Ignore: ${retResult.ignore}` +
+ `\n${PrintTag.OHOS_REPORT_ALL_CODE}: ${retResult.failure > 0 || retResult.error > 0 ? -1 : 0}` +
+ `\n${PrintTag.OHOS_REPORT_ALL_STATUS}: taskconsuming=${taskConsuming > 0 ? taskConsuming : ret.duration}`;
+ abilityDelegator.printSync(message);
+ console.info(`${TAG}, [end] you worker test`);
+ abilityDelegator.finishTest('you worker test finished!!!', 0, () => {});
+ }).catch((e) => {
+ console.info(`${TAG}, [end] error you worker test, ${JSON.stringify(e)}`);
+ abilityDelegator.finishTest('you worker test error finished!!!', 0, () => {});
+ }).finally(() => {
+ console.info(`${TAG}, all promise finally end`);
+ });
+ }
+ // 创建worker线程
+ static createWorkerPromise(scriptURL, i, params) {
+ console.info(`${TAG}, createWorkerPromiser, ${scriptURL}, ${i}`);
+ const workerPromise = new Promise((resolve, reject) => {
+ const workerInstance = new worker.ThreadWorker(scriptURL, {name: `worker_${i}`});
+ console.info(`${TAG}, send data to worker`);
+ // 发送数据到worker线程中
+ workerInstance.postMessage(params);
+ workerInstance.onmessage = function (e) {
+ let currentThreadName = e.data?.currentThreadName;
+ console.info(`${TAG}, receview data from ${currentThreadName}, ${JSON.stringify(e.data)}`);
+ //
+ resolve(e.data?.summary);
+ console.info(`${TAG}, ${currentThreadName} finish`);
+ workerInstance.terminate();
+ };
+ workerInstance.onerror = function (e) {
+ console.info(`${TAG}, worker error, ${JSON.stringify(e)}`);
+ reject(e);
+ workerInstance.terminate();
+ };
+ workerInstance.onmessageerror = function (e) {
+ console.info(`${TAG}, worker message error, ${JSON.stringify(e)}`);
+ reject(e);
+ workerInstance.terminate();
+ };
+ });
+ return workerPromise;
+ }
+ static handleWorkerTestResult(ret, allItemList, items) {
+ console.info(`${TAG}, handleWorkerTestResult, ${JSON.stringify(items)}`);
+ for (const {total, failure, error, pass, ignore, duration, itItemList} of items) {
+ ret.total += total;
+ ret.failure += failure;
+ ret.error += error;
+ ret.pass += pass;
+ ret.ignore += ignore;
+ ret.duration += duration;
+ Hypium.handleItResult(allItemList, itItemList);
+ }
+ }
+ static handleItResult(allItemList, itItemList) {
+ // 遍历所有的用例结果统计最终结果
+ for (const {currentThreadName, description, result} of itItemList) {
+ let item = allItemList.find((it) => it.description === description);
+ if (item) {
+ let itResult = item.result;
+ // 当在worker中出现一次failure就标记为failure, 出现一次error就标记为error, 所有线程都pass才标记为pass
+ if (itResult === 0) {
+ item.result = result;
+ item.currentThreadName = currentThreadName;
+ }
+ } else {
+ let it = {
+ description: description,
+ currentThreadName: currentThreadName,
+ result: result
+ };
+ allItemList.push(it);
+ }
+ }
+ }
+ static configWorkerItTestResult(retResult, allItemList) {
+ console.info(`${TAG}, configWorkerItTestResult, ${JSON.stringify(allItemList)}`);
+ for (const {currentThreadName, description, result} of allItemList) {
+ console.info(`${TAG}, description, ${description}, result,${result}`);
+ retResult.total ++;
+ if (result === 0) {
+ retResult.pass ++;
+ } else if (result === -1) {
+ retResult.error ++;
+ } else if (result === -2) {
+ retResult.failure ++;
+ } else {
+ retResult.ignore ++;
+ }
+ }
+ }
+ static printWorkerTestResult(abilityDelegator, allItemList) {
+ console.info(`${TAG}, printWorkerTestResult, ${JSON.stringify(allItemList)}`);
+ let index = 1;
+ for (const {currentThreadName, description, result} of allItemList) {
+ console.info(`${TAG}, description print, ${description}, result,${result}`);
+ let itArray = description.split('#');
+ let des;
+ let itName;
+ if (itArray.length > 1) {
+ des = itArray[0];
+ itName = itArray[1];
+ } else if (itArray.length > 1) {
+ des = itArray[0];
+ itName = itArray[0];
+ } else {
+ des = 'undefined';
+ itName = 'undefined';
+ }
+
+ let msg = `\n${PrintTag.OHOS_REPORT_WORKER_STATUS}: class=${des}`;
+ msg += `\n${PrintTag.OHOS_REPORT_WORKER_STATUS}: test=${itName}`;
+ msg += `\n${PrintTag.OHOS_REPORT_WORKER_STATUS}: current=${index}`;
+ msg += `\n${PrintTag.OHOS_REPORT_WORKER_STATUS}: CODE=${result}`;
+ abilityDelegator.printSync(msg);
+ index ++;
+ }
+ }
+ static hypiumWorkerTest(abilityDelegator, abilityDelegatorArguments, testsuite, workerPort) {
+ console.info(`${TAG}, hypiumWorkerTest call`);
+ SysTestKit.workerPort = workerPort;
+ let currentWorkerName = workerPort.name;
+ console.info(`${TAG}, hypiumWorkerTest_currentWorkerName: ${currentWorkerName}`);
+ Hypium.hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite);
+
+ }
+
+ static registerAssert(customAssertion) {
+ const core = Core.getInstance();
+ const expectService = core.getDefaultService('expect');
+ let matchers = {};
+ matchers[customAssertion.name] = customAssertion;
+ expectService.addMatchers(matchers);
+ expectService.customMatchers.push(customAssertion.name);
+ console.info(`${TAG}success to register the ${customAssertion.name}`);
+ }
+
+ static unregisterAssert(customAssertion) {
+ const core = Core.getInstance();
+ const expectService = core.getDefaultService('expect');
+ let customAssertionName = typeof customAssertion === 'function' ? customAssertion.name : customAssertion;
+ expectService.removeMatchers(customAssertionName);
+ console.info(`${TAG}success to unregister the ${customAssertionName}`);
+ }
+
+}
+
+export {
+ Hypium,
+ Core,
+ DEFAULT,
+ TestType,
+ Size,
+ Level,
+ DataDriver,
+ ExpectExtend,
+ OhReport,
+ SysTestKit,
+ describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, beforeItSpecified, afterItSpecified, xdescribe, xit,
+ MockKit, when,
+ ArgumentMatchers
+};
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/index.ts b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b7082ebc98214b58d41e8681791809f1aee48f12
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/index.ts
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { TestType, Size, Level } from "./src/main/Constant";
+
+export declare function xdescribe(testSuiteName: string, func: Function): void;
+
+export declare namespace xdescribe {
+ function reason(reason: string): any;
+};
+
+export declare function describe(testSuiteName: string, func: Function): void;
+
+export declare function xit(testCaseName: string, attribute: TestType | Size | Level, func: Function): void;
+
+export declare namespace xit {
+ function reason(reason: string): any;
+};
+
+export declare function it(testCaseName: string, attribute: TestType | Size | Level, func: Function): void;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/oh-package.json5 b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/oh-package.json5
new file mode 100644
index 0000000000000000000000000000000000000000..d91344eda60f35477a5caf4bf5c116ffac2e53db
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/oh-package.json5
@@ -0,0 +1 @@
+{"name":"@ohos/hypium","version":"1.0.19","description":"A unit test framework for OpenHarmony application","main":"index.js","keywords":["测试框架","except","mock"],"author":"huawei","license":"Apache-2.0","repository":"https://gitee.com/openharmony/testfwk_arkxtest","homepage":"https://gitee.com/openharmony/testfwk_arkxtest","dependencies":{}}
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/Constant.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/Constant.js
new file mode 100644
index 0000000000000000000000000000000000000000..f470d69cd9a3302b19d45c147ca7d7c1dd8a3b18
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/Constant.js
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * define the testcase type : TestType, Size , Level
+ */
+export const TAG = '[Hypium]';
+
+export const DEFAULT = 0B0000;
+
+export class PrintTag {
+ static OHOS_REPORT_WORKER_STATUS = 'OHOS_REPORT_WORKER_STATUS';
+ static OHOS_REPORT_ALL_RESULT = 'OHOS_REPORT_ALL_RESULT';
+ static OHOS_REPORT_ALL_CODE = 'OHOS_REPORT_ALL_CODE';
+ static OHOS_REPORT_ALL_STATUS = 'OHOS_REPORT_ALL_STATUS';
+ static OHOS_REPORT_RESULT = 'OHOS_REPORT_RESULT';
+ static OHOS_REPORT_CODE = 'OHOS_REPORT_CODE';
+ static OHOS_REPORT_STATUS = 'OHOS_REPORT_STATUS';
+ static OHOS_REPORT_SUM = 'OHOS_REPORT_SUM';
+ static OHOS_REPORT_STATUS_CODE = 'OHOS_REPORT_STATUS_CODE';
+};
+
+export class TestType {
+ static FUNCTION = 0B1;
+ static PERFORMANCE = 0B1 << 1;
+ static POWER = 0B1 << 2;
+ static RELIABILITY = 0B1 << 3;
+ static SECURITY = 0B1 << 4;
+ static GLOBAL = 0B1 << 5;
+ static COMPATIBILITY = 0B1 << 6;
+ static USER = 0B1 << 7;
+ static STANDARD = 0B1 << 8;
+ static SAFETY = 0B1 << 9;
+ static RESILIENCE = 0B1 << 10;
+}
+
+export class Size {
+ static SMALLTEST = 0B1 << 16;
+ static MEDIUMTEST = 0B1 << 17;
+ static LARGETEST = 0B1 << 18;
+}
+
+export class Level {
+ static LEVEL0 = 0B1 << 24;
+ static LEVEL1 = 0B1 << 25;
+ static LEVEL2 = 0B1 << 26;
+ static LEVEL3 = 0B1 << 27;
+ static LEVEL4 = 0B1 << 28;
+}
+
+export const TESTTYPE = {
+ 'function': 1,
+ 'performance': 1 << 1,
+ 'power': 1 << 2,
+ 'reliability': 1 << 3,
+ 'security': 1 << 4,
+ 'global': 1 << 5,
+ 'compatibility': 1 << 6,
+ 'user': 1 << 7,
+ 'standard': 1 << 8,
+ 'safety': 1 << 9,
+ 'resilience': 1 << 10,
+}
+
+export const LEVEL = {
+ '0': 1 << 24,
+ '1': 1 << 25,
+ '2': 1 << 26,
+ '3': 1 << 27,
+ '4': 1 << 28,
+}
+
+export const SIZE = {
+ 'small': 1 << 16,
+ 'medium': 1 << 17,
+ 'large': 1 << 18,
+}
+
+export const KEYSET = [
+ '-s class', '-s notClass', '-s suite', '-s itName',
+ '-s level', '-s testType', '-s size', '-s timeout',
+ '-s dryRun', '-s random', '-s breakOnError', '-s stress',
+ '-s coverage', '-s skipMessage', '-s runSkipped',
+ 'class', 'notClass', 'suite', 'itName',
+ 'level', 'testType', 'size', 'timeout', 'dryRun', 'random',
+ 'breakOnError', 'stress', 'coverage', 'skipMessage', 'runSkipped'
+]
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/core.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/core.js
new file mode 100644
index 0000000000000000000000000000000000000000..cfcb5f17287208f5e6869b4248faf6c9093002d9
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/core.js
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {SuiteService, SpecService, ExpectService, ReportService} from './service';
+import {ConfigService} from './module/config/configService';
+import {SpecEvent, TaskEvent, SuiteEvent} from './event';
+
+/**
+ * core service for execute testcase.
+ */
+class Core {
+ static getInstance() {
+ if (!this.instance) {
+ this.instance = new Core();
+ }
+ return this.instance;
+ }
+
+ constructor() {
+ this.instance = null;
+ this.services = {
+ suite: {},
+ spec: {},
+ config: {},
+ expect: {},
+ log: {},
+ report: {}
+
+ };
+ this.events = {
+ suite: {},
+ spec: {},
+ task: {}
+ };
+ }
+
+ addService(name, service) {
+ let serviceObj = {};
+ if (!this.services[name]) {
+ this.services[name] = serviceObj;
+ } else {
+ serviceObj = this.services[name];
+ }
+ serviceObj[service.id] = service;
+ }
+
+ getDefaultService(name) {
+ return this.services[name].default;
+ }
+
+ getServices(name) {
+ return this.services[name];
+ }
+
+ registerEvent(serviceName, event) {
+ let eventObj = {};
+ if (!this.events[serviceName]) {
+ this.events[serviceName] = eventObj;
+ } else {
+ eventObj = this.events[serviceName];
+ }
+ eventObj[event.id] = event;
+ }
+
+ unRegisterEvent(serviceName, eventID) {
+ const eventObj = this.events[serviceName];
+ if (eventObj) {
+ delete eventObj[eventID];
+ }
+ }
+
+ subscribeEvent(serviceName, serviceObj) {
+ const eventObj = this.events[serviceName];
+ if (eventObj) {
+ for (const attr in eventObj) {
+ eventObj[attr]['subscribeEvent'](serviceObj);
+ }
+ }
+ }
+
+ async fireEvents(serviceName, eventName) {
+ const eventObj = this.events[serviceName];
+ if (!eventObj) {
+ return;
+ }
+ for (const attr in eventObj) {
+ await eventObj[attr][eventName]();
+ }
+ }
+
+ addToGlobal(apis) {
+ if (typeof globalThis !== 'undefined') {
+ for (let api in apis) {
+ globalThis[api] = apis[api];
+ }
+ }
+ for (const api in apis) {
+ this[api] = apis[api];
+ }
+ }
+
+ init() {
+ this.addService('suite', new SuiteService({id: 'default'}));
+ this.addService('spec', new SpecService({id: 'default'}));
+ this.addService('expect', new ExpectService({id: 'default'}));
+ this.addService('report', new ReportService({id: 'default'}));
+ this.addService('config', new ConfigService({id: 'default'}));
+ this.registerEvent('task', new TaskEvent({id: 'default', coreContext: this}));
+ this.registerEvent('suite', new SuiteEvent({id: 'default', coreContext: this}));
+ this.registerEvent('spec', new SpecEvent({id: 'default', coreContext: this}));
+ this.subscribeEvent('spec', this.getDefaultService('report'));
+ this.subscribeEvent('suite', this.getDefaultService('report'));
+ this.subscribeEvent('task', this.getDefaultService('report'));
+ const context = this;
+ for (const key in this.services) {
+ const serviceObj = this.services[key];
+ for (const serviceID in serviceObj) {
+ const service = serviceObj[serviceID];
+ service.init(context);
+
+ if (typeof service.apis !== 'function') {
+ continue;
+ }
+ const apis = service.apis();
+ if (apis) {
+ this.addToGlobal(apis);
+ }
+ }
+ }
+ }
+
+ execute(abilityDelegator) {
+ const suiteService = this.getDefaultService('suite');
+ const configService = this.getDefaultService('config');
+ if (configService['dryRun'] === 'true') {
+ (async function () {
+ await suiteService.dryRun(abilityDelegator);
+ })();
+ return;
+ }
+ setTimeout(() => {
+ suiteService.execute();
+ }, 10);
+ }
+}
+
+export default Core;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/event.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/event.js
new file mode 100644
index 0000000000000000000000000000000000000000..3be0211f01646c9c269c2425cbee82c87ac6d9ea
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/event.js
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class SpecEvent {
+ constructor(attr) {
+ this.id = attr.id;
+ this.coreContext = attr.context;
+ this.eventMonitors = [];
+ }
+
+ subscribeEvent(service) {
+ this.eventMonitors.push(service);
+ }
+
+ async specStart() {
+ for (const monitor of this.eventMonitors) {
+ await monitor['specStart']();
+ }
+ }
+
+ async specDone() {
+ for (const monitor of this.eventMonitors) {
+ await monitor['specDone']();
+ }
+ }
+}
+
+class SuiteEvent {
+ constructor(attr) {
+ this.id = attr.id;
+ this.suiteContext = attr.coreContext;
+ this.eventMonitors = [];
+ }
+
+ subscribeEvent(service) {
+ this.eventMonitors.push(service);
+ }
+
+ async suiteStart() {
+ for (const monitor of this.eventMonitors) {
+ await monitor['suiteStart']();
+ }
+ }
+
+ async suiteDone() {
+ for (const monitor of this.eventMonitors) {
+ await monitor['suiteDone']();
+ }
+ }
+}
+
+class TaskEvent {
+ constructor(attr) {
+ this.id = attr.id;
+ this.coreContext = attr.coreContext;
+ this.eventMonitors = [];
+ }
+
+ subscribeEvent(service) {
+ this.eventMonitors.push(service);
+ }
+
+ async taskStart() {
+ for (const monitor of this.eventMonitors) {
+ await monitor['taskStart']();
+ }
+ }
+
+ async taskDone() {
+ for (const monitor of this.eventMonitors) {
+ await monitor['taskDone']();
+ }
+ }
+
+ incorrectFormat() {
+ for (const monitor of this.eventMonitors) {
+ monitor['incorrectFormat']();
+ }
+ }
+
+ incorrectTestSuiteFormat() {
+ for (const monitor of this.eventMonitors) {
+ monitor.incorrectTestSuiteFormat();
+ }
+ }
+}
+
+export { SpecEvent, TaskEvent, SuiteEvent };
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/interface.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/interface.js
new file mode 100644
index 0000000000000000000000000000000000000000..1bf43509ac3f70f1275e1da79388e1511e72a3f9
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/interface.js
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Core from './core';
+
+const core = Core.getInstance();
+
+const describe = function (desc, func) {
+ return Reflect.has(core, 'describe') ? core.describe(desc, func) : (desc, func) => { };
+};
+const it = function (desc, filter, func) {
+ return Reflect.has(core, 'it') ? core.it(desc, filter, func) : (desc, filter, func) => { };
+};
+const beforeItSpecified = function (itDescs, func) {
+ return Reflect.has(core, 'beforeItSpecified') ? core.beforeItSpecified(itDescs, func) : (itDescs, func) => { };
+};
+
+const afterItSpecified = function (itDescs, func) {
+ return Reflect.has(core, 'afterItSpecified') ? core.afterItSpecified(itDescs, func) : (itDescs, func) => { };
+};
+const beforeEach = function (func) {
+ return Reflect.has(core, 'beforeEach') ? core.beforeEach(func) : (func) => { };
+};
+const afterEach = function (func) {
+ return Reflect.has(core, 'afterEach') ? core.afterEach(func) : (func) => { };
+};
+const beforeAll = function (func) {
+ return Reflect.has(core, 'beforeAll') ? core.beforeAll(func) : (func) => { };
+};
+const afterAll = function (func) {
+ return Reflect.has(core, 'afterAll') ? core.afterAll(func) : (func) => { };
+};
+const expect = function (actualValue) {
+ return Reflect.has(core, 'expect') ? core.expect(actualValue) : (actualValue) => { };
+};
+
+const xdescribe = function (desc, func) {
+ return Reflect.has(core, 'xdescribe') ? core.xdescribe(desc, func, null) : (desc, func, reason) => { };
+};
+xdescribe.reason = (reason) => {
+ return (desc, func) => {
+ return Reflect.has(core, 'xdescribe') ? core.xdescribe(desc, func, reason) : (desc, func, reason) => { };
+ };
+};
+const xit = function (desc, filter, func) {
+ return Reflect.has(core, 'xit') ? core.xit(desc, filter, func, null) : (desc, filter, func, reason) => { };
+};
+xit.reason = (reason) => {
+ return (desc, filter, func) => {
+ return Reflect.has(core, 'xit') ? core.xit(desc, filter, func, reason) : (desc, filter, func, reason) => { };
+ };
+};
+
+export {
+ describe, it, beforeAll, beforeEach, afterEach, afterAll, expect, beforeItSpecified, afterItSpecified, xdescribe, xit
+};
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module.json b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module.json
new file mode 100644
index 0000000000000000000000000000000000000000..b0e022bd13205c4c3310480d6732db4707193b3a
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module.json
@@ -0,0 +1,26 @@
+{
+ "app": {
+ "bundleName": "com.ohos.myapplication",
+ "debug": true,
+ "versionCode": 1000000,
+ "versionName": "1.0.0",
+ "minAPIVersion": 40100011,
+ "targetAPIVersion": 40100011,
+ "apiReleaseType": "Beta1",
+ "compileSdkVersion": "4.1.0.55",
+ "compileSdkType": "HarmonyOS",
+ "bundleType": "app"
+ },
+ "module": {
+ "name": "hypium",
+ "type": "har",
+ "deviceTypes": [
+ "default",
+ "tablet",
+ "tv",
+ "wearable",
+ "car"
+ ],
+ "installationFree": false
+ }
+}
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/ExpectExtend.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/ExpectExtend.js
new file mode 100644
index 0000000000000000000000000000000000000000..d10d15e6f9955c6d04610101f8766c951ee1a35d
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/ExpectExtend.js
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import assertNull from './assertNull';
+import assertClose from './assertClose';
+import assertContain from './assertContain';
+import assertLess from './assertLess';
+import assertLarger from './assertLarger';
+import assertFail from './assertFail';
+import assertUndefined from './assertUndefined';
+import assertFalse from './assertFalse';
+import assertInstanceOf from './assertInstanceOf';
+import assertThrowError from './assertThrowError';
+import assertLargerOrEqual from './assertLargerOrEqual'
+import assertLessOrEqual from './assertLessOrEqual'
+import assertNaN from './assertNaN'
+import assertNegUnlimited from './assertNegUnlimited'
+import assertPosUnlimited from './assertPosUnlimited'
+import assertDeepEquals from './deepEquals/assertDeepEquals'
+import assertPromiseIsPending from './assertPromiseIsPending';
+import assertPromiseIsRejected from './assertPromiseIsRejected';
+import assertPromiseIsRejectedWith from './assertPromiseIsRejectedWith';
+import assertPromiseIsRejectedWithError from './assertPromiseIsRejectedWithError';
+import assertPromiseIsResolved from './assertPromiseIsResolved';
+import assertPromiseIsResolvedWith from './assertPromiseIsResolvedWith';
+class ExpectExtend {
+ constructor(attr) {
+ this.id = attr.id;
+ this.matchers = {};
+ }
+
+ extendsMatchers() {
+ this.matchers.assertNull = assertNull;
+ this.matchers.assertClose = assertClose;
+ this.matchers.assertContain = assertContain;
+ this.matchers.assertLess = assertLess;
+ this.matchers.assertLarger = assertLarger;
+ this.matchers.assertFail = assertFail;
+ this.matchers.assertUndefined = assertUndefined;
+ this.matchers.assertFalse = assertFalse;
+ this.matchers.assertInstanceOf = assertInstanceOf;
+ this.matchers.assertThrowError = assertThrowError;
+ this.matchers.assertLargerOrEqual = assertLargerOrEqual;
+ this.matchers.assertLessOrEqual = assertLessOrEqual;
+ this.matchers.assertNaN = assertNaN;
+ this.matchers.assertNegUnlimited = assertNegUnlimited;
+ this.matchers.assertPosUnlimited = assertPosUnlimited;
+ this.matchers.assertDeepEquals = assertDeepEquals;
+ this.matchers.assertPromiseIsPending = assertPromiseIsPending;
+ this.matchers.assertPromiseIsRejected = assertPromiseIsRejected;
+ this.matchers.assertPromiseIsRejectedWith = assertPromiseIsRejectedWith;
+ this.matchers.assertPromiseIsRejectedWithError = assertPromiseIsRejectedWithError;
+ this.matchers.assertPromiseIsResolved = assertPromiseIsResolved;
+ this.matchers.assertPromiseIsResolvedWith = assertPromiseIsResolvedWith;
+ }
+
+ init(coreContext) {
+ this.coreContext = coreContext;
+ this.extendsMatchers();
+ const expectService = this.coreContext.getDefaultService('expect');
+ expectService.addMatchers(this.matchers);
+ }
+
+ apis() {
+ return {
+ 'expect': function (actualValue) {
+ return this.coreContext.getDefaultService('expect').expect(actualValue);
+ }
+ };
+ }
+}
+
+export default ExpectExtend;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertClose.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertClose.js
new file mode 100644
index 0000000000000000000000000000000000000000..7e692bd25f1c026640978a042a9c9f64b0e8d5d3
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertClose.js
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertClose(actualValue, expected) {
+ if (actualValue === null && expected[0] === null) {
+ throw new Error('actualValue and expected can not be both null!!!');
+ }
+ let result;
+ let diff = Math.abs(expected[0] - actualValue);
+ let actualAbs = Math.abs(actualValue);
+ if ((actualAbs - 0) === 0) {
+ if ((diff - 0) === 0) {
+ result = true;
+ } else {
+ result = false;
+ }
+ } else if (diff / actualAbs < expected[1]) {
+ result = true;
+ } else {
+ result = false;
+ }
+ return {
+ pass: result,
+ message: '|' + actualValue + ' - ' + expected[0] + '|/' + actualValue + ' is not less than ' + expected[1]
+ };
+}
+
+export default assertClose;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertContain.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertContain.js
new file mode 100644
index 0000000000000000000000000000000000000000..7fba0d9755503e5e926f6c1a4e425e0d1cf47570
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertContain.js
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertContain(actualValue, expect) {
+ let result = false;
+ if (Object.prototype.toString.call(actualValue).indexOf('Array')) {
+ for (let i in actualValue) {
+ if (actualValue[i] == expect[0]) {
+ result = true;
+ }
+ }
+ }
+ let type = Object.prototype.toString.call(actualValue);
+ if (type === '[object String]') {
+ result = actualValue.indexOf(expect[0]) >= 0;
+ }
+ return {
+ pass: result,
+ message: 'expect false, ' + actualValue + ' do not have ' + expect[0]
+ };
+}
+
+export default assertContain;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertFail.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertFail.js
new file mode 100644
index 0000000000000000000000000000000000000000..8ab4ac5caef712c75c4eac49dfbbb91d33669d9a
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertFail.js
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertFail() {
+ return {
+ pass: false,
+ message: 'fail '
+ };
+}
+
+export default assertFail;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertFalse.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertFalse.js
new file mode 100644
index 0000000000000000000000000000000000000000..c5008e94f4b2ce13ed35b604811793c76b542347
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertFalse.js
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertFalse(actualValue) {
+ return {
+ pass: (actualValue) === false,
+ message: 'expect false, actualValue is ' + actualValue
+ };
+}
+
+export default assertFalse;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertInstanceOf.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertInstanceOf.js
new file mode 100644
index 0000000000000000000000000000000000000000..1e11b93f7251c67f5455c5007cd7be268aa53b32
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertInstanceOf.js
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertInstanceOf(actualValue, expected) {
+ if (Object.prototype.toString.call(actualValue) == '[object ' + expected[0] + ']') {
+ return {
+ pass: true
+ };
+ } else {
+ return {
+ pass: false,
+ message: actualValue + ' is ' + Object.prototype.toString.call(actualValue) + 'not ' + expected[0]
+ };
+ }
+}
+
+export default assertInstanceOf;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertLarger.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertLarger.js
new file mode 100644
index 0000000000000000000000000000000000000000..a74f4a8cedaf3add9c2dc2d3799081a83198732f
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertLarger.js
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertLarger(actualValue, expected) {
+ return {
+ pass: (actualValue) > expected[0],
+ message: (actualValue) + ' is not larger than ' + expected[0]
+ };
+}
+
+export default assertLarger;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertLargerOrEqual.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertLargerOrEqual.js
new file mode 100644
index 0000000000000000000000000000000000000000..e847e6c217364b7f69c173c66fb98d10efc45ef1
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertLargerOrEqual.js
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertLargerOrEqual(actualValue, expected) {
+ return {
+ pass: (actualValue) >= expected[0],
+ message: (actualValue) + ' is not larger than ' + expected[0]
+ };
+}
+
+export default assertLargerOrEqual;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertLess.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertLess.js
new file mode 100644
index 0000000000000000000000000000000000000000..17e84b0abaeb20804048a5a15c19e0603634846d
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertLess.js
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertLess(actualValue, expected) {
+ return {
+ pass: (actualValue) < expected[0],
+ message: (actualValue) + ' is not less than ' + expected[0]
+ };
+}
+
+export default assertLess;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertLessOrEqual.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertLessOrEqual.js
new file mode 100644
index 0000000000000000000000000000000000000000..f754f97ffa9d24e7852efe2423a1dd35d448af82
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertLessOrEqual.js
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertLessOrEqual(actualValue, expected) {
+ return {
+ pass: (actualValue) <= expected[0],
+ message: (actualValue) + ' is not less than ' + expected[0]
+ };
+}
+
+export default assertLessOrEqual;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertNaN.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertNaN.js
new file mode 100644
index 0000000000000000000000000000000000000000..8d45d6a93b86c5ed325a68b32ff014835993a58e
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertNaN.js
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertNaN(actualValue) {
+ return {
+ pass: actualValue !== actualValue,
+ message: 'expect NaN, actualValue is ' + actualValue
+ };
+}
+
+export default assertNaN;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertNegUnlimited.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertNegUnlimited.js
new file mode 100644
index 0000000000000000000000000000000000000000..ceac555afc826e057970e6cfe9c73b322c672aa2
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertNegUnlimited.js
@@ -0,0 +1,23 @@
+/*
+* Copyright (c) 2022 Huawei Device Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+function assertNegUnlimited(actualValue) {
+ return {
+ pass: actualValue === Number.NEGATIVE_INFINITY,
+ message: 'Expected actualValue not to be -Infinity. actualValue is,' + actualValue
+ };
+}
+
+export default assertNegUnlimited;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertNull.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertNull.js
new file mode 100644
index 0000000000000000000000000000000000000000..53a7bad827323a98d3302a4e7eea679551b459c5
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertNull.js
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertNull(actualValue) {
+ return {
+ pass: (actualValue) === null,
+ message: 'expect null, actualValue is ' + (actualValue)
+ };
+}
+
+export default assertNull;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertPosUnlimited.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertPosUnlimited.js
new file mode 100644
index 0000000000000000000000000000000000000000..6e68c0e2b6c499f4dc3dd56c13e9ea1073a3c54c
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertPosUnlimited.js
@@ -0,0 +1,23 @@
+/*
+* Copyright (c) 2022 Huawei Device Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+function assertPosUnlimited(actualValue) {
+ return {
+ pass: actualValue === Number.POSITIVE_INFINITY,
+ message: 'Expected actualValue is POSITIVE_INFINITY. actualValue is,' + actualValue
+ };
+}
+
+export default assertPosUnlimited;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsPending.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsPending.js
new file mode 100644
index 0000000000000000000000000000000000000000..7e2ca2ce14d50c39554fc1157d6d4eb9329d5c39
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsPending.js
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import isPromiseLike from './isPromiseLike';
+
+function assertPromiseIsPending(actualPromise) {
+ if (!isPromiseLike(actualPromise)) {
+ return Promise.reject().then(function () {
+ }, function () {
+ return {pass: false, message: 'Expected not be called on a promise.'};
+ });
+ }
+ const helper = {};
+ return Promise.race([actualPromise, Promise.resolve(helper)]).then(
+ function (got) {
+ return helper === got ? {pass: true, message: 'actualValue is isPending'}
+ : {
+ pass: false,
+ message: 'expect isPending, actualValue is resolve'
+ };
+ },
+ function () {
+ return {
+ pass: false
+ , message: 'expect isPending, actualValue is reject'
+ };
+ });
+}
+
+export default assertPromiseIsPending;
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsRejected.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsRejected.js
new file mode 100644
index 0000000000000000000000000000000000000000..380075a369a84d6856e7f2db366f704e04302a8d
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsRejected.js
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import isPromiseLike from './isPromiseLike';
+
+function assertPromiseIsRejected(actualPromise) {
+ if (!isPromiseLike(actualPromise)) {
+ return Promise.reject().then(function () {
+ }, function () {
+ return {pass: false, message: 'Expected not be called on a promise.'};
+ });
+ }
+ return actualPromise.then(
+ function (got) {
+ return {
+ pass: false,
+ message: 'expect isRejected, but actualValue is resolve'
+ };
+ },
+ function () {
+ return {pass: true, message: 'actualValue is isRejected'};
+ }
+ );
+}
+
+export default assertPromiseIsRejected;
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsRejectedWith.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsRejectedWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..8179589d5580f9c305d2200b4b197d64ac9d53ae
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsRejectedWith.js
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import isPromiseLike from './isPromiseLike';
+
+function assertPromiseIsRejectedWith(actualPromise, expectedValue) {
+
+ if (!isPromiseLike(actualPromise)) {
+ return Promise.reject().then(function () {
+ }, function () {
+ return {pass: false, message: 'Expected not be called on a promise.'};
+ });
+ }
+
+ function tips(passed) {
+ return ('Expected a promise ' + (passed ? 'not ' : '') +
+ 'to be rejected with ' + JSON.stringify(expectedValue[0]));
+ }
+
+ return actualPromise.then(
+ function (got) {
+ return {
+ pass: false,
+ message: tips(false) + ' but actualValue is resolve'
+ };
+ },
+ function (actualValue) {
+ if (JSON.stringify(actualValue) == JSON.stringify(expectedValue[0])) {
+ return {
+ pass: true,
+ message: 'actualValue was rejected with ' + JSON.stringify(actualValue) + '.'
+ };
+ } else {
+ return {
+ pass: false,
+ message: tips(false) + ' but it was rejected with ' + JSON.stringify(actualValue) + '.'
+ };
+ }
+ }
+ );
+}
+
+export default assertPromiseIsRejectedWith;
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsRejectedWithError.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsRejectedWithError.js
new file mode 100644
index 0000000000000000000000000000000000000000..291af8e5032b7bcd9bcb3e996a39a4fa8ba23157
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsRejectedWithError.js
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import isPromiseLike from './isPromiseLike';
+
+function assertPromiseIsRejectedWithError(actualPromise, expectedValue) {
+ if (!isPromiseLike(actualPromise)) {
+ return Promise.reject().then(function () {
+ }, function () {
+ return {pass: false, message: 'Expected not be called on a promise.'};
+ });
+ }
+ return actualPromise.then(
+ function (got) {
+ return {
+ pass: false,
+ message: 'Expected a promise to be rejected but actualValue is resolve'
+ };
+ },
+ function (actualValue) {
+ return matchError(actualValue, expectedValue);
+ }
+ );
+
+}
+
+function matchError(actualValue, expectedValue) {
+ if (expectedValue.length == 1 && typeof expectedValue[0] === 'function') {
+ if (expectedValue[0].name === actualValue.__proto__.name) {
+ return {pass: true, message: 'actual error type is ' + actualValue.name + '.'};
+ }
+ return {pass: false, message: `except error type is ${expectedValue[0].name},but actual is ${actualValue.name}.`};
+ }
+
+ if (expectedValue.length == 1 && typeof expectedValue[0] === 'string') {
+ if (expectedValue[0] === actualValue.message) {
+ return {pass: true, message: `actual error message is ${actualValue.message}.`};
+ }
+ return {pass: false, message: `except error message ${expectedValue[0]},but actual is ${actualValue.message}.`};
+ }
+
+ if (expectedValue.length == 1) {
+ return {pass: false, message: 'When only one parameter, it should be error type or error message.'};
+ }
+
+ if (expectedValue.length == 2 && typeof expectedValue[0] === 'function' && expectedValue[0].name === actualValue.name) {
+ if (typeof expectedValue[1] === 'string' && actualValue.message === expectedValue[1]) {
+ return {pass: true, message: 'actual error message is ' + actualValue.message + '.'};
+ }
+ return {pass: false, message: `except error message is ${expectedValue[1]},but actual is ${actualValue.message}.`};
+ }
+
+ if (expectedValue.length == 2 && typeof expectedValue[0] === 'function' && expectedValue[0].name !== actualValue.name) {
+ if (typeof expectedValue[1] === 'string' && actualValue.message === expectedValue[1]) {
+ return {pass: false, message: `except error type is ${expectedValue[0].name},but actual is ${actualValue.name}.`};
+ }
+ return {pass: false, message: 'except error type and message are incorrect.'};
+ }
+ if (expectedValue.length > 2) {
+ return {pass: false, message: 'Up to two parameters are supported.'};
+ }
+}
+
+export default assertPromiseIsRejectedWithError;
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsResolved.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsResolved.js
new file mode 100644
index 0000000000000000000000000000000000000000..86f559c32873f27b95d635452d760029de0ed657
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsResolved.js
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import isPromiseLike from './isPromiseLike';
+
+function assertPromiseIsResolved(actualPromise) {
+ if (!isPromiseLike(actualPromise)) {
+ return Promise.reject().then(function () {
+ }, function () {
+ return {pass: false, message: 'Expected not be called on a promise.'};
+ });
+ }
+
+ return actualPromise.then(
+ function (got) {
+ return {pass: true, message: 'actualValue is isResolved'};
+ },
+ function (rej) {
+ return {
+ pass: false,
+ message: 'Expected a promise to be resolved but it was ' +
+ 'rejected with ' + JSON.stringify(rej) + '.'
+ };
+ }
+ );
+}
+
+export default assertPromiseIsResolved;
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsResolvedWith.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsResolvedWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..c6f0ef68fde5b04a589a9fa3c6e2ab2b39acf4d3
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsResolvedWith.js
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import isPromiseLike from './isPromiseLike';
+
+function assertPromiseIsResolvedWith(actualPromise, expectedValue) {
+ if (!isPromiseLike(actualPromise)) {
+ return Promise.reject().then(function () {
+ }, function () {
+ return {pass: false, message: 'Expected not be called on a promise.'};
+ });
+ }
+
+ function tips(passed) {
+ return (
+ 'Expected a promise ' + (passed ? 'not ' : '') +
+ 'to be resolved with ' + JSON.stringify(expectedValue[0]));
+ }
+
+ return actualPromise.then(
+ function (got) {
+ if (JSON.stringify(got) == JSON.stringify(expectedValue[0])) {
+ return {
+ pass: true,
+ message: 'actualValue was resolved with ' + JSON.stringify(got) + '.'
+ };
+ }
+ return {
+ pass: false,
+ message: tips(false) + ' but it was resolved with ' +
+ JSON.stringify(got) + '.'
+ };
+ },
+ function (rej) {
+ return {
+ pass: false,
+ message: tips(false) + ' but it was rejected with ' + JSON.stringify(rej) + '.'
+ };
+ }
+ );
+}
+
+export default assertPromiseIsResolvedWith;
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertThrowError.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertThrowError.js
new file mode 100644
index 0000000000000000000000000000000000000000..c4544a7f825bcecd1a07d5e98dd9a7b99d237278
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertThrowError.js
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertThrowError(actualValue, expected) {
+ let result = false;
+ let message = '';
+ let err;
+ if (typeof actualValue !== 'function') {
+ throw new Error('actualValue is not a function');
+ }
+ try {
+ actualValue();
+ return {
+ pass: result,
+ message: ' An error is not thrown while it is expected!'
+ };
+ } catch (e) {
+ err = e;
+ }
+ if (err instanceof Error) {
+ let type = typeof expected[0];
+ if (type === 'function') {
+ result = err.constructor.name === expected[0].name;
+ message = 'expected throw failed , ' + err.constructor.name + ' is not ' + expected[0].name;
+ }else if(type === 'string'){
+ result = err.message.includes(expected[0]);
+ message = 'expected throw failed , ' + err.message + ' is not ' + expected[0];
+ }
+ }
+ return {
+ pass: result,
+ message: message
+ };
+}
+
+export default assertThrowError;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertUndefined.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertUndefined.js
new file mode 100644
index 0000000000000000000000000000000000000000..61f092d715dd1630297518b59ff13ef0940991e1
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/assertUndefined.js
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertUndefined(actualValue) {
+ return {
+ pass: undefined === (actualValue),
+ message: 'expect Undefined, actualValue is ' + (actualValue)
+ };
+}
+
+export default assertUndefined;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/deepEquals/DeepTypeUtils.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/deepEquals/DeepTypeUtils.js
new file mode 100644
index 0000000000000000000000000000000000000000..916824d9cb77a75d1fb35bc3500d7598bfc73e80
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/deepEquals/DeepTypeUtils.js
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class DeepTypeUtils {
+ static getType(value) {
+ return Object.prototype.toString.apply(value);
+ }
+ static isA(typeName, value) {
+ return this.getType(value) === '[object ' + typeName + ']';
+ }
+ static isAsymmetricEqualityTester(obj) {
+ return obj ? this.isA('Function', obj.asymmetricMatch) : false;
+ }
+
+ /**
+ * 是否是function
+ * @param value
+ */
+ static isFunction(value) {
+ return this.isA('Function', value);
+ }
+
+ /**
+ * 是否是undefined
+ * @param obj
+ */
+ static isUndefined(obj) {
+ return obj === void 0;
+ }
+
+ /**
+ * 是否是Node
+ * @param obj
+ */
+ static isDomNode(obj) {
+ return obj !== null &&
+ typeof obj === 'object' &&
+ typeof obj.nodeType === 'number' &&
+ typeof obj.nodeName === 'string';
+ }
+
+ /**
+ * 是否是promise对象
+ * @param obj
+ */
+ static isPromise(obj) {
+ return !!obj && obj.constructor === Promise;
+ };
+ /**
+ * 是否是map对象
+ * @param obj
+ */
+ static isMap(obj) {
+ return (
+ obj !== null &&
+ typeof obj !== 'undefined' &&
+ obj.constructor === Map
+ );
+ }
+
+ /**
+ * 是否是set对象
+ * @param obj 对象
+ */
+ static isSet(obj) {
+ return (
+ obj !== null &&
+ typeof obj !== 'undefined' &&
+ obj.constructor === Set
+ );
+ }
+
+ /**
+ * 对象是否有key属性
+ * @param obj 对象
+ * @param key 对象属性名称
+ */
+ static has(obj, key) {
+ return Object.prototype.hasOwnProperty.call(obj, key);
+ }
+
+ /**
+ * 获取对象的自有属性
+ * @param obj 对象
+ * @param isArray 是否是数组,[object Array]
+ */
+ static keys(obj, isArray) {
+ const extraKeys = [];
+ // 获取对象所有属性
+ const allKeys = this.getAllKeys(obj);
+ if (!isArray) {
+ return allKeys;
+ }
+ if (allKeys.length === 0) {
+ return allKeys;
+ }
+ for (const k of allKeys) {
+ if (typeof k === 'symbol' || !/^[0-9]+$/.test(k)) {
+ extraKeys.push(k);
+ }
+ }
+ return extraKeys;
+ }
+
+ /**
+ * 获取obj对象的所有属性
+ * @param obj obj对象
+ */
+ static getAllKeys(obj) {
+ const keys = [];
+ for (let key in obj) {
+ if (this.has(obj, key)) {
+ keys.push(key);
+ }
+ }
+ const symbols = Object.getOwnPropertySymbols(obj);
+ for (const sym of symbols) {
+ // obj.propertyIsEnumerable(sym)
+ if (Object.prototype.propertyIsEnumerable.call(obj, sym)) {
+ keys.push(sym);
+ }
+ }
+ return keys;
+ }
+
+}
+export default DeepTypeUtils;
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/deepEquals/assertDeepEquals.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/deepEquals/assertDeepEquals.js
new file mode 100644
index 0000000000000000000000000000000000000000..60de33f7e1afdcfaf205c8c56484ef33dfda8160
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/deepEquals/assertDeepEquals.js
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import DeepTypeUtils from './DeepTypeUtils';
+function assertDeepEquals(actualValue, expected) {
+ let result = eq(actualValue, expected[0])
+ let msg = logMsg(actualValue, expected[0]);
+ return {
+ pass: result,
+ message: msg
+ };
+}
+
+/**
+ * 获取失败显示日志
+ * @param actualValue 实际对象
+ * @param expected 期待比较对象
+ */
+function logMsg(actualValue, expected) {
+ // 获取a的对象名称
+ const aClassName = Object.prototype.toString.call(actualValue);
+ const bClassName = Object.prototype.toString.call(expected);
+ let actualMsg;
+ let expectMsg;
+ if (aClassName == '[object Function]') {
+ actualMsg = 'actualValue Function';
+ } else if (aClassName == '[object Promise]') {
+ actualMsg = 'actualValue Promise';
+ } else if (aClassName == '[object Set]' || aClassName == '[object Map]') {
+ actualMsg = JSON.stringify(Array.from(actualValue));
+ } else if (aClassName == '[object RegExp]') {
+ actualMsg = JSON.stringify(actualValue.source.replace('\\',''));
+ } else if (aClassName == '[object BigInt]') {
+ actualMsg = actualValue;
+ } else if (aClassName == '[object Error]') {
+ actualMsg = actualValue.message;
+ } else if (aClassName == '[object ArrayBuffer]') {
+ actualMsg = actualValue.byteLength;
+ }
+ else {
+ actualMsg = JSON.stringify(actualValue);
+ }
+ if (bClassName == '[object Function]') {
+ expectMsg = 'expected Function';
+ } else if (bClassName == '[object Promise]') {
+ expectMsg = 'expected Promise';
+ } else if (bClassName == '[object Set]' || bClassName == '[object Map]') {
+ expectMsg = JSON.stringify(Array.from(expected));
+ } else if (bClassName == '[object RegExp]') {
+ expectMsg = JSON.stringify(expected.source.replace('\\',''));
+ } else if (bClassName == '[object BigInt]') {
+ expectMsg = expected;
+ } else if (bClassName == '[object Error]') {
+ expectMsg = expected.message;
+ } else if (bClassName == '[object ArrayBuffer]') {
+ expectMsg = expected.byteLength;
+ }
+ else {
+ expectMsg = JSON.stringify(expected);
+ }
+ return actualMsg + ' is not deep equal ' + expectMsg;
+}
+
+function eq(a, b) {
+ let result = true;
+
+ if (a === b) {
+ result = a !== 0 || 1 / a === 1 / b;
+ return result;
+ }
+
+ if (a === null || b === null) {
+ result = a === b;
+ return result;
+ }
+ // 获取a的对象名称
+ const aClassName = Object.prototype.toString.call(a);
+ const bClassName = Object.prototype.toString.call(b);
+ // 不同类型不同对象
+ if (aClassName !== bClassName) {
+ return false;
+ }
+ if (aClassName === '[object String]' || aClassName === '[object Number]' || aClassName === '[object Date]' ||
+ aClassName === '[object Boolean]' || aClassName === '[object ArrayBuffer]' ||
+ aClassName === '[object RegExp]' || aClassName === '[object Error]') {
+ result = isEqualSampleObj(a, b);
+ return result;
+ }
+
+ if (typeof a !== 'object' || typeof b !== 'object') {
+ return false;
+ }
+
+ if (DeepTypeUtils.isDomNode(a) || DeepTypeUtils.isPromise(a) || DeepTypeUtils.isFunction(a)) {
+ result = isEqualNodeOrPromiseOrFunction(a, b);
+ return result;
+ }
+
+ if (aClassName === '[object Array]' || aClassName === '[object Map]' || aClassName === '[object Set]') {
+ result = isEqualCollection(a, b);
+ return result;
+ }
+
+ result = isEqualObj(a, b);
+ return result;
+}
+
+function isEqualNodeOrPromiseOrFunction(a, b) {
+ let equalNodeOrPromiseOrFunction = true;
+ if (DeepTypeUtils.isDomNode(a) && DeepTypeUtils.isDomNode(b)) {
+ const aIsDomNode = DeepTypeUtils.isDomNode(a);
+ const bIsDomNode = DeepTypeUtils.isDomNode(b);
+ if (aIsDomNode && bIsDomNode) {
+ // At first try to use DOM3 method isEqualNode
+ equalNodeOrPromiseOrFunction = a.isEqualNode(b);
+ return equalNodeOrPromiseOrFunction;
+ }
+ if (aIsDomNode || bIsDomNode) {
+ equalNodeOrPromiseOrFunction = false;
+ return false;
+ }
+ }
+
+ if (DeepTypeUtils.isPromise(a) && DeepTypeUtils.isPromise(b)) {
+ const aIsPromise = DeepTypeUtils.isPromise(a);
+ const bIsPromise = DeepTypeUtils.isPromise(b);
+ // 俩个Promise对象
+ if (aIsPromise && bIsPromise) {
+ equalNodeOrPromiseOrFunction = a === b;
+ return a === b;
+ }
+ }
+ if (DeepTypeUtils.isFunction(a) && DeepTypeUtils.isFunction(b)) {
+ // 俩个函数对象
+ const aCtor = a.constructor,
+ bCtor = b.constructor;
+ if (
+ aCtor !== bCtor &&
+ DeepTypeUtils.isFunction(aCtor) &&
+ DeepTypeUtils.isFunction(bCtor) &&
+ a instanceof aCtor &&
+ b instanceof bCtor &&
+ !(aCtor instanceof aCtor && bCtor instanceof bCtor)
+ ) {
+ equalNodeOrPromiseOrFunction = false;
+ return false;
+ }
+ }
+ return equalNodeOrPromiseOrFunction;
+}
+
+function isEqualCollection(a, b) {
+ let equalCollection = true;
+ // 获取a的对象名称
+ const aClassName = Object.prototype.toString.call(a);
+ const bClassName = Object.prototype.toString.call(b);
+ // 都是数组
+ if (aClassName === '[object Array]') {
+ equalCollection = isEqualArray(a, b);
+ return equalCollection;
+ }
+
+ // 都是Map
+ if (DeepTypeUtils.isMap(a) && DeepTypeUtils.isMap(b)) {
+ equalCollection = isEqualMap(a, b);
+ return equalCollection;
+ }
+
+ // 都是Set
+ if (DeepTypeUtils.isSet(a) && DeepTypeUtils.isSet(b)) {
+ equalCollection = isEqualSet(a, b);
+ return equalCollection;
+ }
+
+ return true;
+}
+
+function isEqualSampleObj(a, b) {
+ let equalSampleObj = true;
+ const aClassName = Object.prototype.toString.call(a);
+ const bClassName = Object.prototype.toString.call(b);
+ // 俩个string对象
+ if (aClassName === '[object String]') {
+ equalSampleObj = a === String(b);
+ return equalSampleObj;
+ }
+ // 俩个Number对象
+ if (aClassName === '[object Number]') {
+ equalSampleObj = a !== +a ? b !== +b : a === 0 && b === 0 ? 1 / a === 1 / b : a === +b;
+ return equalSampleObj;
+ }
+
+ // 俩个Date对象/ boolean对象
+ if (aClassName === '[object Date]' || aClassName === '[object Boolean]') {
+ equalSampleObj = +a === +b;
+ return equalSampleObj;
+ }
+
+ // 俩个ArrayBuffer
+ if (aClassName === '[object ArrayBuffer]') {
+ equalSampleObj = eq(new Uint8Array(a), new Uint8Array(b));
+ return equalSampleObj;
+ }
+
+ // 正则表达式
+ if (aClassName === '[object RegExp]') {
+ return (
+ a.source === b.source &&
+ a.global === b.global &&
+ a.multiline === b.multiline &&
+ a.ignoreCase === b.ignoreCase
+ );
+ }
+
+ if (a instanceof Error && b instanceof Error) {
+ equalSampleObj = a.message === b.message;
+ return equalSampleObj;
+ }
+
+ return equalSampleObj;
+}
+
+function isEqualObj(a, b) {
+ let equalObj = true;
+ const aClassName = Object.prototype.toString.call(a);
+ const bClassName = Object.prototype.toString.call(b);
+ const aKeys = DeepTypeUtils.keys(a, aClassName === '[object Array]');
+ let size = aKeys.length;
+
+ // 俩个对象属性长度不一致, 俩对象不相同
+ if (DeepTypeUtils.keys(b, bClassName === '[object Array]').length !== size) {
+ return false;
+ }
+
+ // 俩对象属性数量相同, 递归比较每个属性值得值
+ for (const key of aKeys) {
+ // b 没有 key 属性
+ if (!DeepTypeUtils.has(b, key)) {
+ equalObj = false;
+ continue;
+ }
+ if (!eq(a[key], b[key])) {
+ equalObj = false;
+ }
+ }
+ return equalObj;
+}
+
+function isEqualArray(a, b) {
+ let equalArray = true;
+ const aLength = a.length;
+ const bLength = b.length;
+ if (aLength !== bLength) {
+ // 数组长度不同,不是同一个对象
+ return false;
+ }
+ for (let i = 0; i < aLength || i < bLength; i++) {
+ // 递归每一个元素是否相同
+ equalArray = eq(i < aLength ? a[i] : void 0, i < bLength ? b[i] : void 0) && equalArray;
+ }
+ return equalArray;
+}
+
+function isEqualMap(a, b) {
+ let equalMap = true;
+ if (a.size !== b.size) {
+ return false;
+ }
+ const keysA = [];
+ const keysB = [];
+ a.forEach(function(valueA, keyA) {
+ keysA.push(keyA);
+ });
+ b.forEach(function(valueB, keyB) {
+ keysB.push(keyB);
+ });
+ const mapKeys = [keysA, keysB];
+ const cmpKeys = [keysB, keysA];
+ for (let i = 0; equalMap && i < mapKeys.length; i++) {
+ const mapIter = mapKeys[i];
+ const cmpIter = cmpKeys[i];
+
+ for (let j = 0; equalMap && j < mapIter.length; j++) {
+ const mapKey = mapIter[j];
+ const cmpKey = cmpIter[j];
+ const mapValueA = a.get(mapKey);
+ let mapValueB;
+ if (eq(mapKey, cmpKey)) {
+ mapValueB = b.get(cmpKey);
+ } else {
+ mapValueB = b.get(mapKey);
+ }
+ equalMap = eq(mapValueA, mapValueB);
+ }
+ }
+ return equalMap;
+}
+
+function isEqualSet(a, b) {
+ let equalSet = true;
+ if (a.size !== b.size) {
+ return false;
+ }
+ const valuesA = [];
+ a.forEach(function(valueA) {
+ valuesA.push(valueA);
+ });
+ const valuesB = [];
+ b.forEach(function(valueB) {
+ valuesB.push(valueB);
+ });
+ const setPairs = [[valuesA, valuesB], [valuesB, valuesA]];
+ for (let i = 0; equalSet && i < setPairs.length; i++) {
+ const baseValues = setPairs[i][0];
+ const otherValues = setPairs[i][1];
+ for (const baseValue of baseValues) {
+ let found = false;
+ for (let j = 0; !found && j < otherValues.length; j++) {
+ const otherValue = otherValues[j];
+ // 深度比较对象
+ found = eq(baseValue, otherValue);
+ }
+ equalSet = equalSet && found;
+ }
+ }
+ return equalSet;
+}
+
+export default assertDeepEquals;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/isPromiseLike.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/isPromiseLike.js
new file mode 100644
index 0000000000000000000000000000000000000000..015ab19a2a0c4872d7cb490b61f8e1dd6a8ac90b
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/assert/isPromiseLike.js
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function isPromiseLike(obj) {
+ return !!obj && isFunction_(obj.then);
+}
+
+function isFunction_(value) {
+ return isA_('Function', value);
+}
+
+function isA_(typeName, value) {
+ return getType_(value) === '[object ' + typeName + ']';
+}
+
+function getType_(value) {
+ return Object.prototype.toString.apply(value);
+}
+
+export default isPromiseLike;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/config/DataDriver.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/config/DataDriver.js
new file mode 100644
index 0000000000000000000000000000000000000000..639dffc9cdb912f1f33a6ccb61868c9ed7c695bf
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/config/DataDriver.js
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+const SUITES_KEY = 'suites';
+const SPECS_KEY = 'items';
+const DESCRIBE_KEY = 'describe';
+const IT_KEY = 'it';
+const PARAMS_KEY = 'params';
+const STRESS_KEY = 'stress';
+
+class ObjectUtils {
+ static get(object, name, defaultValue) {
+ let result = defaultValue;
+ for (const key in object) {
+ if (key === name) {
+ return object[key];
+ }
+ }
+ return result;
+ }
+
+ static has(object, key) {
+ return Object.prototype.hasOwnProperty.call(object, key);
+ }
+}
+
+class DataDriver {
+ constructor(attr) {
+ this.id = 'dataDriver';
+ this.data = attr.data || {};
+ }
+
+ init(coreContext) {
+ this.coreContext = coreContext;
+ this.suiteService = this.coreContext.getDefaultService('suite');
+ this.specService = this.coreContext.getDefaultService('spec');
+ }
+
+ getSpecParams() {
+ let specParams = [];
+ let suiteDesc = this.suiteService.getCurrentRunningSuite().description;
+ let specDesc = this.specService.getCurrentRunningSpec().description;
+ let suites = ObjectUtils.get(this.data, SUITES_KEY, []);
+ for (const suiteItem of suites) {
+ let describeValue = ObjectUtils.get(suiteItem, DESCRIBE_KEY, '');
+ if (ObjectUtils.has(suiteItem, DESCRIBE_KEY) && (typeof describeValue === 'object') && describeValue.constructor === Array && describeValue.includes(suiteDesc)) {
+ let specs = ObjectUtils.get(suiteItem, SPECS_KEY, []);
+ for (const specItem of specs) {
+ if (ObjectUtils.has(specItem, IT_KEY) && ObjectUtils.get(specItem, IT_KEY) === specDesc) {
+ return ObjectUtils.get(specItem, PARAMS_KEY, specParams);
+ }
+ }
+ }
+ }
+ return specParams;
+ }
+
+ getSuiteParams() {
+ let suiteParams = {};
+ let suiteDesc = this.suiteService.getCurrentRunningSuite().description;
+ let suites = ObjectUtils.get(this.data, SUITES_KEY, []);
+ for (const suiteItem of suites) {
+ let describeValue = ObjectUtils.get(suiteItem, DESCRIBE_KEY, []);
+ if (ObjectUtils.has(suiteItem, DESCRIBE_KEY) && (typeof describeValue === 'object') && describeValue.constructor === Array && describeValue.includes(suiteDesc)) {
+ suiteParams = Object.assign({}, suiteParams, ObjectUtils.get(suiteItem, PARAMS_KEY, suiteParams));
+ }
+ }
+ return suiteParams;
+ }
+
+ getSpecStress(specDesc) {
+ let stress = 1;
+ let suiteDesc = this.suiteService.getCurrentRunningSuite().description;
+ let suites = ObjectUtils.get(this.data, SUITES_KEY, []);
+ for (const suiteItem of suites) {
+ let describeValue = ObjectUtils.get(suiteItem, DESCRIBE_KEY, '');
+ if (ObjectUtils.has(suiteItem, DESCRIBE_KEY) && (typeof describeValue === 'object') && describeValue.constructor === Array && describeValue.includes(suiteDesc)) {
+ let specs = ObjectUtils.get(suiteItem, SPECS_KEY, []);
+ for (const specItem of specs) {
+ if (ObjectUtils.has(specItem, IT_KEY) && ObjectUtils.get(specItem, IT_KEY) === specDesc) {
+ let tempStress = ObjectUtils.get(specItem, STRESS_KEY, stress);
+ return (Number.isInteger(tempStress) && tempStress >= 1) ? tempStress : stress;
+ }
+ }
+ }
+ }
+ return stress;
+ }
+
+ getSuiteStress(suiteDesc) {
+ let stress = 1;
+ let suites = ObjectUtils.get(this.data, SUITES_KEY, []);
+ for (const suiteItem of suites) {
+ let describeValue = ObjectUtils.get(suiteItem, DESCRIBE_KEY, []);
+ if (ObjectUtils.has(suiteItem, DESCRIBE_KEY) && (typeof describeValue === 'object') && describeValue.constructor === Array && describeValue.includes(suiteDesc)) {
+ let tempStress = ObjectUtils.get(suiteItem, STRESS_KEY, stress);
+ return (Number.isInteger(tempStress) && tempStress >= 1) ? tempStress : stress;
+ }
+ }
+ return stress;
+ }
+}
+
+export default DataDriver;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/config/Filter.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/config/Filter.js
new file mode 100644
index 0000000000000000000000000000000000000000..b07e6c681bfff618cc9f5ca92ec85d1d9880202d
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/config/Filter.js
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { LEVEL, SIZE, TESTTYPE } from '../../Constant';
+
+class ClassFilter {
+ constructor(suiteName, itName, params) {
+ this.suiteName = suiteName;
+ this.itName = itName;
+ this.params = params;
+ }
+
+ filterSuite() {
+ return !this.params.split(',').map(item => item.split('#')[0]).map(item => item == this.suiteName).reduce((pre, cur) => pre || cur, false);
+ }
+
+ filterIt() {
+ let classArray = this.params.split(',') || [];
+ let suiteFilterResult = classArray.filter(item => !item.includes('#')).map(item => item == this.suiteName).reduce((pre, cur) => pre || cur, false);
+ let itFilterResult = classArray.filter(item => item.includes('#')).map(item => item == (this.suiteName + '#' + this.itName)).reduce((pre, cur) => pre || cur, false);
+ return !(suiteFilterResult || itFilterResult);
+ }
+}
+
+class NotClassFilter {
+ constructor(suiteName, itName, params) {
+ this.suiteName = suiteName;
+ this.itName = itName;
+ this.params = params;
+ }
+
+ filterSuite() {
+ return this.params.split(',').map(item => item == this.suiteName).reduce((pre, cur) => pre || cur, false);
+ }
+
+ filterIt() {
+ return this.params.split(',').some(item => item == (this.suiteName + '#' + this.itName));
+ }
+}
+
+class SuiteAndItNameFilter {
+ constructor(suiteName, itName, params) {
+ this.suiteName = suiteName;
+ this.itName = itName;
+ this.params = params;
+ }
+
+ filterSuite() {
+ return !this.params.split(',').map(item => item == this.suiteName).reduce((pre, cur) => pre || cur, false);
+ }
+
+ filterIt() {
+ return !this.params.split(',').map(item => item == this.itName).reduce((pre, cur) => pre || cur, false);
+ }
+}
+
+
+class TestTypesFilter {
+ constructor(suiteName, itName, fi, params) {
+ this.suiteName = suiteName;
+ this.itName = itName;
+ this.params = params;
+ this.fi = fi;
+ }
+
+ filterIt() {
+ return !((this.params === (this.fi & this.params)) || this.fi === 0);
+ }
+}
+
+class NestFilter {
+ filterNestName(targetSuiteArray, targetSpecArray, suiteStack, desc) {
+ let targetSuiteName = '';
+ for (let key in suiteStack) {
+ targetSuiteName = targetSuiteName + '.' + suiteStack[key].description;
+ }
+ targetSuiteName = targetSuiteName.substring(2);
+ const targetSpecName = targetSuiteName + '#' + desc;
+ let isFilter = true;
+ if (targetSpecArray.includes(targetSpecName)) {
+ return false;
+ }
+ for (let index in targetSuiteArray) {
+ if (targetSuiteName.startsWith(targetSuiteArray[index])) {
+ return false;
+ }
+ }
+ return isFilter;
+ }
+
+ filterNotClass(notClass, suiteStack, desc) {
+ let isFilterNotClass = false;
+ if (notClass != null) {
+ let notClassArray = notClass.split(',');
+ let targetSuiteName = '';
+ for (let key in suiteStack) {
+ targetSuiteName = targetSuiteName + '.' + suiteStack[key].description;
+ }
+ targetSuiteName = targetSuiteName.substring(2);
+ const targetSpecName = targetSuiteName + '#' + desc;
+ if (notClassArray.includes(targetSpecName) || notClassArray.some(key => targetSpecName.startsWith(key))) {
+ isFilterNotClass = true;
+ }
+ }
+ return isFilterNotClass;
+ }
+
+ filterLevelOrSizeOrTestType(level, size, testType, filter) {
+ let result = false;
+ if (filter === 0 || filter === '0') {
+ return result;
+ }
+ if (level == null && size == null && testType == null) {
+ return result;
+ }
+ if (level != null) {
+ let levelFilter = LEVEL[`${level}`];
+ result = result || filter === levelFilter;
+ }
+ if (size != null) {
+ let sizeFilter = SIZE[`${size}`];
+ result = result || filter === sizeFilter;
+ }
+ if (testType != null) {
+ let testTypeFilter = TESTTYPE[`${testType}`];
+ result = result || filter === testTypeFilter;
+ }
+ return !result;
+ }
+}
+export { ClassFilter, NotClassFilter, SuiteAndItNameFilter, TestTypesFilter, NestFilter };
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/config/configService.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/config/configService.js
new file mode 100644
index 0000000000000000000000000000000000000000..17674d8cf7e2343bcb4a14ad47eb11cd03c15aac
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/config/configService.js
@@ -0,0 +1,299 @@
+/*
+ * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { ClassFilter, NotClassFilter, SuiteAndItNameFilter, TestTypesFilter, NestFilter } from './Filter';
+import { TAG, TESTTYPE, LEVEL, SIZE, KEYSET } from '../../Constant';
+const STRESS_RULE = /^[1-9]\d*$/;
+
+class ConfigService {
+ constructor(attr) {
+ this.id = attr.id;
+ this.supportAsync = true; // 默认异步处理测试用例
+ this.random = false;
+ this.filterValid = [];
+ this.filter = 0;
+ this.flag = false;
+ this.suite = null;
+ this.itName = null;
+ this.testType = null;
+ this.level = null;
+ this.size = null;
+ this.class = null;
+ this.notClass = null;
+ this.timeout = null;
+ // 遇错即停模式配置
+ this.breakOnError = false;
+ // 压力测试配置
+ this.stress = null;
+ this.skipMessage = false;
+ this.runSkipped = '';
+ this.filterXdescribe = [];
+ }
+
+ init(coreContext) {
+ this.coreContext = coreContext;
+ }
+
+ isNormalInteger(str) {
+ const n = Math.floor(Number(str));
+ return n !== Infinity && String(n) === String(str) && n >= 0;
+ }
+
+
+ getStress() {
+ if (this.stress === undefined || this.stress === '' || this.stress === null) {
+ return 1;
+ }
+ return !this.stress.match(STRESS_RULE) ? 1 : Number.parseInt(this.stress);
+ }
+
+ basicParamValidCheck(params) {
+ let size = params.size;
+ if (size !== undefined && size !== '' && size !== null) {
+ let sizeArray = ['small', 'medium', 'large'];
+ if (sizeArray.indexOf(size) === -1) {
+ this.filterValid.push('size:' + size);
+ }
+ }
+ let level = params.level;
+ if (level !== undefined && level !== '' && level !== null) {
+ let levelArray = ['0', '1', '2', '3', '4'];
+ if (levelArray.indexOf(level) === -1) {
+ this.filterValid.push('level:' + level);
+ }
+ }
+ let testType = params.testType;
+ if (testType !== undefined && testType !== '' && testType !== null) {
+ let testTypeArray = ['function', 'performance', 'power', 'reliability', 'security',
+ 'global', 'compatibility', 'user', 'standard', 'safety', 'resilience'];
+ if (testTypeArray.indexOf(testType) === -1) {
+ this.filterValid.push('testType:' + testType);
+ }
+ }
+ }
+
+ filterParamValidCheck(params) {
+ let timeout = params.timeout;
+ if (timeout !== undefined && timeout !== '' && timeout !== null) {
+ if (!this.isNormalInteger(timeout)) {
+ this.filterValid.push('timeout:' + timeout);
+ }
+ }
+
+ let paramKeys = ['dryRun', 'random', 'breakOnError', 'coverage', 'skipMessage'];
+ for (const key of paramKeys) {
+ if (params[key] !== undefined && params[key] !== 'true' && params[key] !== 'false') {
+ this.filterValid.push(`${key}:${params[key]}`);
+ }
+ }
+
+ // 压力测试参数验证,正整数
+ if (params.stress !== undefined && params.stress !== '' && params.stress !== null) {
+ if (!params.stress.match(STRESS_RULE)) {
+ this.filterValid.push('stress:' + params.stress);
+ }
+ }
+
+ let nameRule = /^[A-Za-z]{1}[\w#,.]*$/;
+ let paramClassKeys = ['class', 'notClass'];
+ for (const key of paramClassKeys) {
+ if (params[key] !== undefined && params[key] !== '' && params[key] !== null) {
+ let classArray = params[key].split(',');
+ classArray.forEach(item => !item.match(nameRule) ? this.filterValid.push(`${key}:${params[key]}`) : null);
+ }
+ }
+ }
+
+ setConfig(params) {
+ this.basicParamValidCheck(params);
+ this.filterParamValidCheck(params);
+ try {
+ this.class = params.class;
+ this.notClass = params.notClass;
+ this.flag = params.flag || { flag: false };
+ this.suite = params.suite;
+ this.itName = params.itName;
+ this.filter = params.filter;
+ this.testType = params.testType;
+ this.level = params.level;
+ this.size = params.size;
+ this.timeout = params.timeout;
+ this.dryRun = params.dryRun;
+ this.breakOnError = params.breakOnError;
+ this.random = params.random === 'true' ? true : false;
+ this.stress = params.stress;
+ this.coverage = params.coverage;
+ this.skipMessage = params.skipMessage;
+ this.runSkipped = params.runSkipped;
+ this.filterParam = {
+ testType: TESTTYPE,
+ level: LEVEL,
+ size: SIZE
+ };
+ this.parseParams();
+ } catch (err) {
+ console.info(`${TAG}setConfig error: ${err.message}`);
+ }
+ }
+
+ parseParams() {
+ if (this.filter != null) {
+ return;
+ }
+ let testTypeFilter = 0;
+ let sizeFilter = 0;
+ let levelFilter = 0;
+ if (this.testType != null) {
+ testTypeFilter = this.testType.split(',')
+ .map(item => this.filterParam.testType[item] || 0)
+ .reduce((pre, cur) => pre | cur, 0);
+ }
+ if (this.level != null) {
+ levelFilter = this.level.split(',')
+ .map(item => this.filterParam.level[item] || 0)
+ .reduce((pre, cur) => pre | cur, 0);
+ }
+ if (this.size != null) {
+ sizeFilter = this.size.split(',')
+ .map(item => this.filterParam.size[item] || 0)
+ .reduce((pre, cur) => pre | cur, 0);
+ }
+ this.filter = testTypeFilter | sizeFilter | levelFilter;
+ console.info(`${TAG}filter params:${this.filter}`);
+ }
+
+ isCurrentSuite(description) {
+ if (this.suite !== undefined && this.suite !== '' && this.suite !== null) {
+ let suiteArray = this.suite.split(',');
+ return suiteArray.indexOf(description) !== -1;
+ }
+ return false;
+ }
+
+ filterSuite(currentSuiteName) {
+ let filterArray = [];
+ if (this.suite !== undefined && this.suite !== '' && this.suite !== null) {
+ filterArray.push(new SuiteAndItNameFilter(currentSuiteName, '', this.suite));
+ }
+ if (this.class !== undefined && this.class !== '' && this.class !== null) {
+ filterArray.push(new ClassFilter(currentSuiteName, '', this.class));
+ }
+ if (this.notClass !== undefined && this.notClass !== '' && this.notClass !== null) {
+ filterArray.push(new NotClassFilter(currentSuiteName, '', this.notClass));
+ }
+
+ let result = filterArray.map(item => item.filterSuite()).reduce((pre, cur) => pre || cur, false);
+ return result;
+ }
+
+ filterDesc(currentSuiteName, desc, fi, coreContext) {
+ let filterArray = [];
+ if (this.itName !== undefined && this.itName !== '' && this.itName !== null) {
+ filterArray.push(new SuiteAndItNameFilter(currentSuiteName, desc, this.itName));
+ }
+ if (this.class !== undefined && this.class !== '' && this.class !== null) {
+ filterArray.push(new ClassFilter(currentSuiteName, desc, this.class));
+ }
+ if (this.notClass !== undefined && this.notClass !== '' && this.notClass !== null) {
+ filterArray.push(new NotClassFilter(currentSuiteName, desc, this.notClass));
+ }
+ if (typeof (this.filter) !== 'undefined' && this.filter !== 0 && fi !== 0) {
+ filterArray.push(new TestTypesFilter('', '', fi, this.filter));
+ }
+ let result = filterArray.map(item => item.filterIt()).reduce((pre, cur) => pre || cur, false);
+ return result;
+ }
+
+ filterWithNest(desc, filter) {
+ let filterArray = [];
+ const nestFilter = new NestFilter();
+ const targetSuiteArray = this.coreContext.getDefaultService('suite').targetSuiteArray;
+ const targetSpecArray = this.coreContext.getDefaultService('suite').targetSpecArray;
+ const suiteStack = this.coreContext.getDefaultService('suite').suitesStack;
+ let isFilter = nestFilter.filterNestName(targetSuiteArray, targetSpecArray, suiteStack, desc);
+ const isFullRun = this.coreContext.getDefaultService('suite').fullRun;
+ if (typeof (this.filter) !== 'undefined' && this.filter !== 0 && filter !== 0) {
+ filterArray.push(new TestTypesFilter('', '', filter, this.filter));
+ return filterArray.map(item => item.filterIt()).reduce((pre, cur) => pre || cur, false);
+ }
+ if (isFilter && !isFullRun) {
+ return true;
+ }
+ return nestFilter.filterNotClass(this.notClass, suiteStack, desc);
+
+ }
+
+ isRandom() {
+ return this.random || false;
+ }
+
+ isBreakOnError() {
+ return this.breakOnError !== 'true' ? false : true;
+ }
+
+ setSupportAsync(value) {
+ this.supportAsync = value;
+ }
+
+ isSupportAsync() {
+ return this.supportAsync;
+ }
+
+ translateParams(parameters) {
+ const keySet = new Set(KEYSET);
+ let targetParams = {};
+ for (const key in parameters) {
+ if (keySet.has(key)) {
+ var newKey = key.replace('-s ', '');
+ targetParams[newKey] = parameters[key];
+ }
+ }
+ return targetParams;
+ }
+ translateParamsToString(parameters) {
+ const keySet = new Set(KEYSET);
+ let targetParams = '';
+ for (const key in parameters) {
+ if (keySet.has(key)) {
+ targetParams += ' ' + key + ' ' + parameters[key];
+ }
+ }
+ return targetParams.trim();
+ }
+
+ execute() {
+ }
+
+ checkIfSuiteInSkipRun(desc) {
+ return this.runSkipped.split(',').some(item => {
+ return item === desc || item.startsWith(desc + '.') || item.startsWith(desc + '#') || desc.startsWith(item + '.') || this.runSkipped === 'skipped';
+ });
+ }
+
+ checkIfSpecInSkipRun(desc) {
+ return this.runSkipped.split(',').some(item => {
+ if (item.includes('#')) {
+ return item === desc;
+ } else {
+ return desc.startsWith(item + '.') || desc.startsWith(item + '#') || this.runSkipped === 'skipped';
+ }
+ }
+ );
+ }
+}
+
+export {
+ ConfigService
+};
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/coverage/coverageCollect.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/coverage/coverageCollect.js
new file mode 100644
index 0000000000000000000000000000000000000000..334a33db9561dd2070c4081457632decf2589b83
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/coverage/coverageCollect.js
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2023 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import SysTestKit from '../kit/SysTestKit';
+import fs from '@ohos.file.fs';
+import {TAG} from '../../Constant';
+
+const jsCoverageFileName = 'js_coverage.json';
+
+export async function collectCoverageData() {
+ if (globalThis.__coverage__ === undefined) {
+ console.info(`${TAG} globalThis not have coverage`);
+ return;
+ }
+ const strJson = JSON.stringify(globalThis.__coverage__);
+ let testMode = globalThis.__testMode__;
+ console.info(`${TAG} coverage data testMode: ${testMode}`);
+ let savePath = globalThis.__savePath__;
+ console.info(`${TAG} write coverage data to: ${savePath}`);
+ let readPath = globalThis.__readPath__;
+ console.info(`${TAG} read coverage data in: ${readPath}`);
+
+ // run callback mode if local test or (save path and read path ) is not defined
+ if (!testMode || !isCoveragePathValid(savePath)) {
+ console.info(`${TAG} run coverage data in call back mode`);
+ const strLen = strJson.length;
+ const maxLen = 500;
+ const maxCount = Math.floor(strLen / maxLen);
+ const OHOS_REPORT_COVERAGE_DATA = 'OHOS_REPORT_COVERAGE_DATA:';
+ for (let count = 0; count <= maxCount; count++) {
+ console.info(`${OHOS_REPORT_COVERAGE_DATA} ${strJson.substring(count * maxLen, (count + 1) * maxLen)}`);
+ await SysTestKit.print(`${OHOS_REPORT_COVERAGE_DATA} ${strJson.substring(count * maxLen, (count + 1) * maxLen)}`);
+ }
+ return;
+ }
+ console.info(`${TAG} run coverage data in save file mode`);
+ if (fs.accessSync(savePath)) {
+ fs.unlinkSync(savePath);
+ }
+
+ let inputPathDir = savePath.substring(0, savePath.length - jsCoverageFileName.length);
+ if (!fs.accessSync(inputPathDir)) {
+ console.info(`${TAG} coverage data create dir: ${inputPathDir}`);
+ fs.mkdirSync(inputPathDir);
+ }
+
+ let file = fs.openSync(savePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
+ let writeLen = fs.writeSync(file.fd, strJson, {encoding:'utf-8'});
+ console.info(`${TAG} write coverage data success: ${writeLen}`);
+ fs.closeSync(file);
+ const OHOS_REPORT_COVERAGE_PATH = 'OHOS_REPORT_COVERAGE_PATH:';
+ await SysTestKit.print(`${OHOS_REPORT_COVERAGE_PATH} ${readPath}`);
+ console.info(`${OHOS_REPORT_COVERAGE_PATH} ${readPath}`);
+}
+
+function isCoveragePathValid(inputPath) {
+ if (!inputPath) {
+ return false;
+ }
+ if (inputPath.indexOf(jsCoverageFileName) === -1) {
+ return false;
+ }
+ return true;
+}
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/kit/SysTestKit.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/kit/SysTestKit.js
new file mode 100644
index 0000000000000000000000000000000000000000..6e2f256514cff87450f910098b1130943a40e39c
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/kit/SysTestKit.js
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {TAG} from '../../Constant';
+import Core from '../../core.js';
+
+export default class SysTestKit {
+
+ static delegator = null;
+ static systemTime = null;
+ static workerPort = null;
+
+ constructor() {
+ this.id = 'sysTestKit';
+ this.index = 0;
+ }
+
+ static getDescribeName() {
+ return Core.getInstance().getDefaultService('suite').getCurrentRunningSuite().description;
+ }
+
+ static getItName() {
+ return Core.getInstance().getDefaultService('spec').getCurrentRunningSpec().description;
+ }
+
+ static getItAttribute() {
+ return Core.getInstance().getDefaultService('spec').getCurrentRunningSpec().fi;
+ }
+
+ static actionStart(tag) {
+ console.info(`${TAG}${JSON.stringify(tag)}`);
+ var message = '\n' + 'OHOS_REPORT_ACTIONSTART: ' + JSON.stringify(tag) + '\n';
+ SysTestKit.print(message);
+ console.info(`${TAG}${JSON.stringify(tag)} actionStart print success`);
+ }
+
+ static actionEnd(tag) {
+ console.info(`${TAG}${JSON.stringify(tag)}`);
+ var message = '\n' + 'OHOS_REPORT_ACTIONEND: ' + JSON.stringify(tag) + '\n';
+ SysTestKit.print(message);
+ console.info(`${TAG}${JSON.stringify(tag)} actionEnd print success`);
+ }
+
+ static async existKeyword(keyword, timeout) {
+ let reg = new RegExp(/^[a-zA-Z0-9]{1,}$/);
+ if (!reg.test(keyword)) {
+ throw new Error('keyword must contain more than one string, and only letters and numbers are supported.');
+ }
+ timeout = timeout || 4;
+
+ let searchResult = false;
+ let cmd = 'hilog -x | grep -i \'' + keyword + '\' | wc -l';
+ await executePromise(cmd, timeout).then((data) => {
+ searchResult = data;
+ });
+ return searchResult;
+ }
+ static async print(message) {
+ if ('printSync' in SysTestKit.delegator) {
+ console.info(`${TAG}printSync called ...`);
+ SysTestKit.delegator.printSync(message);
+ } else {
+ await SysTestKit.delegator.print(message);
+ }
+ }
+
+ static async getRealTime() {
+ let currentTime = new Date().getTime();
+ if (SysTestKit.systemTime !== null && SysTestKit.systemTime !== undefined) {
+ await SysTestKit.systemTime.getRealTime().then((time) => {
+ console.info(`${TAG}systemTime.getRealTime success data: ${JSON.stringify(time)}`);
+ currentTime = time;
+ }).catch((error) => {
+ console.error(`${TAG}failed to systemTime.getRealTime because ${JSON.stringify(error)}`);
+ });
+ }
+ return currentTime;
+ }
+}
+
+function executePromise(cmd, timeout) {
+ return new Promise((resolve, reject) => {
+ SysTestKit.delegator.executeShellCommand(cmd, timeout,
+ (error, data) => {
+ console.info(`${TAG}existKeyword CallBack: err : ${JSON.stringify(error)}`);
+ console.info(`${TAG}existKeyword CallBack: data : ${JSON.stringify(data)}`);
+ resolve(parseInt(data.stdResult) > 3 ? true : false);
+ });
+ });
+}
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/mock/ArgumentMatchers.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/mock/ArgumentMatchers.js
new file mode 100644
index 0000000000000000000000000000000000000000..1e69ac401049589986968a8575ca45a02a299327
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/mock/ArgumentMatchers.js
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class ArgumentMatchers {
+ ANY = '';
+ ANY_STRING = '';
+ ANY_BOOLEAN = '';
+ ANY_NUMBER = '';
+ ANY_OBJECT = '';
+ ANY_FUNCTION = '';
+ MATCH_REGEXS = '';
+
+ static any() {
+ }
+
+ static anyString() {
+ }
+
+ static anyBoolean() {
+ }
+
+ static anyNumber() {
+ }
+
+ static anyObj() {
+ }
+
+ static anyFunction() {
+ }
+
+ static matchRegexs() {
+ let regex = arguments[0];
+ if (ArgumentMatchers.isRegExp(regex)) {
+ return regex;
+ }
+ throw Error('not a regex');
+ }
+
+ static isRegExp(value) {
+ return Object.prototype.toString.call(value) === '[object RegExp]';
+ }
+
+ matcheReturnKey() {
+ let arg = arguments[0];
+ let regex = arguments[1];
+ let stubSetKey = arguments[2];
+
+ if (stubSetKey && stubSetKey == this.ANY) {
+ return this.ANY;
+ }
+
+ if (typeof arg === 'string' && !regex) {
+ return this.ANY_STRING;
+ }
+
+ if (typeof arg === 'boolean' && !regex) {
+ return this.ANY_BOOLEAN;
+ }
+
+ if (typeof arg === 'number' && !regex) {
+ return this.ANY_NUMBER;
+ }
+
+ if (typeof arg === 'object' && !regex) {
+ return this.ANY_OBJECT;
+ }
+
+ if (typeof arg === 'function' && !regex) {
+ return this.ANY_FUNCTION;
+ }
+
+ if (typeof arg === 'string' && regex) {
+ return regex.test(arg);
+ }
+
+ return null;
+ }
+
+ matcheStubKey() {
+ let key = arguments[0];
+
+ if (key === ArgumentMatchers.any) {
+ return this.ANY;
+ }
+
+ if (key === ArgumentMatchers.anyString) {
+ return this.ANY_STRING;
+ }
+ if (key === ArgumentMatchers.anyBoolean) {
+ return this.ANY_BOOLEAN;
+ }
+ if (key === ArgumentMatchers.anyNumber) {
+ return this.ANY_NUMBER;
+ }
+ if (key === ArgumentMatchers.anyObj) {
+ return this.ANY_OBJECT;
+ }
+ if (key === ArgumentMatchers.anyFunction) {
+ return this.ANY_FUNCTION;
+ }
+
+ if (ArgumentMatchers.isRegExp(key)) {
+ return key;
+ }
+
+ return null;
+ }
+}
+
+export default ArgumentMatchers;
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/mock/ExtendInterface.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/mock/ExtendInterface.js
new file mode 100644
index 0000000000000000000000000000000000000000..c6a866a6df662ad10a7f6869dcbc2381fa47bcdc
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/mock/ExtendInterface.js
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class ExtendInterface {
+ constructor(mocker) {
+ this.mocker = mocker;
+ }
+
+ stub() {
+ this.params = arguments;
+ return this;
+ }
+
+ stubMockedCall(returnInfo) {
+ this.mocker.stubApply(this, this.params, returnInfo);
+ }
+
+ afterReturn(value) {
+ this.stubMockedCall(function () {
+ return value;
+ });
+ }
+
+ afterReturnNothing() {
+ this.stubMockedCall(function () {
+ return undefined;
+ });
+ }
+
+ afterAction(action) {
+ this.stubMockedCall(action);
+ }
+
+ afterThrow(msg) {
+ this.stubMockedCall(function () {
+ throw msg;
+ });
+ }
+
+ clear() {
+ this.mocker.clear();
+ }
+}
+
+export default ExtendInterface;
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/mock/MockKit.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/mock/MockKit.js
new file mode 100644
index 0000000000000000000000000000000000000000..5895666bc89ed4270582b436c82045745d5249b4
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/mock/MockKit.js
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import ExtendInterface from './ExtendInterface';
+import VerificationMode from './VerificationMode';
+import ArgumentMatchers from './ArgumentMatchers';
+
+class MockKit {
+
+ constructor() {
+ this.mFunctions = [];
+ this.stubs = new Map();
+ this.recordCalls = new Map();
+ this.currentSetKey = new Map();
+ this.mockObj = null;
+ this.recordMockedMethod = new Map();
+ }
+
+ init() {
+ this.reset();
+ }
+
+ reset() {
+ this.mFunctions = [];
+ this.stubs = {};
+ this.recordCalls = {};
+ this.currentSetKey = new Map();
+ this.mockObj = null;
+ this.recordMockedMethod = new Map();
+ }
+
+ clearAll() {
+ this.reset();
+ var props = Object.keys(this);
+ for (var i = 0; i < props.length; i++) {
+ delete this[props[i]];
+ }
+
+ var props = Object.getOwnPropertyNames(this);
+ for (var i = 0; i < props.length; i++) {
+ delete this[props[i]];
+ }
+ for (var key in this) {
+ delete this[key];
+ }
+ }
+
+ clear(obj) {
+ if (!obj) {
+ throw Error('Please enter an object to be cleaned');
+ }
+ if (typeof (obj) !== 'object' && typeof (obj) !== 'function') {
+ throw new Error('Not a object or static class');
+ }
+ this.recordMockedMethod.forEach(function (value, key, map) {
+ if (key) {
+ obj[key] = value;
+ }
+ });
+ }
+
+ ignoreMock(obj, method) {
+ if (typeof (obj) !== 'object' && typeof (obj) !== 'function') {
+ throw new Error('Not a object or static class');
+ }
+ if (typeof (method) !== 'function') {
+ throw new Error('Not a function');
+ }
+ let og = this.recordMockedMethod.get(method.propName);
+ if (og) {
+ obj[method.propName] = og;
+ this.recordMockedMethod.set(method.propName, undefined);
+ }
+ }
+
+ extend(dest, source) {
+ dest['stub'] = source['stub'];
+ dest['afterReturn'] = source['afterReturn'];
+ dest['afterReturnNothing'] = source['afterReturnNothing'];
+ dest['afterAction'] = source['afterAction'];
+ dest['afterThrow'] = source['afterThrow'];
+ dest['stubMockedCall'] = source['stubMockedCall'];
+ dest['clear'] = source['clear'];
+ return dest;
+ }
+
+ stubApply(f, params, returnInfo) {
+ let values = this.stubs.get(f);
+ if (!values) {
+ values = new Map();
+ }
+ let key = params[0];
+ if (typeof key == 'undefined') {
+ key = 'anonymous-mock-' + f.propName;
+ }
+ let matcher = new ArgumentMatchers();
+ if (matcher.matcheStubKey(key)) {
+ key = matcher.matcheStubKey(key);
+ if (key) {
+ this.currentSetKey.set(f, key);
+ }
+ }
+ values.set(key, returnInfo);
+ this.stubs.set(f, values);
+ }
+
+ getReturnInfo(f, params) {
+ let values = this.stubs.get(f);
+ if (!values) {
+ return undefined;
+ }
+ let retrunKet = params[0];
+ if (typeof retrunKet == 'undefined') {
+ retrunKet = 'anonymous-mock-' + f.propName;
+ }
+ let stubSetKey = this.currentSetKey.get(f);
+
+ if (stubSetKey && (typeof (retrunKet) !== 'undefined')) {
+ retrunKet = stubSetKey;
+ }
+ let matcher = new ArgumentMatchers();
+ if (matcher.matcheReturnKey(params[0], undefined, stubSetKey) && matcher.matcheReturnKey(params[0], undefined, stubSetKey) !== stubSetKey) {
+ retrunKet = params[0];
+ }
+
+ values.forEach(function (value, key, map) {
+ if (ArgumentMatchers.isRegExp(key) && matcher.matcheReturnKey(params[0], key)) {
+ retrunKet = key;
+ }
+ });
+
+ return values.get(retrunKet);
+ }
+
+ findName(obj, value) {
+ let properties = this.findProperties(obj);
+ let name = null;
+ properties.filter(item => (item !== 'caller' && item !== 'arguments')).forEach(
+ function (va1, idx, array) {
+ if (obj[va1] === value) {
+ name = va1;
+ }
+ }
+ );
+ return name;
+ }
+
+ isFunctionFromPrototype(f, container, propName) {
+ if (container.constructor !== Object && container.constructor.prototype !== container) {
+ return container.constructor.prototype[propName] === f;
+ }
+ return false;
+ }
+
+ findProperties(obj, ...arg) {
+ function getProperty(newObj) {
+ if (newObj.__proto__ === null) {
+ return [];
+ }
+ let properties = Object.getOwnPropertyNames(newObj);
+ return [...properties, ...getProperty(newObj.__proto__)];
+ }
+ return getProperty(obj);
+ }
+
+ recordMethodCall(originalMethod, args) {
+ Function.prototype.getName = function () {
+ return this.name || this.toString().match(/function\s*([^(]*)\(/)[1];
+ };
+ let name = originalMethod.getName();
+ let arglistString = name + '(' + Array.from(args).toString() + ')';
+ let records = this.recordCalls.get(arglistString);
+ if (!records) {
+ records = 0;
+ }
+ records++;
+ this.recordCalls.set(arglistString, records);
+ }
+
+ mockFunc(originalObject, originalMethod) {
+ let tmp = this;
+ this.originalMethod = originalMethod;
+ let f = function () {
+ let args = arguments;
+ let action = tmp.getReturnInfo(f, args);
+ if (originalMethod) {
+ tmp.recordMethodCall(originalMethod, args);
+ }
+ if (action) {
+ return action.apply(this, args);
+ }
+ };
+
+ f.container = null || originalObject;
+ f.original = originalMethod || null;
+
+ if (originalObject && originalMethod) {
+ if (typeof (originalMethod) !== 'function') {
+ throw new Error('Not a function');
+ }
+ var name = this.findName(originalObject, originalMethod);
+ originalObject[name] = f;
+ this.recordMockedMethod.set(name, originalMethod);
+ f.propName = name;
+ f.originalFromPrototype = this.isFunctionFromPrototype(f.original, originalObject, f.propName);
+ }
+ f.mocker = this;
+ this.mFunctions.push(f);
+ this.extend(f, new ExtendInterface(this));
+ return f;
+ }
+
+ verify(methodName, argsArray) {
+ if (!methodName) {
+ throw Error('not a function name');
+ }
+ let a = this.recordCalls.get(methodName + '(' + argsArray.toString() + ')');
+ return new VerificationMode(a ? a : 0);
+ }
+
+ mockObject(object) {
+ if (!object || typeof object === 'string') {
+ throw Error(`this ${object} cannot be mocked`);
+ }
+ const _this = this;
+ let mockedObject = {};
+ let keys = Reflect.ownKeys(object);
+ keys.filter(key => (typeof Reflect.get(object, key)) === 'function')
+ .forEach(key => {
+ mockedObject[key] = object[key];
+ mockedObject[key] = _this.mockFunc(mockedObject, mockedObject[key]);
+ });
+ return mockedObject;
+ }
+}
+
+function ifMockedFunction(f) {
+ if (Object.prototype.toString.call(f) !== '[object Function]' &&
+ Object.prototype.toString.call(f) !== '[object AsyncFunction]') {
+ throw Error('not a function');
+ }
+ if (!f.stub) {
+ throw Error('not a mock function');
+ }
+ return true;
+}
+
+function when(f) {
+ if (ifMockedFunction(f)) {
+ return f.stub.bind(f);
+ }
+}
+
+export {MockKit, when};
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/mock/VerificationMode.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/mock/VerificationMode.js
new file mode 100644
index 0000000000000000000000000000000000000000..aaf2fdfae00135d3d2055320fc5ea403b44d0bf3
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/mock/VerificationMode.js
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {expect} from '../../interface';
+
+class VerificationMode {
+ constructor(times) {
+ this.doTimes = times;
+ }
+
+ times(count) {
+ expect(count).assertEqual(this.doTimes);
+ }
+
+ never() {
+ console.info(this.doTimes);
+ expect(0).assertEqual(this.doTimes);
+ }
+
+ once() {
+ expect(1).assertEqual(this.doTimes);
+ }
+
+ atLeast(count) {
+ if (count > this.doTimes) {
+ throw Error('failed ' + count + ' greater than the actual execution times of method');
+ }
+ }
+
+ atMost(count) {
+ if (count < this.doTimes) {
+ throw Error('failed ' + count + ' less than the actual execution times of method');
+ }
+ }
+}
+
+export default VerificationMode;
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/report/LogExpectError.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/report/LogExpectError.js
new file mode 100644
index 0000000000000000000000000000000000000000..5a94cecb4625205797ae886c19ac592f189c2232
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/report/LogExpectError.js
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class LogExpectError {
+ static getErrorMsg(matcherName, actualValue, expect, originMsg) {
+ if (matcherName === 'assertNull') {
+ return 'expect not null, actualValue is ' + (actualValue);
+ }
+ if (matcherName === 'assertTrue') {
+ return 'expect not true, actualValue is ' + (actualValue);
+ }
+ if (matcherName === 'assertFalse') {
+ return 'expect not false, actualValue is ' + (actualValue);
+ }
+ if (matcherName === 'assertEqual') {
+ return 'expect not Equal, actualValue is ' + actualValue + ' equals ' + expect;
+ }
+ if (matcherName === 'assertContain') {
+ return 'expect not have, ' + actualValue + ' have ' + expect;
+ }
+ if (matcherName === 'assertInstanceOf') {
+ return 'expect not InstanceOf, ' + actualValue + ' is ' +
+ Object.prototype.toString.call(actualValue) + expect;
+ }
+ if (matcherName === 'assertLarger') {
+ return 'expect not Larger, ' +
+ (actualValue) + ' is larger than ' + expect;
+ }
+ if (matcherName === 'assertLargerOrEqual') {
+ return 'expect not LargerOrEqual, ' + (actualValue) + ' larger than ' + expect;
+ }
+ if (matcherName === 'assertLess') {
+ return 'expect not Less, ' + (actualValue) + ' less than ' + expect;
+ }
+ if (matcherName === 'assertLessOrEqual') {
+ return 'expect not LessOrEqual, ' + (actualValue) + ' is less than ' + expect;
+ }
+ if (matcherName === 'assertNaN') {
+ return 'expect not NaN, actualValue is ' + (actualValue);
+ }
+ if (matcherName === 'assertNegUnlimited') {
+ return 'expect not NegUnlimited, actualValue is ' + (actualValue);
+ }
+ if (matcherName === 'assertPosUnlimited') {
+ return 'expect not PosUnlimited, actualValue is ' + (actualValue);
+ }
+ if (matcherName === 'assertUndefined') {
+ return 'expect not Undefined, actualValue is ' + (actualValue);
+ }
+ return originMsg;
+ }
+}
+export default LogExpectError;
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/report/OhReport.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/report/OhReport.js
new file mode 100644
index 0000000000000000000000000000000000000000..653e56be9e88e810f6ab1f3d58049cf08d2ac0b6
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/report/OhReport.js
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import SysTestKit from "../kit/SysTestKit";
+import { collectCoverageData } from '../coverage/coverageCollect';
+import { TAG, PrintTag } from '../../Constant';
+
+class OhReport {
+ constructor(attr) {
+ this.delegator = attr.delegator;
+ this.abilityDelegatorArguments = attr.abilityDelegatorArguments;
+ this.id = 'report';
+ this.index = 0;
+ this.duration = 0;
+ this.currentThreadName = 'mainThread';
+ }
+
+ init(coreContext) {
+ this.coreContext = coreContext;
+ this.suiteService = this.coreContext.getDefaultService('suite');
+ this.specService = this.coreContext.getDefaultService('spec');
+ if (SysTestKit.workerPort !== null) {
+ this.currentThreadName = SysTestKit.workerPort.name;
+ }
+ }
+
+ taskStart() {
+ }
+
+ async taskDone() {
+ let summary = this.suiteService.getSummary();
+ if (this.abilityDelegatorArguments !== null) {
+ this.taskDoneTime = new Date().getTime();
+ const configService = this.coreContext.getDefaultService('config');
+ const suiteService = this.coreContext.getDefaultService('suite');
+ const specService = this.coreContext.getDefaultService('spec');
+ if (configService['coverage'] === 'true') {
+ await collectCoverageData();
+ }
+ let message = '\n' + `${PrintTag.OHOS_REPORT_RESULT}: stream=Tests run: ` + summary.total + ', Failure: ' + summary.failure;
+ message += ', Error: ' + summary.error;
+ message += ', Pass: ' + summary.pass;
+ message += ', Ignore: ' + summary.ignore;
+ if (specService.skipSpecNum > 0) {
+ message += ', SkipSpec: ' + specService.skipSpecNum;
+ }
+ message += '\n' + `${PrintTag.OHOS_REPORT_CODE}: ` + (summary.failure > 0 ? -1 : 0) + '\n';
+ let isHasError = summary.failure > 0 || summary.error > 0;
+ let config = this.coreContext.getDefaultService('config');
+ if (config.isBreakOnError() && isHasError) {
+ // 未执行全部说明
+ message += '\n' + `${PrintTag.OHOS_REPORT_RESULT}: breakOnError model, Stopping whole test suite if one specific test case failed or error` + '\n';
+ }
+ message += `${PrintTag.OHOS_REPORT_STATUS}: taskconsuming=` + summary.duration + '\n';
+ console.info(`${message}`);
+ await SysTestKit.print(message);
+ }
+ if (SysTestKit.workerPort === null || SysTestKit.workerPort === undefined) {
+ // 主线程执行完成 结束任务。
+ console.info(`${TAG}report print success`);
+ this.delegator.finishTest('your test finished!!!', 0, () => { });
+ } else {
+ // worker线程执行完成将数据发送到主线程中。
+ let sendData = {
+ currentThreadName: this.currentThreadName,
+ summary: summary
+ };
+ console.info(`${TAG}, send data to mainThread, ${this.currentThreadName}, ${JSON.stringify(sendData)}`);
+ SysTestKit.workerPort.postMessage(sendData);
+ }
+ }
+
+ incorrectFormat() {
+ if (this.coreContext.getDefaultService('config').filterValid.length !== 0) {
+ var value = this.coreContext.getDefaultService('config').filterValid;
+ var message = 'this param ' + value.join(',') + ' is invalid' + '\n';
+ this.delegator.finishTest(message, 0, () => {
+ });
+ }
+ }
+
+ incorrectTestSuiteFormat() {
+ if (this.coreContext.getDefaultService('config').filterXdescribe.length !== 0) {
+ let value = this.coreContext.getDefaultService('config').filterXdescribe;
+ let message = 'xdescribe ' + value.join(',') + ' should not contain it' + '\n';
+ this.delegator.finishTest(message, 0, () => {
+ });
+ }
+ }
+ async suiteStart() {
+ if (this.abilityDelegatorArguments !== null) {
+ let specArr = [];
+ this.suiteService.getAllChildSuiteNum(this.suiteService.getCurrentRunningSuite(), specArr);
+ let message = '\n' + `${PrintTag.OHOS_REPORT_SUM}: ` + specArr.length;
+ this.suiteService.setCurrentRunningSuiteDesc(this.suiteService.getRootSuite(), this.suiteService.getCurrentRunningSuite(), '');
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: class=` + this.suiteService.getCurrentRunningSuiteDesc() + '\n';
+ if (this.suiteService.currentRunningSuite.isSkip) {
+ message += `${PrintTag.OHOS_REPORT_STATUS}: skipReason=` + this.suiteService.currentRunningSuite.skipReason + '\n';
+ }
+ if (SysTestKit.workerPort !== null) {
+ message += `${PrintTag.OHOS_REPORT_STATUS}: currentWorkerName=` + this.currentThreadName;
+ }
+ console.info(`${message}`);
+ await SysTestKit.print(message);
+ console.info(`${TAG}${this.suiteService.getCurrentRunningSuite().description} suiteStart print success`);
+ }
+ }
+
+ async suiteDone() {
+ if (this.abilityDelegatorArguments !== null) {
+ const currentRunningSuite = this.suiteService.getCurrentRunningSuite();
+ this.suiteService.setCurrentRunningSuiteDesc(this.suiteService.getRootSuite(), this.suiteService.getCurrentRunningSuite(), '');
+ let message = '\n' + `${PrintTag.OHOS_REPORT_STATUS}: class=` + this.suiteService.getCurrentRunningSuiteDesc();
+ if (this.suiteService.currentRunningSuite.isSkip && this.suiteService.currentRunningSuite.skipReason !== '') {
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: skipReason=` + this.suiteService.currentRunningSuite.skipReason;
+ }
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: suiteconsuming=` + this.suiteService.getCurrentRunningSuite().duration;
+ if (currentRunningSuite.hookError) {
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: ${currentRunningSuite.hookError.message}`;
+ }
+ message += '\n';
+ if (SysTestKit.workerPort !== null) {
+ message += `${PrintTag.OHOS_REPORT_STATUS}: currentWorkerName=` + this.currentThreadName;
+ }
+ console.info(`${message}`);
+ await SysTestKit.print(message);
+ console.info(`${TAG}${this.suiteService.getCurrentRunningSuite().description} suiteDone print success`);
+ }
+ }
+
+ async specStart() {
+ if (this.abilityDelegatorArguments !== null) {
+ let message = '\n' + `${PrintTag.OHOS_REPORT_STATUS}: class=` + this.suiteService.getCurrentRunningSuiteDesc();
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: current=` + (++this.index);
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: id=JS`;
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: numtests=` + this.specService.getTestTotal();
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: stream=`;
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: test=` + this.specService.currentRunningSpec.description;
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS_CODE}: 1` + '\n';
+ if (this.specService.currentRunningSpec.isSkip) {
+ message += `${PrintTag.OHOS_REPORT_STATUS}: skipReason=` + this.specService.currentRunningSpec.skipReason + '\n';
+ }
+ if (SysTestKit.workerPort !== null) {
+ message += `${PrintTag.OHOS_REPORT_STATUS}: currentWorkerName=` + this.currentThreadName;
+ }
+ console.info(`${message}`);
+ await SysTestKit.print(message);
+ console.info(`${TAG}${this.specService.currentRunningSpec.description} specStart start print success`);
+ }
+ }
+
+ async specDone() {
+ if (this.abilityDelegatorArguments !== null) {
+ let message = '\n' + `${PrintTag.OHOS_REPORT_STATUS}: class=` + this.suiteService.getCurrentRunningSuiteDesc();
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: current=` + (this.index);
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: id=JS`;
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: numtests=` + this.specService.getTestTotal();
+ let messageStack = '';
+ let messageCode = '';
+ if (this.specService.currentRunningSpec.error) {
+ messageStack = `${PrintTag.OHOS_REPORT_STATUS}: stack=` + this.specService.currentRunningSpec.error?.stack?.slice(0, -1);
+ messageCode += `${PrintTag.OHOS_REPORT_STATUS}: stream=`;
+ messageCode += this.specService.currentRunningSpec.expectMsg !== '' ?
+ `message: ${this.specService.currentRunningSpec.expectMsg}, Error in ${this.specService.currentRunningSpec.description}, ${this.specService.currentRunningSpec.error?.message}` :
+ `Error in ${this.specService.currentRunningSpec.description}, ${this.specService.currentRunningSpec.error?.message}`;
+ messageCode += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: test=` + this.specService.currentRunningSpec.description;
+ messageCode += '\n' + `${PrintTag.OHOS_REPORT_STATUS_CODE}: -1` + '\n';
+ } else if (this.specService.currentRunningSpec) {
+ if (this.specService.currentRunningSpec.fail) {
+ messageStack += `${PrintTag.OHOS_REPORT_STATUS}: stack=` + this.specService.currentRunningSpec.fail?.stack?.slice(0, -1);
+ messageCode += `${PrintTag.OHOS_REPORT_STATUS}: stream=`;
+ messageCode += this.specService.currentRunningSpec.expectMsg !== '' ?
+ `message: ${this.specService.currentRunningSpec.expectMsg}, Error in ${this.specService.currentRunningSpec.description}, ${this.specService.currentRunningSpec.fail?.message}` :
+ `Error in ${this.specService.currentRunningSpec.description}, ${this.specService.currentRunningSpec.fail?.message}`;
+ messageCode += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: test=` + this.specService.currentRunningSpec.description;
+ messageCode += '\n' + `${PrintTag.OHOS_REPORT_STATUS_CODE}: -2` + '\n';
+ } else {
+ messageStack += `${PrintTag.OHOS_REPORT_STATUS}: stream=`;
+ messageCode += `${PrintTag.OHOS_REPORT_STATUS}: test=` + this.specService.currentRunningSpec.description;
+ messageCode += '\n' + `${PrintTag.OHOS_REPORT_STATUS_CODE}: 0` + '\n';
+ messageCode += this.specService.currentRunningSpec.isSkip ? (`${PrintTag.OHOS_REPORT_STATUS}: skipReason=` + this.specService.currentRunningSpec.skipReason + '\n') : '';
+ }
+ } else {
+ messageCode += '\n';
+ }
+ messageCode += `${PrintTag.OHOS_REPORT_STATUS}: consuming=` + this.specService.currentRunningSpec.duration + '\n';
+ if (SysTestKit.workerPort !== null) {
+ messageCode += `${PrintTag.OHOS_REPORT_STATUS}: currentWorkerName=` + this.currentThreadName;
+ }
+ console.info(`${message}`);
+ console.info(`\n${messageStack}`);
+ console.info(`\n${messageCode}`);
+ await SysTestKit.print(message);
+ await SysTestKit.print(messageStack);
+ await SysTestKit.print(messageCode);
+ console.info(`${TAG}${this.specService.currentRunningSpec.description} specDone end print success`);
+ }
+ }
+}
+
+export default OhReport;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/report/ReportExtend.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/report/ReportExtend.js
new file mode 100644
index 0000000000000000000000000000000000000000..852fbcd5cbf97e776ebe5177a029df0f516594a5
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/module/report/ReportExtend.js
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class ReportExtend {
+ constructor(fileModule) {
+ this.id = 'extend';
+ this.fileModule = fileModule;
+ }
+
+ init(coreContext) {
+ this.coreContext = coreContext;
+ this.suiteService = this.coreContext.getDefaultService('suite');
+ }
+
+ taskStart() {
+
+ }
+
+ taskDone() {
+ const report = {
+ tag: 'testsuites',
+ name: 'summary_report',
+ timestamp: new Date().toDateString(),
+ time: '1',
+ errors: 0,
+ failures: 0,
+ tests: 0,
+ children: []
+ };
+ const rootSuite = this.suiteService.rootSuite;
+ if (rootSuite && rootSuite.childSuites) {
+ for (let testsuite of rootSuite.childSuites) {
+ let suiteReport = {
+ tag: 'testsuite',
+ name: testsuite['description'],
+ errors: 0,
+ tests: 0,
+ failures: 0,
+ time: '0.1',
+ children: []
+ };
+ let specs = testsuite['specs'];
+ for (let testcase of specs) {
+ report.tests++;
+ suiteReport.tests++;
+ let caseReport = {
+ tag: 'testcase',
+ name: testcase['description'],
+ status: 'run',
+ time: '0.0',
+ classname: testsuite['description']
+ };
+ if (testcase.error) {
+ caseReport['result'] = false;
+ caseReport['children'] = [{
+ tag: 'error',
+ type: '',
+ message: testcase.error.message
+ }];
+ report.errors++;
+ suiteReport.errors++;
+ } else if (testcase.result.failExpects.length > 0) {
+ caseReport['result'] = false;
+ let message = '';
+ testcase.result.failExpects.forEach(failExpect => {
+ message += failExpect.message || ('expect ' + failExpect.actualValue + ' ' + failExpect.checkFunc + ' ' + (failExpect.expectValue || '')) + ';';
+ });
+ caseReport['children'] = [{
+ tag: 'failure',
+ type: '',
+ message: message
+ }];
+ report.failures++;
+ suiteReport.failures++;
+ } else {
+ caseReport['result'] = true;
+ }
+ suiteReport.children.push(caseReport);
+ }
+ report.children.push(suiteReport);
+ }
+ }
+
+ let reportXml = '\n' + json2xml(report);
+ this.fileModule.writeText({
+ uri: 'internal://app/report.xml',
+ text: reportXml,
+ success: function () {
+ console.info('call success callback success');
+ },
+ fail: function (data, code) {
+ console.info('call fail callback success:');
+ },
+ complete: function () {
+ console.info('call complete callback success');
+ }
+ });
+ }
+}
+
+function json2xml(json) {
+ let tagName;
+ let hasChildren = false;
+ let childrenStr = '';
+ let attrStr = '';
+ for (let key in json) {
+ if (key === 'tag') {
+ tagName = json[key];
+ } else if (key === 'children') {
+ if (json[key].length > 0) {
+ hasChildren = true;
+ for (let child of json[key]) {
+ childrenStr += json2xml(child);
+ }
+ }
+ } else {
+ attrStr += ` ${key}="${json[key]}"`;
+ }
+ }
+ let xml = `<${tagName}${attrStr}`;
+ xml += hasChildren ? `>${childrenStr}${tagName}>` : '/>';
+ return xml;
+}
+
+export default ReportExtend;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/service.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/service.js
new file mode 100644
index 0000000000000000000000000000000000000000..92d46b77959af314f40bd601ede62b9b6d8b9ba2
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/service.js
@@ -0,0 +1,1230 @@
+/*
+ * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import SysTestKit from './module/kit/SysTestKit';
+import { TAG } from './Constant';
+import LogExpectError from './module/report/LogExpectError';
+import { NestFilter } from './module/config/Filter';
+
+class AssertException extends Error {
+ constructor(message) {
+ super();
+ this.name = 'AssertException';
+ this.message = message;
+ }
+}
+
+function getFuncWithArgsZero(func, timeout, isStressTest) {
+ return new Promise(async (resolve, reject) => {
+ let timer = null;
+ if (!isStressTest) {
+ timer = setTimeout(() => {
+ reject(new Error('execute timeout ' + timeout + 'ms'));
+ }, timeout);
+ }
+ try {
+ await func();
+ } catch (err) {
+ reject(err);
+ }
+ timer !== null ? clearTimeout(timer) : null;
+ resolve();
+ });
+}
+
+function getFuncWithArgsOne(func, timeout, isStressTest) {
+ return new Promise(async (resolve, reject) => {
+ let timer = null;
+ if (!isStressTest) {
+ timer = setTimeout(() => {
+ reject(new Error('execute timeout ' + timeout + 'ms'));
+ }, timeout);
+ }
+
+ function done() {
+ timer !== null ? clearTimeout(timer) : null;
+ resolve();
+ }
+
+ try {
+ await func(done);
+ } catch (err) {
+ timer !== null ? clearTimeout(timer) : null;
+ reject(err);
+ }
+ });
+}
+
+function getFuncWithArgsTwo(func, timeout, paramItem, isStressTest) {
+ return new Promise(async (resolve, reject) => {
+ let timer = null;
+ if (!isStressTest) {
+ timer = setTimeout(() => {
+ reject(new Error('execute timeout ' + timeout + 'ms'));
+ }, timeout);
+ }
+
+ function done() {
+ timer !== null ? clearTimeout(timer) : null;
+ resolve();
+ }
+
+ try {
+ await func(done, paramItem);
+ } catch (err) {
+ timer !== null ? clearTimeout(timer) : null;
+ reject(err);
+ }
+ });
+}
+
+function processFunc(coreContext, func) {
+ let argNames = ((func || '').toString()
+ .replace(/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg, '')
+ .match(/^(function)?\s*[^\(]*\(\s*([^\)]*)\)/m) || ['', '', ''])[2]
+ .split(',') // split parameters
+ .map(item => item.replace(/^\s*(_?)(.+?)\1\s*$/, name => name.split('=')[0].trim()))
+ .filter(String);
+ let funcLen = func.length;
+ let processedFunc;
+ const config = coreContext.getDefaultService('config');
+ config.setSupportAsync(true);
+ const timeout = + (config.timeout === undefined ? 5000 : config.timeout);
+ const isStressTest = (coreContext.getServices('dataDriver') !== undefined || config.getStress() > 1);
+ switch (funcLen) {
+ case 0: {
+ processedFunc = function () {
+ return getFuncWithArgsZero(func, timeout, isStressTest);
+ };
+ break;
+ }
+ case 1: {
+ if (argNames[0] === 'data') {
+ processedFunc = function (paramItem) {
+ func(paramItem);
+ };
+ } else {
+ processedFunc = function () {
+ return getFuncWithArgsOne(func, timeout, isStressTest);
+ };
+ }
+ break;
+ }
+ default: {
+ processedFunc = function (paramItem) {
+ return getFuncWithArgsTwo(func, timeout, paramItem, isStressTest);
+ };
+ break;
+ }
+ }
+ return processedFunc;
+}
+
+function secureRandomNumber() {
+ return crypto.randomBytes(8).readUInt32LE() / 0xffffffff;
+}
+
+class SuiteService {
+ constructor(attr) {
+ this.id = attr.id;
+ this.rootSuite = new SuiteService.Suite({});
+ this.currentRunningSuite = this.rootSuite;
+ this.suitesStack = [this.rootSuite];
+ this.targetSuiteArray = [];
+ this.targetSpecArray = [];
+ this.currentRunningSuiteDesc = null;
+ this.fullRun = false;
+ this.isSkipSuite = false;
+ this.suiteSkipReason = null;
+ }
+
+ describe(desc, func) {
+ const configService = this.coreContext.getDefaultService('config');
+ if (this.suitesStack.some(suite => { return suite.description === desc })) {
+ console.error(`${TAG} Loop nesting occurs : ${desc}`);
+ this.suiteSkipReason = '';
+ this.isSkipSuite = false;
+ return;
+ }
+ let isFilter = this.analyzeConfigServiceClass(configService.class, desc);
+ if (configService.filterSuite(desc) && isFilter) {
+ if (this.currentRunningSuite.description === '' || this.currentRunningSuite.description == null) {
+ console.info(`${TAG}filter suite : ${desc}`);
+ this.suiteSkipReason = '';
+ this.isSkipSuite = false;
+ return;
+ }
+ }
+ const suite = new SuiteService.Suite({ description: desc });
+ if (this.isSkipSuite) {
+ suite.isSkip = true;
+ suite.skipReason = this.suiteSkipReason;
+ }
+ this.suiteSkipReason = '';
+ this.isSkipSuite = false;
+ if (typeof this.coreContext.getServices('dataDriver') !== 'undefined' && configService['dryRun'] !== 'true') {
+ let suiteStress = this.coreContext.getServices('dataDriver').dataDriver.getSuiteStress(desc);
+ for (let i = 1; i < suiteStress; i++) {
+ this.currentRunningSuite.childSuites.push(suite);
+ }
+ }
+ this.currentRunningSuite.childSuites.push(suite);
+ this.currentRunningSuite = suite;
+ this.suitesStack.push(suite);
+ func.call();
+ this.suitesStack.pop();
+ this.currentRunningSuite = this.suitesStack.pop();
+ this.suitesStack.push(this.currentRunningSuite);
+ }
+ xdescribe(desc, func, reason) {
+ const configService = this.coreContext.getDefaultService('config');
+ if (!configService.skipMessage && configService.runSkipped !== 'all') {
+ if (configService.runSkipped != null && configService.runSkipped !== '') {
+ let finalDesc = '';
+ this.suitesStack.map(suite => {
+ finalDesc = finalDesc + '.' + suite.description;
+ });
+ finalDesc = (finalDesc + '.' + desc).substring(2);
+ console.info(`${TAG} finalDesc ${finalDesc}`);
+ if (configService.checkIfSuiteInSkipRun(finalDesc)) {
+ console.info(`${TAG} runSkipped suite: ${desc}`);
+ } else {
+ console.info(reason == null ? `${TAG} skip suite: ${desc}` : `${TAG} skip suite: ${desc}, and the reason is ${reason}`);
+ return;
+ }
+ } else {
+ console.info(reason == null ? `${TAG} skip suite: ${desc}` : `${TAG} skip suite: ${desc}, and the reason is ${reason}`);
+ return;
+ }
+ }
+ this.isSkipSuite = true;
+ this.suiteSkipReason = reason;
+ this.describe(desc, func);
+ }
+
+ beforeAll(func) {
+ this.currentRunningSuite.beforeAll.push(processFunc(this.coreContext, func));
+ }
+
+ beforeEach(func) {
+ this.currentRunningSuite.beforeEach.push(processFunc(this.coreContext, func));
+ }
+
+ beforeItSpecified(itDescs, func) {
+ this.currentRunningSuite.beforeItSpecified.set(itDescs, processFunc(this.coreContext, func));
+ }
+
+ afterItSpecified(itDescs, func) {
+ this.currentRunningSuite.afterItSpecified.set(itDescs, processFunc(this.coreContext, func));
+ }
+
+ afterAll(func) {
+ this.currentRunningSuite.afterAll.push(processFunc(this.coreContext, func));
+ }
+
+ afterEach(func) {
+ this.currentRunningSuite.afterEach.push(processFunc(this.coreContext, func));
+ }
+
+ getCurrentRunningSuite() {
+ return this.currentRunningSuite;
+ }
+
+ setCurrentRunningSuite(suite) {
+ this.currentRunningSuite = suite;
+ }
+
+ getRootSuite() {
+ return this.rootSuite;
+ }
+
+ getCurrentRunningSuiteDesc() {
+ return this.currentRunningSuiteDesc;
+ }
+
+
+ setCurrentRunningSuiteDesc(suite, currentSuite, prefix) {
+ if (suite != null && suite === currentSuite) {
+ this.currentRunningSuiteDesc = prefix;
+ } else if (suite != null && suite !== currentSuite) {
+ suite.childSuites.forEach(it => {
+ let temp = prefix;
+ if (it.description != null || it.description !== '') {
+ temp = prefix === '' ? it.description : prefix + '.' + it.description;
+ }
+ this.setCurrentRunningSuiteDesc(it, currentSuite, temp);
+ }
+ );
+ }
+ }
+ analyzeConfigServiceClass(configServiceClass, desc) {
+ if (configServiceClass == null || configServiceClass === '') {
+ this.fullRun = true
+ return false;
+ }
+ if (this.targetSuiteArray.length === 0) {
+ const targetArray = configServiceClass.split(',');
+ for (let index in targetArray) {
+ if (targetArray[index].includes('#')) {
+ this.targetSpecArray.push(targetArray[index]);
+ } else {
+ this.targetSuiteArray.push(targetArray[index]);
+ }
+ }
+
+ }
+ return !configServiceClass.includes(desc);
+
+ }
+ traversalResults(suite, obj, breakOnError) {
+ if (suite.childSuites.length === 0 && suite.specs.length === 0) {
+ return obj;
+ }
+ if (suite.specs.length > 0) {
+ for (const itItem of suite.specs) {
+ obj.total++;
+ let itInfo = {
+ currentThreadName: 'mainThread',
+ description: suite.description + '#' + itItem.description,
+ result: -3
+ };
+ if (SysTestKit.workerPort !== null) {
+ itInfo.currentThreadName = SysTestKit.workerPort.name;
+ }
+ obj.itItemList.push(itInfo);
+ if (breakOnError && (obj.error > 0 || obj.failure > 0)) { // breakOnError模式
+ continue;
+ }
+ if (itItem.error) {
+ obj.error++;
+ itInfo.result = -1;
+ } else if (itItem.fail) {
+ obj.failure++;
+ itInfo.result = -2;
+ } else if (itItem.pass === true) {
+ obj.pass++;
+ itInfo.result = 0;
+ }
+ }
+ }
+
+ obj.duration += suite.duration;
+
+ if (suite.childSuites.length > 0) {
+ for (const suiteItem of suite.childSuites) {
+ this.traversalResults(suiteItem, obj, breakOnError);
+ }
+ }
+ }
+
+ async setSuiteResults(suite, error, coreContext) {
+ if (suite.childSuites.length === 0 && suite.specs.length === 0) {
+ return obj;
+ }
+ if (suite.specs.length > 0) {
+ const specService = coreContext.getDefaultService('spec');
+ for (const specItem of suite.specs) {
+ specService.setCurrentRunningSpec(specItem);
+ if (error instanceof AssertException) {
+ specItem.fail = error;
+ } else {
+ specItem.error = error;
+ }
+ await coreContext.fireEvents('spec', 'specStart', specItem);
+ await coreContext.fireEvents('spec', 'specDone', specItem);
+ }
+ }
+ if (suite.childSuites.length > 0) {
+ for (const suiteItem of suite.childSuites) {
+ await this.setSuiteResults(suiteItem, error, coreContext);
+ }
+ }
+ }
+
+ getSummary() {
+ let suiteService = this.coreContext.getDefaultService('suite');
+ let rootSuite = suiteService.rootSuite;
+ const specService = this.coreContext.getDefaultService('spec');
+ const configService = this.coreContext.getDefaultService('config');
+ let breakOnError = configService.isBreakOnError();
+ let isError = specService.getStatus();
+ let isBreaKOnError = breakOnError && isError;
+ // itItemList 保存当前用例执行情况, 发送到主线程用例计算最终结果
+ let obj = { total: 0, failure: 0, error: 0, pass: 0, ignore: 0, duration: 0, itItemList: []};
+ for (const suiteItem of rootSuite.childSuites) {
+ this.traversalResults(suiteItem, obj, isBreaKOnError);
+ }
+ obj.ignore = obj.total - obj.pass - obj.failure - obj.error;
+ return obj;
+ }
+
+ init(coreContext) {
+ this.coreContext = coreContext;
+ }
+
+ traversalSuites(suite, obj, configService) {
+ if (suite.childSuites.length === 0 && suite.specs.length === 0) {
+ return [];
+ }
+ if (suite.specs.length > 0) {
+ let itArray = [];
+ for (const itItem of suite['specs']) {
+ if (!configService.filterDesc(suite.description, itItem.description, itItem.fi, null)) {
+ itArray.push({ 'itName': itItem.description });
+ }
+ }
+ obj[suite.description] = itArray;
+ }
+ if (suite.childSuites.length > 0) {
+ let suiteArray = [];
+ for (const suiteItem of suite.childSuites) {
+ let suiteObj = {};
+ this.traversalSuites(suiteItem, suiteObj, configService);
+ if (!configService.filterSuite(suiteItem.description)) {
+ suiteArray.push(suiteObj);
+ }
+ }
+ obj.suites = suiteArray;
+ }
+ }
+
+ async dryRun(abilityDelegator) {
+ console.info(`${TAG} rootSuite : ` + JSON.stringify(this.rootSuite));
+ let obj = this.rootSuite;
+ let prefixStack = [];
+ let suiteArray = [];
+ let skipSuiteArray = [];
+ this.analyzeSuitesArray(prefixStack, suiteArray, skipSuiteArray, obj);
+ const configService = this.coreContext.getDefaultService('config');
+ let result;
+ if (configService.skipMessage) {
+ result = { 'suites': suiteArray, 'skipSuites': skipSuiteArray };
+ } else {
+ result = { 'suites': suiteArray };
+ }
+ let strJson = JSON.stringify(result);
+ let strLen = strJson.length;
+ let maxLen = 500;
+ let maxCount = Math.floor(strLen / maxLen);
+ for (let count = 0; count <= maxCount; count++) {
+ await SysTestKit.print(strJson.substring(count * maxLen, (count + 1) * maxLen));
+ }
+ console.info(`${TAG}dryRun print success`);
+ abilityDelegator.finishTest('dry run finished!!!', 0, () => { });
+ }
+
+ //将suitesArray的嵌套结构展开成三层结构
+ analyzeSuitesArray(prefixStack, suiteArray, skipSuiteArray, obj) {
+ obj.childSuites.map(suite => {
+ if (suite.description != null && suite.description !== '') {
+ let prefix = '';
+ if (prefixStack.length > 0) {
+ prefix = prefixStack.join('.') + '.' + suite.description;
+ } else {
+ prefix = suite.description;
+ }
+ prefixStack.push(suite.description);
+ let temp = {};
+ temp[prefix] = [];
+ let skipTemp = {};
+ skipTemp[prefix] = [];
+ suite.specs.map(spec => {
+ let it = { 'itName': spec.description };
+ spec.isSkip ? skipTemp[prefix].push(it) : temp[prefix].push(it);
+ });
+ suiteArray.push(temp);
+ skipSuiteArray.push(skipTemp);
+ }
+ this.analyzeSuitesArray(prefixStack, suiteArray, skipSuiteArray, suite);
+ prefixStack.pop();
+ });
+ }
+ //获取当前测试套下的所有测试用例数量
+ getAllChildSuiteNum(suite, specArray) {
+ if (suite.specs != null) {
+ suite.specs.forEach(spec => specArray.push(spec));
+ }
+ if (suite.childSuites != null) {
+ suite.childSuites.forEach(it => this.getAllChildSuiteNum(it, specArray));
+ }
+ }
+
+ execute() {
+ const configService = this.coreContext.getDefaultService('config');
+ if (configService.filterValid.length !== 0) {
+ this.coreContext.fireEvents('task', 'incorrectFormat');
+ return;
+ }
+ if (configService.filterXdescribe.length !== 0) {
+ this.coreContext.fireEvents('task', 'incorrectTestSuiteFormat');
+ return;
+ }
+ if (configService.isRandom() && this.rootSuite.childSuites.length > 0) {
+ this.rootSuite.childSuites.sort(function () {
+ return Math.random().toFixed(1) > 0.5 ? -1 : 1;
+ });
+ this.currentRunningSuite = this.rootSuite.childSuites[0];
+ }
+ if (configService.isSupportAsync()) {
+ console.info(`${TAG} rootSuite:` + JSON.stringify(this.rootSuite));
+ let asyncExecute = async () => {
+ await this.coreContext.fireEvents('task', 'taskStart');
+ await this.rootSuite.asyncRun(this.coreContext);
+ };
+ asyncExecute().then(async () => {
+ await this.coreContext.fireEvents('task', 'taskDone');
+ });
+ } else {
+ console.info('${TAG} rootSuite:' + JSON.stringify(this.rootSuite));
+ this.coreContext.fireEvents('task', 'taskStart');
+ this.rootSuite.run(this.coreContext);
+ this.coreContext.fireEvents('task', 'taskDone');
+ }
+ }
+
+ apis() {
+ const _this = this;
+ return {
+ describe: function (desc, func) {
+ return _this.describe(desc, func);
+ },
+ xdescribe: function (desc, func, reason) {
+ return _this.xdescribe(desc, func, reason);
+ },
+ beforeItSpecified: function (itDescs, func) {
+ return _this.beforeItSpecified(itDescs, func);
+ },
+ afterItSpecified: function (itDescs, func) {
+ return _this.afterItSpecified(itDescs, func);
+ },
+ beforeAll: function (func) {
+ return _this.beforeAll(func);
+ },
+ beforeEach: function (func) {
+ return _this.beforeEach(func);
+ },
+ afterAll: function (func) {
+ return _this.afterAll(func);
+ },
+ afterEach: function (func) {
+ return _this.afterEach(func);
+ }
+ };
+ }
+}
+
+SuiteService.Suite = class {
+ constructor(attrs) {
+ this.description = attrs.description || '';
+ this.childSuites = [];
+ this.specs = [];
+ this.beforeAll = [];
+ this.afterAll = [];
+ this.beforeItSpecified = new Map();
+ this.afterItSpecified = new Map();
+ this.beforeEach = [];
+ this.afterEach = [];
+ this.duration = 0;
+ this.hookError = null;
+ this.isSkip = false;
+ this.skipReason = '';
+ }
+
+ pushSpec(spec) {
+ this.specs.push(spec);
+ }
+
+ removeSpec(desc) {
+ this.specs = this.specs.filter((item, index) => {
+ return item.description !== desc;
+ });
+ }
+
+ getSpecsNum() {
+ return this.specs.length;
+ }
+
+ isRun(coreContext) {
+ const configService = coreContext.getDefaultService('config');
+ const suiteService = coreContext.getDefaultService('suite');
+ const specService = coreContext.getDefaultService('spec');
+ let breakOnError = configService.isBreakOnError();
+ let isError = specService.getStatus();
+ return breakOnError && isError;
+ }
+
+ run(coreContext) {
+ const suiteService = coreContext.getDefaultService('suite');
+ suiteService.setCurrentRunningSuite(this);
+ if (this.description !== '') {
+ coreContext.fireEvents('suite', 'suiteStart', this);
+ }
+ this.runHookFunc('beforeAll');
+ if (this.specs.length > 0) {
+ const configService = coreContext.getDefaultService('config');
+ if (configService.isRandom()) {
+ this.specs.sort(function () {
+ return Math.random().toFixed(1) > 0.5 ? -1 : 1;
+ });
+ }
+ for (let spec in this.specs) {
+ let isBreakOnError = this.isRun(coreContext);
+ if (isBreakOnError) {
+ break;
+ }
+ this.runHookFunc('beforeEach');
+ spec.run(coreContext);
+ this.runHookFunc('afterEach');
+ }
+ }
+ if (this.childSuites.length > 0) {
+ for (let suite in this.childSuites) {
+ let isBreakOnError = this.isRun(coreContext);
+ if (isBreakOnError) {
+ break;
+ }
+ suite.run(coreContext);
+ suiteService.setCurrentRunningSuite(suite);
+ }
+ }
+ this.runHookFunc('afterAll');
+ if (this.description !== '') {
+ coreContext.fireEvents('suite', 'suiteDone');
+ }
+ }
+
+ async asyncRunSpecs(coreContext) {
+ const configService = coreContext.getDefaultService('config');
+ if (configService.isRandom()) {
+ this.specs.sort(function () {
+ return Math.random().toFixed(1) > 0.5 ? -1 : 1;
+ });
+ }
+ const specService = coreContext.getDefaultService('spec');
+ for (let specItem of this.specs) {
+ specService.setCurrentRunningSpec(specItem);
+ // 遇错即停模式,发现用例有问题,直接返回,不在执行后面的it
+ let isBreakOnError = this.isRun(coreContext);
+ if (isBreakOnError) {
+ console.info('break description :' + this.description);
+ break;
+ }
+ await coreContext.fireEvents('spec', 'specStart', specItem);
+ try {
+ for (const [itNames, hookFunc] of this.beforeItSpecified) {
+ if ((Object.prototype.toString.call(itNames) === '[object Array]' && itNames.includes(specItem.description)) ||
+ (Object.prototype.toString.call(itNames) === '[object String]' && itNames === specItem.description)) {
+ await Reflect.apply(hookFunc, null, []);
+ }
+ break;
+ }
+ await this.runAsyncHookFunc('beforeEach');
+ await specItem.asyncRun(coreContext);
+ for (const [itNames, hookFunc] of this.afterItSpecified) {
+ if ((Object.prototype.toString.call(itNames) === '[object Array]' && itNames.includes(specItem.description)) ||
+ (Object.prototype.toString.call(itNames) === '[object String]' && itNames === specItem.description)) {
+ await Reflect.apply(hookFunc, null, []);
+ }
+ break;
+ }
+ await this.runAsyncHookFunc('afterEach');
+ } catch (e) {
+ console.error(`${TAG}stack:${e?.stack}`);
+ console.error(`${TAG}stack end`);
+ if (e instanceof AssertException) {
+ specItem.fail = e;
+ } else {
+ specItem.error = e;
+ }
+ specService.setStatus(true);
+ }
+ specItem.setResult();
+ await coreContext.fireEvents('spec', 'specDone', specItem);
+ specService.setCurrentRunningSpec(null);
+ }
+ }
+
+ async asyncRunChildSuites(coreContext) {
+ for (let i = 0; i < this.childSuites.length; i++) {
+ // 遇错即停模式, 发现用例有问题,直接返回,不在执行后面的description
+ let isBreakOnError = this.isRun(coreContext);
+ if (isBreakOnError) {
+ console.info(`${TAG}break description : ${this.description}`);
+ break;
+ }
+ await this.childSuites[i].asyncRun(coreContext);
+ }
+ }
+
+ async asyncRun(coreContext) {
+ const suiteService = coreContext.getDefaultService('suite');
+ const specService = coreContext.getDefaultService('spec');
+
+ suiteService.setCurrentRunningSuite(this);
+ suiteService.suitesStack.push(this);
+ if (this.description !== '') {
+ await coreContext.fireEvents('suite', 'suiteStart', this);
+ }
+
+ try {
+ await this.runAsyncHookFunc('beforeAll');
+ } catch (error) {
+ console.error(`${TAG}${error?.stack}`);
+ this.hookError = error;
+ }
+
+ if (this.hookError !== null) {
+ specService.setStatus(true);
+ await suiteService.setSuiteResults(this, this.hookError, coreContext);
+ }
+
+ if (this.specs.length > 0 && this.hookError === null) {
+ await this.asyncRunSpecs(coreContext);
+ }
+
+ if (this.childSuites.length > 0 && this.hookError === null) {
+ await this.asyncRunChildSuites(coreContext);
+ }
+
+ try {
+ await this.runAsyncHookFunc('afterAll');
+ } catch (error) {
+ console.error(`${TAG}${error?.stack}`);
+ this.hookError = error;
+ specService.setStatus(true);
+ }
+
+ if (this.description !== '') {
+ await coreContext.fireEvents('suite', 'suiteDone');
+ let childSuite = suiteService.suitesStack.pop();
+ let currentRunningSuite = suiteService.suitesStack.pop();
+ suiteService.setCurrentRunningSuite(currentRunningSuite);
+ suiteService.suitesStack.push(currentRunningSuite);
+ }
+ }
+
+ runHookFunc(hookName) {
+ if (this[hookName] && this[hookName].length > 0) {
+ this[hookName].forEach(func => {
+ try {
+ func();
+ } catch (e) {
+ console.error(`${TAG}${e.stack}`);
+ }
+ });
+ }
+ }
+
+ async runAsyncHookFunc(hookName) {
+ for (const hookItem of this[hookName]) {
+ try {
+ await hookItem();
+ } catch (error) {
+ error['message'] += `, error in ${hookName} function`;
+ throw error;
+ }
+
+ }
+ }
+};
+
+class SpecService {
+ constructor(attr) {
+ this.id = attr.id;
+ this.totalTest = 0;
+ this.hasError = false;
+ this.skipSpecNum = 0;
+ this.isSkipSpec = false;
+ this.specSkipReason = '';
+ }
+
+ init(coreContext) {
+ this.coreContext = coreContext;
+ }
+
+ setCurrentRunningSpec(spec) {
+ this.currentRunningSpec = spec;
+ }
+
+ setStatus(obj) {
+ this.hasError = obj;
+ }
+
+ getStatus() {
+ return this.hasError;
+ }
+
+ getTestTotal() {
+ return this.totalTest;
+ }
+
+ getCurrentRunningSpec() {
+ return this.currentRunningSpec;
+ }
+
+
+ getSkipSpecNum() {
+ return this.skipSpecNum;
+ }
+
+ initSpecService() {
+ this.isSkipSpec = false;
+ this.specSkipReason = '';
+ }
+
+ it(desc, filter, func) {
+ const suiteService = this.coreContext.getDefaultService('suite');
+ const configService = this.coreContext.getDefaultService('config');
+ let isFilter = new NestFilter().filterNestName(suiteService.targetSuiteArray, suiteService.targetSpecArray, suiteService.suitesStack, desc);
+ if (configService.filterWithNest(desc, filter)) {
+ console.info(`${TAG}filter it :${desc}`);
+ this.initSpecService();
+ return;
+ }
+ if (configService.filterDesc(suiteService.currentRunningSuite.description, desc, filter, this.coreContext) && isFilter && !suiteService.fullRun) {
+ console.info(`${TAG}filter it :${desc}`);
+ this.initSpecService();
+ } else {
+ let processedFunc = processFunc(this.coreContext, func);
+ const spec = new SpecService.Spec({ description: desc, fi: filter, fn: processedFunc });
+ if (this.isSkipSpec) {
+ spec.isSkip = true;
+ spec.skipReason = this.specSkipReason;
+ }
+ this.initSpecService();
+ if (configService.runSkipped === 'skipped' && !spec.isSkip) {
+ console.info(`${TAG} runSkipped is skipped , just run xit, don't run it: ${spec.description}`);
+ return;
+ }
+ if (suiteService.getCurrentRunningSuite().isSkip && !spec.isSkip) {
+ configService.filterXdescribe.push(suiteService.getCurrentRunningSuite().description);
+ }
+ if (typeof this.coreContext.getServices('dataDriver') !== 'undefined' && configService['dryRun'] !== 'true') {
+ let specStress = this.coreContext.getServices('dataDriver').dataDriver.getSpecStress(desc);
+ for (let i = 1; i < specStress; i++) {
+ this.totalTest++;
+ suiteService.getCurrentRunningSuite().pushSpec(spec);
+ }
+ }
+ // dryRun 状态下不统计压力测试重复数据
+ if (configService['dryRun'] !== 'true') {
+ let stress = configService.getStress(); // 命令配置压力测试
+ console.info(`${TAG}stress length : ${stress}`);
+ for (let i = 1; i < stress; i++) {
+ this.totalTest++;
+ suiteService.getCurrentRunningSuite().pushSpec(spec);
+ }
+ }
+ this.totalTest++;
+ suiteService.getCurrentRunningSuite().pushSpec(spec);
+ }
+ }
+
+ xit(desc, filter, func, reason) {
+ const configService = this.coreContext.getDefaultService('config');
+ const suiteService = this.coreContext.getDefaultService('suite');
+ if (!configService.skipMessage && configService.runSkipped !== 'all') {
+ if (configService.runSkipped != null && configService.runSkipped !== '') {
+ let finalDesc = '';
+ suiteService.suitesStack.map(suite => {
+ finalDesc = finalDesc + '.' + suite.description;
+ });
+ finalDesc = (finalDesc + '#' + desc).substring(2);
+ if (configService.checkIfSpecInSkipRun(finalDesc)) {
+ console.info(`${TAG} runSkipped spec: ${desc}`);
+ } else {
+ console.info(reason == null ? `${TAG} skip spec: ${desc}` : `${TAG} skip spec: ${desc}, and the reason is ${reason}`);
+ return;
+ }
+ } else {
+ console.info(reason == null ? `${TAG} skip spec: ${desc}` : `${TAG} skip spec: ${desc}, and the reason is ${reason}`);
+ return;
+ }
+ }
+ this.skipSpecNum++;
+ this.isSkipSpec = true;
+ this.specSkipReason = reason;
+ this.it(desc, filter, func);
+ }
+
+ apis() {
+ const _this = this;
+ return {
+ it: function (desc, filter, func) {
+ return _this.it(desc, filter, func);
+ },
+ xit: function (desc, filter, func, reason) {
+ return _this.xit(desc, filter, func, reason);
+ }
+ };
+ }
+}
+
+SpecService.Spec = class {
+ constructor(attrs) {
+ this.description = attrs.description || '';
+ this.fi = attrs.fi;
+ this.fn = attrs.fn || function () {
+ };
+ this.fail = undefined;
+ this.error = undefined;
+ this.duration = 0;
+ this.startTime = 0;
+ this.isExecuted = false; // 当前用例是否执行
+ this.isSkip = false;
+ this.skipReason = '';
+ this.expectMsg = '';
+ }
+
+ setResult() {
+ if (this.fail) {
+ this.pass = false;
+ } else {
+ this.pass = true;
+ }
+ }
+
+ run(coreContext) {
+ const specService = coreContext.getDefaultService('spec');
+ specService.setCurrentRunningSpec(this);
+ coreContext.fireEvents('spec', 'specStart', this);
+ this.isExecuted = true;
+ try {
+ let dataDriver = coreContext.getServices('dataDriver');
+ if (typeof dataDriver === 'undefined') {
+ this.fn();
+ } else {
+ let suiteParams = dataDriver.dataDriver.getSuiteParams();
+ let specParams = dataDriver.dataDriver.getSpecParams();
+ console.info(`${TAG}[suite params] ${JSON.stringify(suiteParams)}`);
+ console.info(`${TAG}[spec params] ${JSON.stringify(specParams)}`);
+ if (this.fn.length === 0) {
+ this.fn();
+ } else if (specParams.length === 0) {
+ this.fn(suiteParams);
+ } else {
+ specParams.forEach(paramItem => this.fn(Object.assign({}, paramItem, suiteParams)));
+ }
+ }
+ this.setResult();
+ } catch (e) {
+ this.error = e;
+ specService.setStatus(true);
+ }
+ coreContext.fireEvents('spec', 'specDone', this);
+ }
+
+ async asyncRun(coreContext) {
+ const dataDriver = coreContext.getServices('dataDriver');
+ if (typeof dataDriver === 'undefined') {
+ await this.fn();
+ } else {
+ const suiteParams = dataDriver.dataDriver.getSuiteParams();
+ const specParams = dataDriver.dataDriver.getSpecParams();
+ console.info(`[suite params] ${JSON.stringify(suiteParams)}`);
+ console.info(`[spec params] ${JSON.stringify(specParams)}`);
+ if (this.fn.length === 0) {
+ await this.fn();
+ } else if (specParams.length === 0) {
+ await this.fn(suiteParams);
+ } else {
+ for (const paramItem of specParams) {
+ await this.fn(Object.assign({}, paramItem, suiteParams));
+ }
+ }
+ }
+
+ this.isExecuted = true;
+ }
+
+ filterCheck(coreContext) {
+ const specService = coreContext.getDefaultService('spec');
+ specService.setCurrentRunningSpec(this);
+ return true;
+ }
+};
+
+class ExpectService {
+ constructor(attr) {
+ this.id = attr.id;
+ this.matchers = {};
+ this.customMatchers = [];
+ }
+
+ expect(actualValue) {
+ return this.wrapMatchers(actualValue);
+ }
+
+ init(coreContext) {
+ this.coreContext = coreContext;
+ this.addMatchers(this.basicMatchers());
+ }
+
+ addMatchers(matchers) {
+ for (const matcherName in matchers) {
+ if (Object.prototype.hasOwnProperty.call(matchers, matcherName)) {
+ this.matchers[matcherName] = matchers[matcherName];
+ }
+ }
+ }
+
+ removeMatchers(customAssertionName) {
+ if (customAssertionName === 'all') {
+ for (const matcherName in this.matchers) {
+ this.matchers[matcherName] = this.customMatchers.includes(matcherName) ? (() => {throw new Error(`${matcherName} is unregistered`)}) : undefined;
+ }
+ }else {
+ this.matchers[customAssertionName] = () => {
+ throw new Error(`${customAssertionName} is unregistered`)
+ };
+ }
+ }
+
+ basicMatchers() {
+ return {
+ assertTrue: function (actualValue) {
+ return {
+ pass: (actualValue) === true,
+ message: 'expect true, actualValue is ' + actualValue
+ };
+ },
+ assertEqual: function (actualValue, args) {
+ let msg = 'expect ' + actualValue + ' equals ' + args[0];
+ if (actualValue == args[0]) { // 数值相同,提示数据类型
+ const aClassName = Object.prototype.toString.call(actualValue);
+ const bClassName = Object.prototype.toString.call(args[0]);
+ msg = 'expect ' + actualValue + aClassName + ' equals ' + args[0] + bClassName + 'strict mode inspect type';
+ }
+ return {
+ pass: (actualValue) === args[0],
+ expectValue: args[0],
+ message: msg
+ };
+ },
+ assertThrow: function (actual, args) {
+ const result = {
+ pass: false
+ };
+ if (typeof actual !== 'function') {
+ result.message = 'toThrow\'s Actual should be a Function';
+ } else {
+ let hasThrow = false;
+ let throwError;
+ try {
+ actual();
+ } catch (e) {
+ hasThrow = true;
+ throwError = e;
+ }
+ if (!hasThrow) {
+ result.message = 'function did not throw an exception';
+ } else if (throwError && throwError.message === args[0]) {
+ result.pass = true;
+ } else {
+ result.message = `expect to throw ${args[0]} , actual throw ${throwError.message}`;
+ }
+ }
+ return result;
+ }
+ };
+ }
+
+ initWrapMatchers(currentRunningSpec) {
+ return {
+ // 翻转标识
+ isNot: false,
+ // 翻转方法
+ not: function () {
+ this.isNot = true;
+ return this;
+ },
+ message: function (msg) {
+ currentRunningSpec.expectMsg = msg;
+ console.info(`${TAG} msg: ${msg}`);
+ return this;
+ }
+ };
+
+ }
+ wrapMatchers(actualValue) {
+ const _this = this;
+ const specService = _this.coreContext.getDefaultService('spec');
+ const currentRunningSpec = specService.getCurrentRunningSpec();
+ const wrappedMatchers = this.initWrapMatchers(currentRunningSpec);
+ const currentRunningSuite = _this.coreContext.getDefaultService('suite').getCurrentRunningSuite();
+ for (const matcherName in this.matchers) {
+ let result = Object.prototype.hasOwnProperty.call(this.matchers, matcherName);
+ if (!result) {
+ continue;
+ }
+ if (matcherName.search('assertPromise') == 0) {
+ wrappedMatchers[matcherName] = async function () {
+ await _this.matchers[matcherName](actualValue, arguments).then(function (result) {
+ if (wrappedMatchers.isNot) {
+ result.pass = !result.pass;
+ }
+ result.actualValue = actualValue;
+ result.checkFunc = matcherName;
+ if (!result.pass) {
+ const assertError = new AssertException(result.message);
+ currentRunningSpec ? currentRunningSpec.fail = assertError : currentRunningSuite.hookError = assertError;
+ throw assertError;
+ }
+ });
+ };
+ } else {
+ wrappedMatchers[matcherName] = function () {
+ const result = _this.customMatchers.includes(matcherName) ? _this.matchers[matcherName](actualValue, arguments[0]) : _this.matchers[matcherName](actualValue, arguments);
+ if (wrappedMatchers.isNot) {
+ result.pass = !result.pass;
+ result.message = LogExpectError.getErrorMsg(matcherName, actualValue, arguments[0], result.message);
+ }
+ result.actualValue = actualValue;
+ result.checkFunc = matcherName;
+ if (!result.pass) {
+ const assertError = new AssertException(result.message);
+ currentRunningSpec ? currentRunningSpec.fail = assertError : currentRunningSuite.hookError = assertError;
+ throw assertError;
+ }
+ };
+ }
+ }
+ return wrappedMatchers;
+ }
+
+ apis() {
+ const _this = this;
+ return {
+ expect: function (actualValue) {
+ return _this.expect(actualValue);
+ }
+ };
+ }
+}
+
+class ReportService {
+ constructor(attr) {
+ this.id = attr.id;
+ }
+
+ init(coreContext) {
+ this.coreContext = coreContext;
+ this.specService = this.coreContext.getDefaultService('spec');
+ this.suiteService = this.coreContext.getDefaultService('suite');
+ this.duration = 0;
+ }
+
+ taskStart() {
+ console.info(`${TAG}[start] start run suites`);
+ }
+
+ async suiteStart() {
+ console.info(`${TAG}[suite start]${this.suiteService.getCurrentRunningSuite().description}`);
+ }
+
+ async specStart() {
+ console.info(`${TAG}start running case '${this.specService.currentRunningSpec.description}'`);
+ this.index = this.index + 1;
+ let spec = this.specService.currentRunningSpec;
+ spec.startTime = await SysTestKit.getRealTime();
+ }
+
+ async specDone() {
+ let msg = '';
+ let spec = this.specService.currentRunningSpec;
+ let suite = this.suiteService.currentRunningSuite;
+ spec.duration = await SysTestKit.getRealTime() - spec.startTime;
+ suite.duration += spec.duration;
+ if (spec.error) {
+ this.formatPrint('error', spec.description + ' ; consuming ' + spec.duration + 'ms');
+ this.formatPrint('errorDetail', spec.error);
+ } else if (spec.fail) {
+ this.formatPrint('fail', spec.description + ' ; consuming ' + spec.duration + 'ms');
+ this.formatPrint('failDetail', spec.fail?.message);
+ } else {
+ this.formatPrint('pass', spec.description + ' ; consuming ' + spec.duration + 'ms');
+ }
+ this.formatPrint(this.specService.currentRunningSpec.error, msg);
+ }
+
+ suiteDone() {
+ let suite = this.suiteService.currentRunningSuite;
+ let message = suite.hookError ? `, ${suite.hookError?.message}` : '';
+ console.info(`[suite end] ${suite.description} consuming ${suite.duration} ms${message}`);
+ }
+
+ taskDone() {
+ let msg = '';
+ let summary = this.suiteService.getSummary();
+ msg = 'total cases:' + summary.total + ';failure ' + summary.failure + ',' + 'error ' + summary.error;
+ msg += ',pass ' + summary.pass + '; consuming ' + summary.duration + 'ms';
+ console.info(`${TAG}${msg}`);
+ console.info(`${TAG}[end] run suites end`);
+ }
+
+ incorrectFormat() {
+ if (this.coreContext.getDefaultService('config').filterValid.length !== 0) {
+ this.coreContext.getDefaultService('config').filterValid.forEach(function (item) {
+ console.info(`${TAG}this param ${item} is invalid`);
+ });
+ }
+ }
+
+ incorrectTestSuiteFormat() {
+ if (this.coreContext.getDefaultService('config').filterXdescribe.length !== 0) {
+ this.coreContext.getDefaultService('config').filterXdescribe.forEach(function (item) {
+ console.info(`${TAG}xdescribe: ${item} should not contain it`);
+ })
+ }
+ }
+
+ formatPrint(type, msg) {
+ switch (type) {
+ case 'pass':
+ console.info(`${TAG}[pass]${msg}`);
+ break;
+ case 'fail':
+ console.info(`${TAG}[fail]${msg}`);
+ break;
+ case 'failDetail':
+ console.info(`${TAG}[failDetail]${msg}`);
+ break;
+ case 'error':
+ console.info(`${TAG}[error]${msg}`);
+ break;
+ case 'errorDetail':
+ console.info(`${TAG}[errorDetail]${msg}`);
+ break;
+ }
+ }
+
+ sleep(numberMillis) {
+ var now = new Date();
+ var exitTime = now.getTime() + numberMillis;
+ while (true) {
+ now = new Date();
+ if (now.getTime() > exitTime) {
+ return;
+ }
+ }
+ }
+}
+
+export {
+ SuiteService,
+ SpecService,
+ ExpectService,
+ ReportService
+};
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/testrunner/OpenHarmonyTestRunner.ts b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/testrunner/OpenHarmonyTestRunner.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e6f4c1b12dd69714ed5a4524671abca1fbcaa58c
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/@ohos+hypium@1.0.19/oh_modules/@ohos/hypium/src/main/testrunner/OpenHarmonyTestRunner.ts
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2023-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { abilityDelegatorRegistry, TestRunner } from '@kit.TestKit';
+import { BusinessError } from '@kit.BasicServicesKit';
+import { hilog } from '@kit.PerformanceAnalysisKit';
+import { resourceManager } from '@kit.LocalizationKit';
+import { util } from '@kit.ArkTS';
+import { Hypium } from '@ohos/hypium';
+import testsuite from '../test/List.test';
+
+let abilityDelegator: abilityDelegatorRegistry.AbilityDelegator;
+let abilityDelegatorArguments: abilityDelegatorRegistry.AbilityDelegatorArgs;
+let jsonPath: string = 'mock/mock-config.json';
+let domain: number = 0x0000; //日志标识,0x0000作为测试框架的业务标识
+let tag: string = 'testTag'; //日志标识字符串,作为tag标识当前runner类下的测试行为
+
+export default class OpenHarmonyTestRunner implements TestRunner {
+ constructor() {
+ }
+
+ onPrepare() {
+ hilog.info(domain, tag, '%{public}s', 'OpenHarmonyTestRunner OnPrepare');
+ }
+
+ async onRun() {
+ hilog.info(domain, tag, '%{public}s', 'OpenHarmonyTestRunner onRun run');
+ abilityDelegatorArguments = abilityDelegatorRegistry.getArguments();
+ abilityDelegator = abilityDelegatorRegistry.getAbilityDelegator();
+ let moduleName = abilityDelegatorArguments.parameters['-m'];
+ let context = abilityDelegator.getAppContext().getApplicationContext().createModuleContext(moduleName);
+ let mResourceManager = context.resourceManager;
+ await checkMock(abilityDelegator, mResourceManager);
+ hilog.info(domain, tag, '%{public}s', 'start run testcase!!!');
+ Hypium.hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite);
+ hilog.info(domain, tag, '%{public}s', 'OpenHarmonyTestRunner onRun end');
+ }
+}
+
+async function checkMock(abilityDelegator: abilityDelegatorRegistry.AbilityDelegator, resourceManager: resourceManager.ResourceManager) {
+ let rawFile: Uint8Array;
+ try {
+ rawFile = resourceManager.getRawFileContentSync(jsonPath);
+ hilog.info(domain, tag, 'MockList file exists');
+ let mockStr: string = util.TextDecoder.create("utf-8", { ignoreBOM: true }).decodeWithStream(rawFile);
+ let mockMap: Record = getMockList(mockStr);
+ try {
+ abilityDelegator.setMockList(mockMap);
+ } catch (error) {
+ let code = (error as BusinessError).code;
+ let message = (error as BusinessError).message;
+ hilog.error(domain, tag, `abilityDelegator.setMockList failed, error code: ${code}, message: ${message}.`);
+ }
+ } catch (error) {
+ let code = (error as BusinessError).code;
+ let message = (error as BusinessError).message;
+ hilog.error(domain, tag, `ResourceManager:callback getRawFileContent failed, error code: ${code}, message: ${message}.`);
+ }
+}
+
+function getMockList(jsonStr: string) {
+ let jsonObj: Record = JSON.parse(jsonStr);
+ let map: Map = new Map(Object.entries(jsonObj));
+ let mockList: Record = {};
+ map.forEach((value: object, key: string) => {
+ let realValue: string = value['source'].toString();
+ mockList[key] = realValue;
+ });
+ hilog.info(domain, tag, '%{public}s', 'mock-json value:' + JSON.stringify(mockList) ?? '');
+ return mockList;
+}
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/BuildProfile.ets b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/BuildProfile.ets
new file mode 100644
index 0000000000000000000000000000000000000000..b054e98af7ad6092740cef28d7dcf6207e514dcb
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/BuildProfile.ets
@@ -0,0 +1,5 @@
+export default class BuildProfile {
+ static readonly HAR_VERSION = '1.0.19';
+ static readonly BUILD_MODE_NAME = 'debug';
+ static readonly DEBUG = true;
+}
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/CHANGELOG.md b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/CHANGELOG.md
new file mode 100644
index 0000000000000000000000000000000000000000..309d707c3d19f506f5582509edf1d0db9011a5b1
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/CHANGELOG.md
@@ -0,0 +1,24 @@
+## 1.0.14
+- 堆栈信息打印到cmd
+## 1.0.15
+- 支持获取测试代码的失败堆栈信息
+- mock代码迁移至harmock包
+- 适配arkts语法
+- 修复覆盖率数据容易截断的bug
+## 1.0.16
+- 修改覆盖率文件生成功能
+- 修改静态方法无法ignoreMock函数
+- ## 1.0.17
+- 修改not断言失败提示日志
+- 自定义错误message信息
+- 添加xdescribe, xit API功能
+- ## 1.0.18
+- 添加全局变量存储API get set
+- 自定义断言功能
+## 1.0.18-rc.0
+添加框架worker执行能力
+## 1.0.18-rc.1
+规范日志格式
+## 1.0.19
+- 规范日志格式
+- 代码规范整改
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/LICENSE b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..4947287f7b5ccb5d1e8b7b2d3aa5d89f322c160d
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/LICENSE
@@ -0,0 +1,177 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/README.md b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..6d795105533a9b3b9949e91d2c3dd14e8f867433
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/README.md
@@ -0,0 +1,219 @@
+Hypium
+A unit test framework for OpenHarmonyOS application
+
+## Hypium是什么?
+***
+- Hypium是OpenHarmony上的测试框架,提供测试用例编写、执行、结果显示能力,用于OpenHarmony系统应用接口以及应用界面测试。
+- Hypium结构化模型:hypium工程主要由List.test.js与TestCase.test.js组成。
+```
+rootProject // Hypium工程根目录
+├── moduleA
+│ ├── src
+│ ├── main // 被测试应用目录
+│ ├── ohosTest // 测试用例目录
+│ ├── js/ets
+│ └── test
+│ └── List.test.js // 测试用例加载脚本,ets目录下为.ets后缀
+│ └── TestCase.test.js // 测试用例脚本,ets目录下为.ets后缀
+└── moduleB
+ ...
+│ └── List.test.js // 测试用例加载脚本,ets目录下为.ets后缀
+│ └── TestCase.test.js // 测试用例脚本,ets目录下为.ets后缀
+```
+
+## 安装使用
+***
+- 在DevEco Studio内使用Hypium
+- 工程级package.json内配置:
+```json
+"dependencies": {
+ "@ohos/hypium": "1.0.19"
+}
+```
+注:
+hypium服务于OpenHarmonyOS应用对外接口测试、系统对外接口测试(SDK中接口),完成HAP自动化测试。详细指导:
+[Deveco Studio](https://developer.harmonyos.com/cn/develop/deveco-studio)
+
+#### 通用语法
+
+- 测试用例采用业内通用语法,describe代表一个测试套, it代表一条用例。
+
+| No. | API | 功能说明 |
+| --- | ---------- | ---------------------------------------------------------------------------------------------------------------------- |
+| 1 | describe | 定义一个测试套,支持两个参数:测试套名称和测试套函数 |
+| 2 | beforeAll | 在测试套内定义一个预置条件,在所有测试用例开始前执行且仅执行一次,支持一个参数:预置动作函数 |
+| 3 | beforeEach | 在测试套内定义一个单元预置条件,在每条测试用例开始前执行,执行次数与it定义的测试用例数一致,支持一个参数:预置动作函数 |
+| 4 | afterEach | 在测试套内定义一个单元清理条件,在每条测试用例结束后执行,执行次数与it定义的测试用例数一致,支持一个参数:清理动作函数 |
+| 5 | afterAll | 在测试套内定义一个清理条件,在所有测试用例结束后执行且仅执行一次,支持一个参数:清理动作函数 |
+| 6 | it | 定义一条测试用例,支持三个参数:用例名称,过滤参数和用例函数 |
+| 7 | expect | 支持bool类型判断等多种断言方法 |
+
+#### 断言库
+
+- 示例代码:
+
+```javascript
+ expect(${actualvalue}).assertX(${expectvalue})
+```
+
+- 断言功能列表:
+
+| No. | API | 功能说明 |
+| :--- | :------------------------------- | ---------------------------------------------------------------------------------------------- |
+| 1 | assertClose | 检验actualvalue和expectvalue(0)的接近程度是否是expectValue(1) |
+| 2 | assertContain | 检验actualvalue中是否包含expectvalue |
+| 3 | assertDeepEquals | @since1.0.4 检验actualvalue和expectvalue(0)是否是同一个对象 |
+| 4 | assertEqual | 检验actualvalue是否等于expectvalue[0] |
+| 5 | assertFail | 抛出一个错误 |
+| 6 | assertFalse | 检验actualvalue是否是false |
+| 7 | assertTrue | 检验actualvalue是否是true |
+| 8 | assertInstanceOf | 检验actualvalue是否是expectvalue类型 |
+| 9 | assertLarger | 检验actualvalue是否大于expectvalue |
+| 10 | assertLess | 检验actualvalue是否小于expectvalue |
+| 11 | assertNaN | @since1.0.4 检验actualvalue是否是NaN |
+| 12 | assertNegUnlimited | @since1.0.4 检验actualvalue是否等于Number.NEGATIVE_INFINITY |
+| 13 | assertNull | 检验actualvalue是否是null |
+| 14 | assertPosUnlimited | @since1.0.4 检验actualvalue是否等于Number.POSITIVE_INFINITY |
+| 15 | assertPromiseIsPending | @since1.0.4 检验actualvalue是否处于Pending状态【actualvalue为promse对象】 |
+| 16 | assertPromiseIsRejected | @since1.0.4 检验actualvalue是否处于Rejected状态【同15】 |
+| 17 | assertPromiseIsRejectedWith | @since1.0.4 检验actualvalue是否处于Rejected状态,并且比较执行的结果值【同15】 |
+| 18 | assertPromiseIsRejectedWithError | @since1.0.4 检验actualvalue是否处于Rejected状态并有异常,同时比较异常的类型和message值【同15】 |
+| 19 | assertPromiseIsResolved | @since1.0.4 检验actualvalue是否处于Resolved状态【同15】 |
+| 20 | assertPromiseIsResolvedWith | @since1.0.4 检验actualvalue是否处于Resolved状态,并且比较执行的结果值【同15】 |
+| 21 | assertThrowError | 检验actualvalue抛出Error内容是否是expectValue |
+| 22 | assertUndefined | 检验actualvalue是否是undefined |
+| 23 | not | @since1.0.4 断言结果取反 |
+
+
+示例代码:
+
+```javascript
+ import { describe, it, expect } from '@ohos/hypium';
+
+ export default async function assertCloseTest() {
+ describe('assertClose', function () {
+ it('assertClose_success', 0, function () {
+ let a = 100;
+ let b = 0.1;
+ expect(a).assertClose(99, b);
+ })
+ })
+ }
+```
+
+#### 公共系统能力
+
+| No. | API | 功能描述 |
+| ---- | ------------------------------------------------------- | ------------------------------------------------------------ |
+| 1 | existKeyword(keyword: string, timeout: number): boolean | @since1.0.3 hilog日志中查找指定字段是否存在,keyword是待查找关键字,timeout为设置的查找时间 |
+| 2 | actionStart(tag: string): void | @since1.0.3 cmd窗口输出开始tag |
+| 3 | actionEnd(tag: string): void | @since1.0.3 cmd窗口输出结束tag |
+
+示例代码:
+
+```javascript
+import { describe, it, expect, SysTestKit} from '@ohos/hypium';
+
+export default function existKeywordTest() {
+ describe('existKeywordTest', function () {
+ it('existKeyword',DEFAULT, async function () {
+ console.info("HelloTest");
+ let isExist = await SysTestKit.existKeyword('HelloTest');
+ console.info('isExist ------>' + isExist);
+ })
+ })
+}
+```
+```javascript
+import { describe, it, expect, SysTestKit} from '@ohos/hypium';
+
+export default function actionTest() {
+ describe('actionTest', function () {
+ it('existKeyword',DEFAULT, async function () {
+ let tag = '[MyTest]';
+ SysTestKit.actionStart(tag);
+ //do something
+ SysTestKit.actionEnd(tag);
+ })
+ })
+}
+```
+
+#### 专项能力
+
+- 测试用例属性筛选能力:hypium支持根据用例属性筛选执行指定测试用例,使用方式是先在测试用例上标记用例属性后,再在测试应用的启动shell命令后新增" -s ${Key} ${Value}"。
+
+| Key | 含义说明 | Value取值范围 |
+| -------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| level | 用例级别 | "0","1","2","3","4", 例如:-s level 1 |
+| size | 用例粒度 | "small","medium","large", 例如:-s size small |
+| testType | 用例测试类型 | "function","performance","power","reliability","security","global","compatibility","user","standard","safety","resilience", 例如:-s testType function |
+
+示例代码
+
+```javascript
+import { describe, it, expect, TestType, Size, Level } from '@ohos/hypium';
+
+export default function attributeTest() {
+ describe('attributeTest', function () {
+ it("testAttributeIt", TestType.FUNCTION | Size.SMALLTEST | Level.LEVEL0, function () {
+ console.info('Hello Test');
+ })
+ })
+}
+```
+
+示例命令
+```shell
+XX -s level 1 -s size small -s testType function
+```
+该命令的作用是:筛选测试应用中同时满足a)用例级别是1 b)用例粒度是small c)用例测试类型是function 三个条件的用例执行。
+
+- 测试套/测试用例名称筛选能力(测试套与用例名称用“#”号连接,多个用“,”英文逗号分隔)
+
+| Key | 含义说明 | Value取值范围 |
+| -------- | ----------------------- | -------------------------------------------------------------------------------------------- |
+| class | 指定要执行的测试套&用例 | ${describeName}#${itName},${describeName} , 例如:-s class attributeTest#testAttributeIt |
+| notClass | 指定不执行的测试套&用例 | ${describeName}#${itName},${describeName} , 例如:-s notClass attributeTest#testAttributeIt |
+
+示例命令
+```shell
+XX -s class attributeTest#testAttributeIt,abilityTest#testAbilityIt
+```
+该命令的作用是:筛选测试应用中attributeTest测试套下的testAttributeIt测试用例,abilityTest测试套下的testAbilityIt测试用例,只执行这两条用例。
+
+- 其他能力
+
+| 能力项 | Key | 含义说明 | Value取值范围 |
+| ------------ | ------- | ---------------------------- | ---------------------------------------------- |
+| 随机执行能力 | random | 测试套&测试用例随机执行 | true, 不传参默认为false, 例如:-s random true |
+| 空跑能力 | dryRun | 显示要执行的测试用例信息全集 | true , 不传参默认为false,例如:-s dryRun true |
+| 异步超时能力 | timeout | 异步用例执行的超时时间 | 正整数 , 单位ms,例如:-s timeout 5000 |
+
+##### 约束限制
+随机执行能力和空跑能力从npm包1.0.3版本开始支持
+
+#### Mock能力
+
+##### 约束限制
+
+单元测试框架Mock能力从npm包[1.0.1版本](https://repo.harmonyos.com/#/cn/application/atomService/@ohos%2Fhypium/v/1.0.1)开始支持
+
+## 约束
+
+***
+ 本模块首批接口从OpenHarmony SDK API version 8开始支持。
+
+## Hypium开放能力隐私声明
+
+- 我们如何收集和使用您的个人信息
+ 您在使用集成了Hypium开放能力的测试应用时,Hypium不会处理您的个人信息。
+- SDK处理的个人信息
+ 不涉及。
+- SDK集成第三方服务声明
+ 不涉及。
+- SDK数据安全保护
+ 不涉及。
+- SDK版本更新声明
+ 为了向您提供最新的服务,我们会不时更新Hypium版本。我们强烈建议开发者集成使用最新版本的Hypium。
+
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/build-profile.json5 b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/build-profile.json5
new file mode 100644
index 0000000000000000000000000000000000000000..312d38eb08629793b3484c7373213f22840c8d82
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/build-profile.json5
@@ -0,0 +1,28 @@
+{
+ "apiType": "stageMode",
+ "buildOption": {
+ },
+ "buildOptionSet": [
+ {
+ "name": "release",
+ "arkOptions": {
+ "obfuscation": {
+ "ruleOptions": {
+ "enable": true,
+ "files": [
+ "./obfuscation-rules.txt"
+ ]
+ },
+ "consumerFiles": [
+ "./consumer-rules.txt"
+ ]
+ }
+ },
+ },
+ ],
+ "targets": [
+ {
+ "name": "default"
+ }
+ ]
+}
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/hvigorfile.ts b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/hvigorfile.ts
new file mode 100644
index 0000000000000000000000000000000000000000..42187071482d292588ad40babeda74f7b8d97a23
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/hvigorfile.ts
@@ -0,0 +1,6 @@
+import { harTasks } from '@ohos/hvigor-ohos-plugin';
+
+export default {
+ system: harTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
+ plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
+}
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/index.d.ts b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/index.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7272b5fa839a2cd510d0c70d517bb6800133dba2
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/index.d.ts
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export const DEFAULT = 0B0000
+
+export const when: when;
+
+export enum TestType {
+ FUNCTION = 0B1,
+ PERFORMANCE = 0B1 << 1,
+ POWER = 0B1 << 2,
+ RELIABILITY = 0B1 << 3,
+ SECURITY = 0B1 << 4,
+ GLOBAL = 0B1 << 5,
+ COMPATIBILITY = 0B1 << 6,
+ USER = 0B1 << 7,
+ STANDARD = 0B1 << 8,
+ SAFETY = 0B1 << 9,
+ RESILIENCE = 0B1 << 10
+}
+
+export enum Size {
+ SMALLTEST = 0B1 << 16,
+ MEDIUMTEST = 0B1 << 17,
+ LARGETEST = 0B1 << 18
+}
+
+export enum Level {
+ LEVEL0 = 0B1 << 24,
+ LEVEL1 = 0B1 << 25,
+ LEVEL2 = 0B1 << 26,
+ LEVEL3 = 0B1 << 27,
+ LEVEL4 = 0B1 << 28
+}
+export { xdescribe, xit, describe, it } from './index';
+
+
+
+export function beforeItSpecified(testCaseNames: Array | string, callback: Function): void
+
+export function afterItSpecified(testCaseNames: Array | string, callback: Function): void
+
+export function beforeEach(callback: Function): void
+
+export function afterEach(callback: Function): void
+
+export function beforeAll(callback: Function): void
+
+export function afterAll(callback: Function): void
+
+
+export interface Assert {
+ assertClose(expectValue: number, precision: number): void
+ assertContain(expectValue: any): void
+ assertEqual(expectValue: any): void
+ assertFail(): void
+ assertFalse(): void
+ assertTrue(): void
+ assertInstanceOf(expectValue: string): void
+ assertLarger(expectValue: number): void
+ assertLess(expectValue: number): void
+ assertNull(): void
+ assertThrowError(expectValue: string | Function): void
+ assertUndefined(): void
+ assertLargerOrEqual(expectValue: number): void
+ assertLessOrEqual(expectValue: number): void
+ assertNaN(): void
+ assertNegUnlimited(): void
+ assertPosUnlimited(): void
+ not(): Assert;
+ assertDeepEquals(expectValue: any): void
+ assertPromiseIsPending(): Promise
+ assertPromiseIsRejected(): Promise
+ assertPromiseIsRejectedWith(expectValue?: any): Promise
+ assertPromiseIsRejectedWithError(...expectValue): Promise
+ assertPromiseIsResolved(): Promise
+ assertPromiseIsResolvedWith(expectValue?: any): Promise
+ message(msg: string): Assert
+}
+
+export function expect(actualValue?: any): Assert
+
+export class ArgumentMatchers {
+ static any;
+ static anyString;
+ static anyBoolean;
+ static anyNumber;
+ static anyObj;
+ static anyFunction;
+ static matchRegexs(Regex: RegExp): void
+}
+
+declare interface when {
+ afterReturn(value: any): any
+ afterReturnNothing(): undefined
+ afterAction(action: any): any
+ afterThrow(e_msg: string): string
+ (argMatchers?: any): when;
+}
+
+export interface VerificationMode {
+ times(count: Number): void
+ never(): void
+ once(): void
+ atLeast(count: Number): void
+ atMost(count: Number): void
+}
+
+export class MockKit {
+ constructor()
+ mockFunc(obj: Object, func: Function): Function
+ mockObject(obj: Object): Object
+ verify(methodName: String, argsArray: Array): VerificationMode
+ ignoreMock(obj: Object, func: Function): void
+ clear(obj: Object): void
+ clearAll(): void
+}
+
+export class SysTestKit {
+ static getDescribeName(): string;
+ static getItName(): string;
+ static getItAttribute(): TestType | Size | Level
+ static actionStart(tag: string): void
+ static actionEnd(tag: string): void
+ static existKeyword(keyword: string, timeout?: number): boolean
+}
+
+export class Hypium {
+ static setData(data: { [key: string]: any }): void
+ static setTimeConfig(systemTime: any)
+ static hypiumTest(abilityDelegator: any, abilityDelegatorArguments: any, testsuite: Function): void
+ static set(key: string, value: any): void
+ static get(key: string): any
+ static registerAssert(customAssertion: Function): void
+ static unregisterAssert(customAssertion: string | Function): void
+ static hypiumWorkerTest(abilityDelegator: Object, abilityDelegatorArguments: Object, testsuite: Function, workerPort: Object): void;
+ static hypiumInitWorkers(abilityDelegator: Object, scriptURL: string, workerNum: number, params: Object): void;
+}
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/index.ets b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/index.ets
new file mode 100644
index 0000000000000000000000000000000000000000..02a237f1c999d1f48b3974b6076d5dae9213245a
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/index.ets
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Core from './src/main/core';
+import {TestType, Size, Level, DEFAULT} from './src/main/Constant';
+import DataDriver from './src/main/module/config/DataDriver';
+import ExpectExtend from './src/main/module/assert/ExpectExtend';
+import OhReport from './src/main/module/report/OhReport';
+export { xdescribe, xit, describe, it } from './index.ts';
+
+export declare class Hypium {
+ static setData(data: Object): void
+ static setTimeConfig(systemTime: Object): void
+ static hypiumTest(abilityDelegator: Object, abilityDelegatorArguments: Object, testsuite: Function): void
+ static set(key: string, value: Object): void
+ static get(key: string): Object
+ static registerAssert(customAssertion: Function): void
+ static unregisterAssert(customAssertion: string | Function): void
+ static hypiumWorkerTest(abilityDelegator: Object, abilityDelegatorArguments: Object,
+ testsuite: Function, workerPort: Object): void;
+ static hypiumInitWorkers(abilityDelegator: Object, scriptURL: string, workerNum: number, params: Object): void;
+}
+
+export {
+ Core,
+ DataDriver,
+ ExpectExtend,
+ OhReport,
+ TestType,
+ Size,
+ Level,
+ DEFAULT
+};
+
+type allExpectType = Object | undefined | null
+
+export declare function beforeItSpecified(testCaseNames: Array | string, callback: Function): void
+
+export declare function afterItSpecified(testCaseNames: Array | string, callback: Function): void
+
+export declare function beforeEach(callback: Function): void
+
+export declare function afterEach(callback: Function): void
+
+export declare function beforeAll(callback: Function): void
+
+export declare function afterAll(callback: Function): void
+
+export declare interface Assert {
+ assertClose(expectValue: number, precision: number): void
+ assertContain(expectValue: allExpectType): void
+ assertEqual(expectValue: allExpectType): void
+ assertFail(): void
+ assertFalse(): void
+ assertTrue(): void
+ assertInstanceOf(expectValue: string): void
+ assertLarger(expectValue: number): void
+ assertLess(expectValue: number): void
+ assertNull(): void
+ assertThrowError(expectValue: string | Function): void
+ assertUndefined(): void
+ assertLargerOrEqual(expectValue: number):void
+ assertLessOrEqual(expectValue: number):void
+ assertNaN():void
+ assertNegUnlimited(): void
+ assertPosUnlimited(): void
+ not(): Assert;
+ assertDeepEquals(expectValue: allExpectType):void
+ assertPromiseIsPending(): Promise
+ assertPromiseIsRejected(): Promise
+ assertPromiseIsRejectedWith(expectValue?: allExpectType): Promise
+ assertPromiseIsRejectedWithError(...expectValue: allExpectType[]): Promise
+ assertPromiseIsResolved(): Promise
+ assertPromiseIsResolvedWith(expectValue?: allExpectType): Promise
+ message(msg: string): Assert
+}
+
+export declare function expect(actualValue?: allExpectType): Assert
+
+export declare class ArgumentMatchers {
+ public static any: allExpectType;
+ public static anyString: string;
+ public static anyBoolean: Boolean;
+ public static anyNumber: Number;
+ public static anyObj: Object;
+ public static anyFunction: Function;
+ public static matchRegexs(regex: RegExp): void
+}
+
+declare interface whenResult {
+ afterReturn: (value: allExpectType) => allExpectType
+ afterReturnNothing: () => undefined
+ afterAction: (action: allExpectType) => allExpectType
+ afterThrow: (e_msg: string) => string
+}
+
+export declare function when(f:Function): (f?: allExpectType | void) => whenResult
+
+export declare interface VerificationMode {
+ times(count: Number): void
+ never(): void
+ once(): void
+ atLeast(count: Number): void
+ atMost(count: Number): void
+}
+
+export declare class MockKit {
+ constructor()
+ mockFunc(obj: Object, func: Function): Function
+ mockObject(obj: Object): Object
+ verify(methodName: String, argsArray: Array): VerificationMode
+ ignoreMock(obj: Object, func: Function): void
+ clear(obj: Object): void
+ clearAll(): void
+}
+
+export declare class SysTestKit {
+ static getDescribeName(): string;
+ static getItName(): string;
+ static getItAttribute(): TestType | Size | Level
+ static actionStart(tag: string): void
+ static actionEnd(tag: string): void
+ static existKeyword(keyword: string, timeout?: number): boolean
+}
+
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/index.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..02d06d9d1b4b478aa2aec70ba3a73a5e123c98db
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/index.js
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License")
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Core from './src/main/core';
+import { DEFAULT, TestType, Size, Level, TAG, PrintTag } from './src/main/Constant';
+import DataDriver from './src/main/module/config/DataDriver';
+import ExpectExtend from './src/main/module/assert/ExpectExtend';
+import OhReport from './src/main/module/report/OhReport';
+import SysTestKit from './src/main/module/kit/SysTestKit';
+import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, beforeItSpecified, afterItSpecified, xdescribe, xit } from './src/main/interface';
+import { MockKit, when } from './src/main/module/mock/MockKit';
+import ArgumentMatchers from './src/main/module/mock/ArgumentMatchers';
+import worker from '@ohos.worker';
+
+class Hypium {
+ static context = new Map();
+ static setData(data) {
+ const core = Core.getInstance();
+ const dataDriver = new DataDriver({ data });
+ core.addService('dataDriver', dataDriver);
+ }
+
+ static setTimeConfig(systemTime) {
+ SysTestKit.systemTime = systemTime;
+ }
+
+ static set(key, value) {
+ Hypium.context.set(key, value);
+ }
+
+ static get(key) {
+ return Hypium.context.get(key);
+ }
+
+ static hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite) {
+ const core = Core.getInstance();
+ const expectExtend = new ExpectExtend({
+ 'id': 'extend'
+ });
+ core.addService('expect', expectExtend);
+ const ohReport = new OhReport({
+ 'delegator': abilityDelegator,
+ 'abilityDelegatorArguments': abilityDelegatorArguments
+ });
+ SysTestKit.delegator = abilityDelegator;
+ core.addService('report', ohReport);
+ core.init();
+ core.subscribeEvent('spec', ohReport);
+ core.subscribeEvent('suite', ohReport);
+ core.subscribeEvent('task', ohReport);
+ const configService = core.getDefaultService('config');
+ if (abilityDelegatorArguments !== null) {
+ let testParameters = configService.translateParams(abilityDelegatorArguments.parameters);
+ console.info(`${TAG}parameters:${JSON.stringify(testParameters)}`);
+ configService.setConfig(testParameters);
+ }
+ testsuite();
+ core.execute(abilityDelegator);
+ }
+ static async hypiumInitWorkers(abilityDelegator, scriptURL, workerNum = 8, params) {
+ console.info(`${TAG}, hypiumInitWorkers call,${scriptURL}`);
+ let workerPromiseArray = [];
+
+ // 开始统计时间
+ let startTime = await SysTestKit.getRealTime();
+ for (let i = 0; i < workerNum; i++) {
+ // 创建worker线程
+ const workerPromise = Hypium.createWorkerPromise(scriptURL, i, params);
+ workerPromiseArray.push(workerPromise);
+ }
+ const ret = {total: 0, failure: 0, error: 0, pass: 0, ignore: 0, duration: 0};
+ Promise.all(workerPromiseArray).then(async (items) => {
+ console.info(`${TAG}, all result from workers, ${JSON.stringify(items)}`);
+ let allItemList = new Array();
+ // 统计执行结果
+ Hypium.handleWorkerTestResult(ret, allItemList, items);
+ console.info(`${TAG}, all it result, ${JSON.stringify(allItemList)}`);
+ // 统计用例执行结果
+ const retResult = {total: 0, failure: 0, error: 0, pass: 0, ignore: 0, duration: 0};
+ // 标记用例执行结果
+ Hypium.configWorkerItTestResult(retResult, allItemList);
+ // 打印用例结果
+ Hypium.printWorkerTestResult(abilityDelegator, allItemList);
+ // 用例执行完成统计时间
+ let endTime = await SysTestKit.getRealTime();
+ const taskConsuming = endTime - startTime;
+ const message =
+ `\n${PrintTag.OHOS_REPORT_ALL_RESULT}: stream=Test run: runTimes: ${ret.total},total: ${retResult.total}, Failure: ${retResult.failure}, Error: ${retResult.error}, Pass: ${retResult.pass}, Ignore: ${retResult.ignore}` +
+ `\n${PrintTag.OHOS_REPORT_ALL_CODE}: ${retResult.failure > 0 || retResult.error > 0 ? -1 : 0}` +
+ `\n${PrintTag.OHOS_REPORT_ALL_STATUS}: taskconsuming=${taskConsuming > 0 ? taskConsuming : ret.duration}`;
+ abilityDelegator.printSync(message);
+ console.info(`${TAG}, [end] you worker test`);
+ abilityDelegator.finishTest('you worker test finished!!!', 0, () => {});
+ }).catch((e) => {
+ console.info(`${TAG}, [end] error you worker test, ${JSON.stringify(e)}`);
+ abilityDelegator.finishTest('you worker test error finished!!!', 0, () => {});
+ }).finally(() => {
+ console.info(`${TAG}, all promise finally end`);
+ });
+ }
+ // 创建worker线程
+ static createWorkerPromise(scriptURL, i, params) {
+ console.info(`${TAG}, createWorkerPromiser, ${scriptURL}, ${i}`);
+ const workerPromise = new Promise((resolve, reject) => {
+ const workerInstance = new worker.ThreadWorker(scriptURL, {name: `worker_${i}`});
+ console.info(`${TAG}, send data to worker`);
+ // 发送数据到worker线程中
+ workerInstance.postMessage(params);
+ workerInstance.onmessage = function (e) {
+ let currentThreadName = e.data?.currentThreadName;
+ console.info(`${TAG}, receview data from ${currentThreadName}, ${JSON.stringify(e.data)}`);
+ //
+ resolve(e.data?.summary);
+ console.info(`${TAG}, ${currentThreadName} finish`);
+ workerInstance.terminate();
+ };
+ workerInstance.onerror = function (e) {
+ console.info(`${TAG}, worker error, ${JSON.stringify(e)}`);
+ reject(e);
+ workerInstance.terminate();
+ };
+ workerInstance.onmessageerror = function (e) {
+ console.info(`${TAG}, worker message error, ${JSON.stringify(e)}`);
+ reject(e);
+ workerInstance.terminate();
+ };
+ });
+ return workerPromise;
+ }
+ static handleWorkerTestResult(ret, allItemList, items) {
+ console.info(`${TAG}, handleWorkerTestResult, ${JSON.stringify(items)}`);
+ for (const {total, failure, error, pass, ignore, duration, itItemList} of items) {
+ ret.total += total;
+ ret.failure += failure;
+ ret.error += error;
+ ret.pass += pass;
+ ret.ignore += ignore;
+ ret.duration += duration;
+ Hypium.handleItResult(allItemList, itItemList);
+ }
+ }
+ static handleItResult(allItemList, itItemList) {
+ // 遍历所有的用例结果统计最终结果
+ for (const {currentThreadName, description, result} of itItemList) {
+ let item = allItemList.find((it) => it.description === description);
+ if (item) {
+ let itResult = item.result;
+ // 当在worker中出现一次failure就标记为failure, 出现一次error就标记为error, 所有线程都pass才标记为pass
+ if (itResult === 0) {
+ item.result = result;
+ item.currentThreadName = currentThreadName;
+ }
+ } else {
+ let it = {
+ description: description,
+ currentThreadName: currentThreadName,
+ result: result
+ };
+ allItemList.push(it);
+ }
+ }
+ }
+ static configWorkerItTestResult(retResult, allItemList) {
+ console.info(`${TAG}, configWorkerItTestResult, ${JSON.stringify(allItemList)}`);
+ for (const {currentThreadName, description, result} of allItemList) {
+ console.info(`${TAG}, description, ${description}, result,${result}`);
+ retResult.total ++;
+ if (result === 0) {
+ retResult.pass ++;
+ } else if (result === -1) {
+ retResult.error ++;
+ } else if (result === -2) {
+ retResult.failure ++;
+ } else {
+ retResult.ignore ++;
+ }
+ }
+ }
+ static printWorkerTestResult(abilityDelegator, allItemList) {
+ console.info(`${TAG}, printWorkerTestResult, ${JSON.stringify(allItemList)}`);
+ let index = 1;
+ for (const {currentThreadName, description, result} of allItemList) {
+ console.info(`${TAG}, description print, ${description}, result,${result}`);
+ let itArray = description.split('#');
+ let des;
+ let itName;
+ if (itArray.length > 1) {
+ des = itArray[0];
+ itName = itArray[1];
+ } else if (itArray.length > 1) {
+ des = itArray[0];
+ itName = itArray[0];
+ } else {
+ des = 'undefined';
+ itName = 'undefined';
+ }
+
+ let msg = `\n${PrintTag.OHOS_REPORT_WORKER_STATUS}: class=${des}`;
+ msg += `\n${PrintTag.OHOS_REPORT_WORKER_STATUS}: test=${itName}`;
+ msg += `\n${PrintTag.OHOS_REPORT_WORKER_STATUS}: current=${index}`;
+ msg += `\n${PrintTag.OHOS_REPORT_WORKER_STATUS}: CODE=${result}`;
+ abilityDelegator.printSync(msg);
+ index ++;
+ }
+ }
+ static hypiumWorkerTest(abilityDelegator, abilityDelegatorArguments, testsuite, workerPort) {
+ console.info(`${TAG}, hypiumWorkerTest call`);
+ SysTestKit.workerPort = workerPort;
+ let currentWorkerName = workerPort.name;
+ console.info(`${TAG}, hypiumWorkerTest_currentWorkerName: ${currentWorkerName}`);
+ Hypium.hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite);
+
+ }
+
+ static registerAssert(customAssertion) {
+ const core = Core.getInstance();
+ const expectService = core.getDefaultService('expect');
+ let matchers = {};
+ matchers[customAssertion.name] = customAssertion;
+ expectService.addMatchers(matchers);
+ expectService.customMatchers.push(customAssertion.name);
+ console.info(`${TAG}success to register the ${customAssertion.name}`);
+ }
+
+ static unregisterAssert(customAssertion) {
+ const core = Core.getInstance();
+ const expectService = core.getDefaultService('expect');
+ let customAssertionName = typeof customAssertion === 'function' ? customAssertion.name : customAssertion;
+ expectService.removeMatchers(customAssertionName);
+ console.info(`${TAG}success to unregister the ${customAssertionName}`);
+ }
+
+}
+
+export {
+ Hypium,
+ Core,
+ DEFAULT,
+ TestType,
+ Size,
+ Level,
+ DataDriver,
+ ExpectExtend,
+ OhReport,
+ SysTestKit,
+ describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, beforeItSpecified, afterItSpecified, xdescribe, xit,
+ MockKit, when,
+ ArgumentMatchers
+};
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/index.ts b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b7082ebc98214b58d41e8681791809f1aee48f12
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/index.ts
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { TestType, Size, Level } from "./src/main/Constant";
+
+export declare function xdescribe(testSuiteName: string, func: Function): void;
+
+export declare namespace xdescribe {
+ function reason(reason: string): any;
+};
+
+export declare function describe(testSuiteName: string, func: Function): void;
+
+export declare function xit(testCaseName: string, attribute: TestType | Size | Level, func: Function): void;
+
+export declare namespace xit {
+ function reason(reason: string): any;
+};
+
+export declare function it(testCaseName: string, attribute: TestType | Size | Level, func: Function): void;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/oh-package.json5 b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/oh-package.json5
new file mode 100644
index 0000000000000000000000000000000000000000..d91344eda60f35477a5caf4bf5c116ffac2e53db
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/oh-package.json5
@@ -0,0 +1 @@
+{"name":"@ohos/hypium","version":"1.0.19","description":"A unit test framework for OpenHarmony application","main":"index.js","keywords":["测试框架","except","mock"],"author":"huawei","license":"Apache-2.0","repository":"https://gitee.com/openharmony/testfwk_arkxtest","homepage":"https://gitee.com/openharmony/testfwk_arkxtest","dependencies":{}}
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/Constant.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/Constant.js
new file mode 100644
index 0000000000000000000000000000000000000000..f470d69cd9a3302b19d45c147ca7d7c1dd8a3b18
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/Constant.js
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * define the testcase type : TestType, Size , Level
+ */
+export const TAG = '[Hypium]';
+
+export const DEFAULT = 0B0000;
+
+export class PrintTag {
+ static OHOS_REPORT_WORKER_STATUS = 'OHOS_REPORT_WORKER_STATUS';
+ static OHOS_REPORT_ALL_RESULT = 'OHOS_REPORT_ALL_RESULT';
+ static OHOS_REPORT_ALL_CODE = 'OHOS_REPORT_ALL_CODE';
+ static OHOS_REPORT_ALL_STATUS = 'OHOS_REPORT_ALL_STATUS';
+ static OHOS_REPORT_RESULT = 'OHOS_REPORT_RESULT';
+ static OHOS_REPORT_CODE = 'OHOS_REPORT_CODE';
+ static OHOS_REPORT_STATUS = 'OHOS_REPORT_STATUS';
+ static OHOS_REPORT_SUM = 'OHOS_REPORT_SUM';
+ static OHOS_REPORT_STATUS_CODE = 'OHOS_REPORT_STATUS_CODE';
+};
+
+export class TestType {
+ static FUNCTION = 0B1;
+ static PERFORMANCE = 0B1 << 1;
+ static POWER = 0B1 << 2;
+ static RELIABILITY = 0B1 << 3;
+ static SECURITY = 0B1 << 4;
+ static GLOBAL = 0B1 << 5;
+ static COMPATIBILITY = 0B1 << 6;
+ static USER = 0B1 << 7;
+ static STANDARD = 0B1 << 8;
+ static SAFETY = 0B1 << 9;
+ static RESILIENCE = 0B1 << 10;
+}
+
+export class Size {
+ static SMALLTEST = 0B1 << 16;
+ static MEDIUMTEST = 0B1 << 17;
+ static LARGETEST = 0B1 << 18;
+}
+
+export class Level {
+ static LEVEL0 = 0B1 << 24;
+ static LEVEL1 = 0B1 << 25;
+ static LEVEL2 = 0B1 << 26;
+ static LEVEL3 = 0B1 << 27;
+ static LEVEL4 = 0B1 << 28;
+}
+
+export const TESTTYPE = {
+ 'function': 1,
+ 'performance': 1 << 1,
+ 'power': 1 << 2,
+ 'reliability': 1 << 3,
+ 'security': 1 << 4,
+ 'global': 1 << 5,
+ 'compatibility': 1 << 6,
+ 'user': 1 << 7,
+ 'standard': 1 << 8,
+ 'safety': 1 << 9,
+ 'resilience': 1 << 10,
+}
+
+export const LEVEL = {
+ '0': 1 << 24,
+ '1': 1 << 25,
+ '2': 1 << 26,
+ '3': 1 << 27,
+ '4': 1 << 28,
+}
+
+export const SIZE = {
+ 'small': 1 << 16,
+ 'medium': 1 << 17,
+ 'large': 1 << 18,
+}
+
+export const KEYSET = [
+ '-s class', '-s notClass', '-s suite', '-s itName',
+ '-s level', '-s testType', '-s size', '-s timeout',
+ '-s dryRun', '-s random', '-s breakOnError', '-s stress',
+ '-s coverage', '-s skipMessage', '-s runSkipped',
+ 'class', 'notClass', 'suite', 'itName',
+ 'level', 'testType', 'size', 'timeout', 'dryRun', 'random',
+ 'breakOnError', 'stress', 'coverage', 'skipMessage', 'runSkipped'
+]
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/core.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/core.js
new file mode 100644
index 0000000000000000000000000000000000000000..cfcb5f17287208f5e6869b4248faf6c9093002d9
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/core.js
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {SuiteService, SpecService, ExpectService, ReportService} from './service';
+import {ConfigService} from './module/config/configService';
+import {SpecEvent, TaskEvent, SuiteEvent} from './event';
+
+/**
+ * core service for execute testcase.
+ */
+class Core {
+ static getInstance() {
+ if (!this.instance) {
+ this.instance = new Core();
+ }
+ return this.instance;
+ }
+
+ constructor() {
+ this.instance = null;
+ this.services = {
+ suite: {},
+ spec: {},
+ config: {},
+ expect: {},
+ log: {},
+ report: {}
+
+ };
+ this.events = {
+ suite: {},
+ spec: {},
+ task: {}
+ };
+ }
+
+ addService(name, service) {
+ let serviceObj = {};
+ if (!this.services[name]) {
+ this.services[name] = serviceObj;
+ } else {
+ serviceObj = this.services[name];
+ }
+ serviceObj[service.id] = service;
+ }
+
+ getDefaultService(name) {
+ return this.services[name].default;
+ }
+
+ getServices(name) {
+ return this.services[name];
+ }
+
+ registerEvent(serviceName, event) {
+ let eventObj = {};
+ if (!this.events[serviceName]) {
+ this.events[serviceName] = eventObj;
+ } else {
+ eventObj = this.events[serviceName];
+ }
+ eventObj[event.id] = event;
+ }
+
+ unRegisterEvent(serviceName, eventID) {
+ const eventObj = this.events[serviceName];
+ if (eventObj) {
+ delete eventObj[eventID];
+ }
+ }
+
+ subscribeEvent(serviceName, serviceObj) {
+ const eventObj = this.events[serviceName];
+ if (eventObj) {
+ for (const attr in eventObj) {
+ eventObj[attr]['subscribeEvent'](serviceObj);
+ }
+ }
+ }
+
+ async fireEvents(serviceName, eventName) {
+ const eventObj = this.events[serviceName];
+ if (!eventObj) {
+ return;
+ }
+ for (const attr in eventObj) {
+ await eventObj[attr][eventName]();
+ }
+ }
+
+ addToGlobal(apis) {
+ if (typeof globalThis !== 'undefined') {
+ for (let api in apis) {
+ globalThis[api] = apis[api];
+ }
+ }
+ for (const api in apis) {
+ this[api] = apis[api];
+ }
+ }
+
+ init() {
+ this.addService('suite', new SuiteService({id: 'default'}));
+ this.addService('spec', new SpecService({id: 'default'}));
+ this.addService('expect', new ExpectService({id: 'default'}));
+ this.addService('report', new ReportService({id: 'default'}));
+ this.addService('config', new ConfigService({id: 'default'}));
+ this.registerEvent('task', new TaskEvent({id: 'default', coreContext: this}));
+ this.registerEvent('suite', new SuiteEvent({id: 'default', coreContext: this}));
+ this.registerEvent('spec', new SpecEvent({id: 'default', coreContext: this}));
+ this.subscribeEvent('spec', this.getDefaultService('report'));
+ this.subscribeEvent('suite', this.getDefaultService('report'));
+ this.subscribeEvent('task', this.getDefaultService('report'));
+ const context = this;
+ for (const key in this.services) {
+ const serviceObj = this.services[key];
+ for (const serviceID in serviceObj) {
+ const service = serviceObj[serviceID];
+ service.init(context);
+
+ if (typeof service.apis !== 'function') {
+ continue;
+ }
+ const apis = service.apis();
+ if (apis) {
+ this.addToGlobal(apis);
+ }
+ }
+ }
+ }
+
+ execute(abilityDelegator) {
+ const suiteService = this.getDefaultService('suite');
+ const configService = this.getDefaultService('config');
+ if (configService['dryRun'] === 'true') {
+ (async function () {
+ await suiteService.dryRun(abilityDelegator);
+ })();
+ return;
+ }
+ setTimeout(() => {
+ suiteService.execute();
+ }, 10);
+ }
+}
+
+export default Core;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/event.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/event.js
new file mode 100644
index 0000000000000000000000000000000000000000..3be0211f01646c9c269c2425cbee82c87ac6d9ea
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/event.js
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class SpecEvent {
+ constructor(attr) {
+ this.id = attr.id;
+ this.coreContext = attr.context;
+ this.eventMonitors = [];
+ }
+
+ subscribeEvent(service) {
+ this.eventMonitors.push(service);
+ }
+
+ async specStart() {
+ for (const monitor of this.eventMonitors) {
+ await monitor['specStart']();
+ }
+ }
+
+ async specDone() {
+ for (const monitor of this.eventMonitors) {
+ await monitor['specDone']();
+ }
+ }
+}
+
+class SuiteEvent {
+ constructor(attr) {
+ this.id = attr.id;
+ this.suiteContext = attr.coreContext;
+ this.eventMonitors = [];
+ }
+
+ subscribeEvent(service) {
+ this.eventMonitors.push(service);
+ }
+
+ async suiteStart() {
+ for (const monitor of this.eventMonitors) {
+ await monitor['suiteStart']();
+ }
+ }
+
+ async suiteDone() {
+ for (const monitor of this.eventMonitors) {
+ await monitor['suiteDone']();
+ }
+ }
+}
+
+class TaskEvent {
+ constructor(attr) {
+ this.id = attr.id;
+ this.coreContext = attr.coreContext;
+ this.eventMonitors = [];
+ }
+
+ subscribeEvent(service) {
+ this.eventMonitors.push(service);
+ }
+
+ async taskStart() {
+ for (const monitor of this.eventMonitors) {
+ await monitor['taskStart']();
+ }
+ }
+
+ async taskDone() {
+ for (const monitor of this.eventMonitors) {
+ await monitor['taskDone']();
+ }
+ }
+
+ incorrectFormat() {
+ for (const monitor of this.eventMonitors) {
+ monitor['incorrectFormat']();
+ }
+ }
+
+ incorrectTestSuiteFormat() {
+ for (const monitor of this.eventMonitors) {
+ monitor.incorrectTestSuiteFormat();
+ }
+ }
+}
+
+export { SpecEvent, TaskEvent, SuiteEvent };
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/interface.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/interface.js
new file mode 100644
index 0000000000000000000000000000000000000000..1bf43509ac3f70f1275e1da79388e1511e72a3f9
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/interface.js
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Core from './core';
+
+const core = Core.getInstance();
+
+const describe = function (desc, func) {
+ return Reflect.has(core, 'describe') ? core.describe(desc, func) : (desc, func) => { };
+};
+const it = function (desc, filter, func) {
+ return Reflect.has(core, 'it') ? core.it(desc, filter, func) : (desc, filter, func) => { };
+};
+const beforeItSpecified = function (itDescs, func) {
+ return Reflect.has(core, 'beforeItSpecified') ? core.beforeItSpecified(itDescs, func) : (itDescs, func) => { };
+};
+
+const afterItSpecified = function (itDescs, func) {
+ return Reflect.has(core, 'afterItSpecified') ? core.afterItSpecified(itDescs, func) : (itDescs, func) => { };
+};
+const beforeEach = function (func) {
+ return Reflect.has(core, 'beforeEach') ? core.beforeEach(func) : (func) => { };
+};
+const afterEach = function (func) {
+ return Reflect.has(core, 'afterEach') ? core.afterEach(func) : (func) => { };
+};
+const beforeAll = function (func) {
+ return Reflect.has(core, 'beforeAll') ? core.beforeAll(func) : (func) => { };
+};
+const afterAll = function (func) {
+ return Reflect.has(core, 'afterAll') ? core.afterAll(func) : (func) => { };
+};
+const expect = function (actualValue) {
+ return Reflect.has(core, 'expect') ? core.expect(actualValue) : (actualValue) => { };
+};
+
+const xdescribe = function (desc, func) {
+ return Reflect.has(core, 'xdescribe') ? core.xdescribe(desc, func, null) : (desc, func, reason) => { };
+};
+xdescribe.reason = (reason) => {
+ return (desc, func) => {
+ return Reflect.has(core, 'xdescribe') ? core.xdescribe(desc, func, reason) : (desc, func, reason) => { };
+ };
+};
+const xit = function (desc, filter, func) {
+ return Reflect.has(core, 'xit') ? core.xit(desc, filter, func, null) : (desc, filter, func, reason) => { };
+};
+xit.reason = (reason) => {
+ return (desc, filter, func) => {
+ return Reflect.has(core, 'xit') ? core.xit(desc, filter, func, reason) : (desc, filter, func, reason) => { };
+ };
+};
+
+export {
+ describe, it, beforeAll, beforeEach, afterEach, afterAll, expect, beforeItSpecified, afterItSpecified, xdescribe, xit
+};
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module.json b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module.json
new file mode 100644
index 0000000000000000000000000000000000000000..b0e022bd13205c4c3310480d6732db4707193b3a
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module.json
@@ -0,0 +1,26 @@
+{
+ "app": {
+ "bundleName": "com.ohos.myapplication",
+ "debug": true,
+ "versionCode": 1000000,
+ "versionName": "1.0.0",
+ "minAPIVersion": 40100011,
+ "targetAPIVersion": 40100011,
+ "apiReleaseType": "Beta1",
+ "compileSdkVersion": "4.1.0.55",
+ "compileSdkType": "HarmonyOS",
+ "bundleType": "app"
+ },
+ "module": {
+ "name": "hypium",
+ "type": "har",
+ "deviceTypes": [
+ "default",
+ "tablet",
+ "tv",
+ "wearable",
+ "car"
+ ],
+ "installationFree": false
+ }
+}
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/ExpectExtend.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/ExpectExtend.js
new file mode 100644
index 0000000000000000000000000000000000000000..d10d15e6f9955c6d04610101f8766c951ee1a35d
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/ExpectExtend.js
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import assertNull from './assertNull';
+import assertClose from './assertClose';
+import assertContain from './assertContain';
+import assertLess from './assertLess';
+import assertLarger from './assertLarger';
+import assertFail from './assertFail';
+import assertUndefined from './assertUndefined';
+import assertFalse from './assertFalse';
+import assertInstanceOf from './assertInstanceOf';
+import assertThrowError from './assertThrowError';
+import assertLargerOrEqual from './assertLargerOrEqual'
+import assertLessOrEqual from './assertLessOrEqual'
+import assertNaN from './assertNaN'
+import assertNegUnlimited from './assertNegUnlimited'
+import assertPosUnlimited from './assertPosUnlimited'
+import assertDeepEquals from './deepEquals/assertDeepEquals'
+import assertPromiseIsPending from './assertPromiseIsPending';
+import assertPromiseIsRejected from './assertPromiseIsRejected';
+import assertPromiseIsRejectedWith from './assertPromiseIsRejectedWith';
+import assertPromiseIsRejectedWithError from './assertPromiseIsRejectedWithError';
+import assertPromiseIsResolved from './assertPromiseIsResolved';
+import assertPromiseIsResolvedWith from './assertPromiseIsResolvedWith';
+class ExpectExtend {
+ constructor(attr) {
+ this.id = attr.id;
+ this.matchers = {};
+ }
+
+ extendsMatchers() {
+ this.matchers.assertNull = assertNull;
+ this.matchers.assertClose = assertClose;
+ this.matchers.assertContain = assertContain;
+ this.matchers.assertLess = assertLess;
+ this.matchers.assertLarger = assertLarger;
+ this.matchers.assertFail = assertFail;
+ this.matchers.assertUndefined = assertUndefined;
+ this.matchers.assertFalse = assertFalse;
+ this.matchers.assertInstanceOf = assertInstanceOf;
+ this.matchers.assertThrowError = assertThrowError;
+ this.matchers.assertLargerOrEqual = assertLargerOrEqual;
+ this.matchers.assertLessOrEqual = assertLessOrEqual;
+ this.matchers.assertNaN = assertNaN;
+ this.matchers.assertNegUnlimited = assertNegUnlimited;
+ this.matchers.assertPosUnlimited = assertPosUnlimited;
+ this.matchers.assertDeepEquals = assertDeepEquals;
+ this.matchers.assertPromiseIsPending = assertPromiseIsPending;
+ this.matchers.assertPromiseIsRejected = assertPromiseIsRejected;
+ this.matchers.assertPromiseIsRejectedWith = assertPromiseIsRejectedWith;
+ this.matchers.assertPromiseIsRejectedWithError = assertPromiseIsRejectedWithError;
+ this.matchers.assertPromiseIsResolved = assertPromiseIsResolved;
+ this.matchers.assertPromiseIsResolvedWith = assertPromiseIsResolvedWith;
+ }
+
+ init(coreContext) {
+ this.coreContext = coreContext;
+ this.extendsMatchers();
+ const expectService = this.coreContext.getDefaultService('expect');
+ expectService.addMatchers(this.matchers);
+ }
+
+ apis() {
+ return {
+ 'expect': function (actualValue) {
+ return this.coreContext.getDefaultService('expect').expect(actualValue);
+ }
+ };
+ }
+}
+
+export default ExpectExtend;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertClose.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertClose.js
new file mode 100644
index 0000000000000000000000000000000000000000..7e692bd25f1c026640978a042a9c9f64b0e8d5d3
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertClose.js
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertClose(actualValue, expected) {
+ if (actualValue === null && expected[0] === null) {
+ throw new Error('actualValue and expected can not be both null!!!');
+ }
+ let result;
+ let diff = Math.abs(expected[0] - actualValue);
+ let actualAbs = Math.abs(actualValue);
+ if ((actualAbs - 0) === 0) {
+ if ((diff - 0) === 0) {
+ result = true;
+ } else {
+ result = false;
+ }
+ } else if (diff / actualAbs < expected[1]) {
+ result = true;
+ } else {
+ result = false;
+ }
+ return {
+ pass: result,
+ message: '|' + actualValue + ' - ' + expected[0] + '|/' + actualValue + ' is not less than ' + expected[1]
+ };
+}
+
+export default assertClose;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertContain.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertContain.js
new file mode 100644
index 0000000000000000000000000000000000000000..7fba0d9755503e5e926f6c1a4e425e0d1cf47570
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertContain.js
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertContain(actualValue, expect) {
+ let result = false;
+ if (Object.prototype.toString.call(actualValue).indexOf('Array')) {
+ for (let i in actualValue) {
+ if (actualValue[i] == expect[0]) {
+ result = true;
+ }
+ }
+ }
+ let type = Object.prototype.toString.call(actualValue);
+ if (type === '[object String]') {
+ result = actualValue.indexOf(expect[0]) >= 0;
+ }
+ return {
+ pass: result,
+ message: 'expect false, ' + actualValue + ' do not have ' + expect[0]
+ };
+}
+
+export default assertContain;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertFail.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertFail.js
new file mode 100644
index 0000000000000000000000000000000000000000..8ab4ac5caef712c75c4eac49dfbbb91d33669d9a
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertFail.js
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertFail() {
+ return {
+ pass: false,
+ message: 'fail '
+ };
+}
+
+export default assertFail;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertFalse.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertFalse.js
new file mode 100644
index 0000000000000000000000000000000000000000..c5008e94f4b2ce13ed35b604811793c76b542347
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertFalse.js
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertFalse(actualValue) {
+ return {
+ pass: (actualValue) === false,
+ message: 'expect false, actualValue is ' + actualValue
+ };
+}
+
+export default assertFalse;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertInstanceOf.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertInstanceOf.js
new file mode 100644
index 0000000000000000000000000000000000000000..1e11b93f7251c67f5455c5007cd7be268aa53b32
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertInstanceOf.js
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertInstanceOf(actualValue, expected) {
+ if (Object.prototype.toString.call(actualValue) == '[object ' + expected[0] + ']') {
+ return {
+ pass: true
+ };
+ } else {
+ return {
+ pass: false,
+ message: actualValue + ' is ' + Object.prototype.toString.call(actualValue) + 'not ' + expected[0]
+ };
+ }
+}
+
+export default assertInstanceOf;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertLarger.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertLarger.js
new file mode 100644
index 0000000000000000000000000000000000000000..a74f4a8cedaf3add9c2dc2d3799081a83198732f
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertLarger.js
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertLarger(actualValue, expected) {
+ return {
+ pass: (actualValue) > expected[0],
+ message: (actualValue) + ' is not larger than ' + expected[0]
+ };
+}
+
+export default assertLarger;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertLargerOrEqual.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertLargerOrEqual.js
new file mode 100644
index 0000000000000000000000000000000000000000..e847e6c217364b7f69c173c66fb98d10efc45ef1
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertLargerOrEqual.js
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertLargerOrEqual(actualValue, expected) {
+ return {
+ pass: (actualValue) >= expected[0],
+ message: (actualValue) + ' is not larger than ' + expected[0]
+ };
+}
+
+export default assertLargerOrEqual;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertLess.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertLess.js
new file mode 100644
index 0000000000000000000000000000000000000000..17e84b0abaeb20804048a5a15c19e0603634846d
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertLess.js
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertLess(actualValue, expected) {
+ return {
+ pass: (actualValue) < expected[0],
+ message: (actualValue) + ' is not less than ' + expected[0]
+ };
+}
+
+export default assertLess;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertLessOrEqual.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertLessOrEqual.js
new file mode 100644
index 0000000000000000000000000000000000000000..f754f97ffa9d24e7852efe2423a1dd35d448af82
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertLessOrEqual.js
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertLessOrEqual(actualValue, expected) {
+ return {
+ pass: (actualValue) <= expected[0],
+ message: (actualValue) + ' is not less than ' + expected[0]
+ };
+}
+
+export default assertLessOrEqual;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertNaN.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertNaN.js
new file mode 100644
index 0000000000000000000000000000000000000000..8d45d6a93b86c5ed325a68b32ff014835993a58e
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertNaN.js
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertNaN(actualValue) {
+ return {
+ pass: actualValue !== actualValue,
+ message: 'expect NaN, actualValue is ' + actualValue
+ };
+}
+
+export default assertNaN;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertNegUnlimited.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertNegUnlimited.js
new file mode 100644
index 0000000000000000000000000000000000000000..ceac555afc826e057970e6cfe9c73b322c672aa2
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertNegUnlimited.js
@@ -0,0 +1,23 @@
+/*
+* Copyright (c) 2022 Huawei Device Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+function assertNegUnlimited(actualValue) {
+ return {
+ pass: actualValue === Number.NEGATIVE_INFINITY,
+ message: 'Expected actualValue not to be -Infinity. actualValue is,' + actualValue
+ };
+}
+
+export default assertNegUnlimited;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertNull.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertNull.js
new file mode 100644
index 0000000000000000000000000000000000000000..53a7bad827323a98d3302a4e7eea679551b459c5
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertNull.js
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertNull(actualValue) {
+ return {
+ pass: (actualValue) === null,
+ message: 'expect null, actualValue is ' + (actualValue)
+ };
+}
+
+export default assertNull;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertPosUnlimited.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertPosUnlimited.js
new file mode 100644
index 0000000000000000000000000000000000000000..6e68c0e2b6c499f4dc3dd56c13e9ea1073a3c54c
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertPosUnlimited.js
@@ -0,0 +1,23 @@
+/*
+* Copyright (c) 2022 Huawei Device Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+function assertPosUnlimited(actualValue) {
+ return {
+ pass: actualValue === Number.POSITIVE_INFINITY,
+ message: 'Expected actualValue is POSITIVE_INFINITY. actualValue is,' + actualValue
+ };
+}
+
+export default assertPosUnlimited;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsPending.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsPending.js
new file mode 100644
index 0000000000000000000000000000000000000000..7e2ca2ce14d50c39554fc1157d6d4eb9329d5c39
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsPending.js
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import isPromiseLike from './isPromiseLike';
+
+function assertPromiseIsPending(actualPromise) {
+ if (!isPromiseLike(actualPromise)) {
+ return Promise.reject().then(function () {
+ }, function () {
+ return {pass: false, message: 'Expected not be called on a promise.'};
+ });
+ }
+ const helper = {};
+ return Promise.race([actualPromise, Promise.resolve(helper)]).then(
+ function (got) {
+ return helper === got ? {pass: true, message: 'actualValue is isPending'}
+ : {
+ pass: false,
+ message: 'expect isPending, actualValue is resolve'
+ };
+ },
+ function () {
+ return {
+ pass: false
+ , message: 'expect isPending, actualValue is reject'
+ };
+ });
+}
+
+export default assertPromiseIsPending;
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsRejected.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsRejected.js
new file mode 100644
index 0000000000000000000000000000000000000000..380075a369a84d6856e7f2db366f704e04302a8d
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsRejected.js
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import isPromiseLike from './isPromiseLike';
+
+function assertPromiseIsRejected(actualPromise) {
+ if (!isPromiseLike(actualPromise)) {
+ return Promise.reject().then(function () {
+ }, function () {
+ return {pass: false, message: 'Expected not be called on a promise.'};
+ });
+ }
+ return actualPromise.then(
+ function (got) {
+ return {
+ pass: false,
+ message: 'expect isRejected, but actualValue is resolve'
+ };
+ },
+ function () {
+ return {pass: true, message: 'actualValue is isRejected'};
+ }
+ );
+}
+
+export default assertPromiseIsRejected;
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsRejectedWith.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsRejectedWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..8179589d5580f9c305d2200b4b197d64ac9d53ae
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsRejectedWith.js
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import isPromiseLike from './isPromiseLike';
+
+function assertPromiseIsRejectedWith(actualPromise, expectedValue) {
+
+ if (!isPromiseLike(actualPromise)) {
+ return Promise.reject().then(function () {
+ }, function () {
+ return {pass: false, message: 'Expected not be called on a promise.'};
+ });
+ }
+
+ function tips(passed) {
+ return ('Expected a promise ' + (passed ? 'not ' : '') +
+ 'to be rejected with ' + JSON.stringify(expectedValue[0]));
+ }
+
+ return actualPromise.then(
+ function (got) {
+ return {
+ pass: false,
+ message: tips(false) + ' but actualValue is resolve'
+ };
+ },
+ function (actualValue) {
+ if (JSON.stringify(actualValue) == JSON.stringify(expectedValue[0])) {
+ return {
+ pass: true,
+ message: 'actualValue was rejected with ' + JSON.stringify(actualValue) + '.'
+ };
+ } else {
+ return {
+ pass: false,
+ message: tips(false) + ' but it was rejected with ' + JSON.stringify(actualValue) + '.'
+ };
+ }
+ }
+ );
+}
+
+export default assertPromiseIsRejectedWith;
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsRejectedWithError.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsRejectedWithError.js
new file mode 100644
index 0000000000000000000000000000000000000000..291af8e5032b7bcd9bcb3e996a39a4fa8ba23157
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsRejectedWithError.js
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import isPromiseLike from './isPromiseLike';
+
+function assertPromiseIsRejectedWithError(actualPromise, expectedValue) {
+ if (!isPromiseLike(actualPromise)) {
+ return Promise.reject().then(function () {
+ }, function () {
+ return {pass: false, message: 'Expected not be called on a promise.'};
+ });
+ }
+ return actualPromise.then(
+ function (got) {
+ return {
+ pass: false,
+ message: 'Expected a promise to be rejected but actualValue is resolve'
+ };
+ },
+ function (actualValue) {
+ return matchError(actualValue, expectedValue);
+ }
+ );
+
+}
+
+function matchError(actualValue, expectedValue) {
+ if (expectedValue.length == 1 && typeof expectedValue[0] === 'function') {
+ if (expectedValue[0].name === actualValue.__proto__.name) {
+ return {pass: true, message: 'actual error type is ' + actualValue.name + '.'};
+ }
+ return {pass: false, message: `except error type is ${expectedValue[0].name},but actual is ${actualValue.name}.`};
+ }
+
+ if (expectedValue.length == 1 && typeof expectedValue[0] === 'string') {
+ if (expectedValue[0] === actualValue.message) {
+ return {pass: true, message: `actual error message is ${actualValue.message}.`};
+ }
+ return {pass: false, message: `except error message ${expectedValue[0]},but actual is ${actualValue.message}.`};
+ }
+
+ if (expectedValue.length == 1) {
+ return {pass: false, message: 'When only one parameter, it should be error type or error message.'};
+ }
+
+ if (expectedValue.length == 2 && typeof expectedValue[0] === 'function' && expectedValue[0].name === actualValue.name) {
+ if (typeof expectedValue[1] === 'string' && actualValue.message === expectedValue[1]) {
+ return {pass: true, message: 'actual error message is ' + actualValue.message + '.'};
+ }
+ return {pass: false, message: `except error message is ${expectedValue[1]},but actual is ${actualValue.message}.`};
+ }
+
+ if (expectedValue.length == 2 && typeof expectedValue[0] === 'function' && expectedValue[0].name !== actualValue.name) {
+ if (typeof expectedValue[1] === 'string' && actualValue.message === expectedValue[1]) {
+ return {pass: false, message: `except error type is ${expectedValue[0].name},but actual is ${actualValue.name}.`};
+ }
+ return {pass: false, message: 'except error type and message are incorrect.'};
+ }
+ if (expectedValue.length > 2) {
+ return {pass: false, message: 'Up to two parameters are supported.'};
+ }
+}
+
+export default assertPromiseIsRejectedWithError;
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsResolved.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsResolved.js
new file mode 100644
index 0000000000000000000000000000000000000000..86f559c32873f27b95d635452d760029de0ed657
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsResolved.js
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import isPromiseLike from './isPromiseLike';
+
+function assertPromiseIsResolved(actualPromise) {
+ if (!isPromiseLike(actualPromise)) {
+ return Promise.reject().then(function () {
+ }, function () {
+ return {pass: false, message: 'Expected not be called on a promise.'};
+ });
+ }
+
+ return actualPromise.then(
+ function (got) {
+ return {pass: true, message: 'actualValue is isResolved'};
+ },
+ function (rej) {
+ return {
+ pass: false,
+ message: 'Expected a promise to be resolved but it was ' +
+ 'rejected with ' + JSON.stringify(rej) + '.'
+ };
+ }
+ );
+}
+
+export default assertPromiseIsResolved;
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsResolvedWith.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsResolvedWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..c6f0ef68fde5b04a589a9fa3c6e2ab2b39acf4d3
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsResolvedWith.js
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import isPromiseLike from './isPromiseLike';
+
+function assertPromiseIsResolvedWith(actualPromise, expectedValue) {
+ if (!isPromiseLike(actualPromise)) {
+ return Promise.reject().then(function () {
+ }, function () {
+ return {pass: false, message: 'Expected not be called on a promise.'};
+ });
+ }
+
+ function tips(passed) {
+ return (
+ 'Expected a promise ' + (passed ? 'not ' : '') +
+ 'to be resolved with ' + JSON.stringify(expectedValue[0]));
+ }
+
+ return actualPromise.then(
+ function (got) {
+ if (JSON.stringify(got) == JSON.stringify(expectedValue[0])) {
+ return {
+ pass: true,
+ message: 'actualValue was resolved with ' + JSON.stringify(got) + '.'
+ };
+ }
+ return {
+ pass: false,
+ message: tips(false) + ' but it was resolved with ' +
+ JSON.stringify(got) + '.'
+ };
+ },
+ function (rej) {
+ return {
+ pass: false,
+ message: tips(false) + ' but it was rejected with ' + JSON.stringify(rej) + '.'
+ };
+ }
+ );
+}
+
+export default assertPromiseIsResolvedWith;
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertThrowError.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertThrowError.js
new file mode 100644
index 0000000000000000000000000000000000000000..c4544a7f825bcecd1a07d5e98dd9a7b99d237278
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertThrowError.js
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertThrowError(actualValue, expected) {
+ let result = false;
+ let message = '';
+ let err;
+ if (typeof actualValue !== 'function') {
+ throw new Error('actualValue is not a function');
+ }
+ try {
+ actualValue();
+ return {
+ pass: result,
+ message: ' An error is not thrown while it is expected!'
+ };
+ } catch (e) {
+ err = e;
+ }
+ if (err instanceof Error) {
+ let type = typeof expected[0];
+ if (type === 'function') {
+ result = err.constructor.name === expected[0].name;
+ message = 'expected throw failed , ' + err.constructor.name + ' is not ' + expected[0].name;
+ }else if(type === 'string'){
+ result = err.message.includes(expected[0]);
+ message = 'expected throw failed , ' + err.message + ' is not ' + expected[0];
+ }
+ }
+ return {
+ pass: result,
+ message: message
+ };
+}
+
+export default assertThrowError;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertUndefined.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertUndefined.js
new file mode 100644
index 0000000000000000000000000000000000000000..61f092d715dd1630297518b59ff13ef0940991e1
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/assertUndefined.js
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertUndefined(actualValue) {
+ return {
+ pass: undefined === (actualValue),
+ message: 'expect Undefined, actualValue is ' + (actualValue)
+ };
+}
+
+export default assertUndefined;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/deepEquals/DeepTypeUtils.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/deepEquals/DeepTypeUtils.js
new file mode 100644
index 0000000000000000000000000000000000000000..916824d9cb77a75d1fb35bc3500d7598bfc73e80
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/deepEquals/DeepTypeUtils.js
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class DeepTypeUtils {
+ static getType(value) {
+ return Object.prototype.toString.apply(value);
+ }
+ static isA(typeName, value) {
+ return this.getType(value) === '[object ' + typeName + ']';
+ }
+ static isAsymmetricEqualityTester(obj) {
+ return obj ? this.isA('Function', obj.asymmetricMatch) : false;
+ }
+
+ /**
+ * 是否是function
+ * @param value
+ */
+ static isFunction(value) {
+ return this.isA('Function', value);
+ }
+
+ /**
+ * 是否是undefined
+ * @param obj
+ */
+ static isUndefined(obj) {
+ return obj === void 0;
+ }
+
+ /**
+ * 是否是Node
+ * @param obj
+ */
+ static isDomNode(obj) {
+ return obj !== null &&
+ typeof obj === 'object' &&
+ typeof obj.nodeType === 'number' &&
+ typeof obj.nodeName === 'string';
+ }
+
+ /**
+ * 是否是promise对象
+ * @param obj
+ */
+ static isPromise(obj) {
+ return !!obj && obj.constructor === Promise;
+ };
+ /**
+ * 是否是map对象
+ * @param obj
+ */
+ static isMap(obj) {
+ return (
+ obj !== null &&
+ typeof obj !== 'undefined' &&
+ obj.constructor === Map
+ );
+ }
+
+ /**
+ * 是否是set对象
+ * @param obj 对象
+ */
+ static isSet(obj) {
+ return (
+ obj !== null &&
+ typeof obj !== 'undefined' &&
+ obj.constructor === Set
+ );
+ }
+
+ /**
+ * 对象是否有key属性
+ * @param obj 对象
+ * @param key 对象属性名称
+ */
+ static has(obj, key) {
+ return Object.prototype.hasOwnProperty.call(obj, key);
+ }
+
+ /**
+ * 获取对象的自有属性
+ * @param obj 对象
+ * @param isArray 是否是数组,[object Array]
+ */
+ static keys(obj, isArray) {
+ const extraKeys = [];
+ // 获取对象所有属性
+ const allKeys = this.getAllKeys(obj);
+ if (!isArray) {
+ return allKeys;
+ }
+ if (allKeys.length === 0) {
+ return allKeys;
+ }
+ for (const k of allKeys) {
+ if (typeof k === 'symbol' || !/^[0-9]+$/.test(k)) {
+ extraKeys.push(k);
+ }
+ }
+ return extraKeys;
+ }
+
+ /**
+ * 获取obj对象的所有属性
+ * @param obj obj对象
+ */
+ static getAllKeys(obj) {
+ const keys = [];
+ for (let key in obj) {
+ if (this.has(obj, key)) {
+ keys.push(key);
+ }
+ }
+ const symbols = Object.getOwnPropertySymbols(obj);
+ for (const sym of symbols) {
+ // obj.propertyIsEnumerable(sym)
+ if (Object.prototype.propertyIsEnumerable.call(obj, sym)) {
+ keys.push(sym);
+ }
+ }
+ return keys;
+ }
+
+}
+export default DeepTypeUtils;
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/deepEquals/assertDeepEquals.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/deepEquals/assertDeepEquals.js
new file mode 100644
index 0000000000000000000000000000000000000000..60de33f7e1afdcfaf205c8c56484ef33dfda8160
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/deepEquals/assertDeepEquals.js
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import DeepTypeUtils from './DeepTypeUtils';
+function assertDeepEquals(actualValue, expected) {
+ let result = eq(actualValue, expected[0])
+ let msg = logMsg(actualValue, expected[0]);
+ return {
+ pass: result,
+ message: msg
+ };
+}
+
+/**
+ * 获取失败显示日志
+ * @param actualValue 实际对象
+ * @param expected 期待比较对象
+ */
+function logMsg(actualValue, expected) {
+ // 获取a的对象名称
+ const aClassName = Object.prototype.toString.call(actualValue);
+ const bClassName = Object.prototype.toString.call(expected);
+ let actualMsg;
+ let expectMsg;
+ if (aClassName == '[object Function]') {
+ actualMsg = 'actualValue Function';
+ } else if (aClassName == '[object Promise]') {
+ actualMsg = 'actualValue Promise';
+ } else if (aClassName == '[object Set]' || aClassName == '[object Map]') {
+ actualMsg = JSON.stringify(Array.from(actualValue));
+ } else if (aClassName == '[object RegExp]') {
+ actualMsg = JSON.stringify(actualValue.source.replace('\\',''));
+ } else if (aClassName == '[object BigInt]') {
+ actualMsg = actualValue;
+ } else if (aClassName == '[object Error]') {
+ actualMsg = actualValue.message;
+ } else if (aClassName == '[object ArrayBuffer]') {
+ actualMsg = actualValue.byteLength;
+ }
+ else {
+ actualMsg = JSON.stringify(actualValue);
+ }
+ if (bClassName == '[object Function]') {
+ expectMsg = 'expected Function';
+ } else if (bClassName == '[object Promise]') {
+ expectMsg = 'expected Promise';
+ } else if (bClassName == '[object Set]' || bClassName == '[object Map]') {
+ expectMsg = JSON.stringify(Array.from(expected));
+ } else if (bClassName == '[object RegExp]') {
+ expectMsg = JSON.stringify(expected.source.replace('\\',''));
+ } else if (bClassName == '[object BigInt]') {
+ expectMsg = expected;
+ } else if (bClassName == '[object Error]') {
+ expectMsg = expected.message;
+ } else if (bClassName == '[object ArrayBuffer]') {
+ expectMsg = expected.byteLength;
+ }
+ else {
+ expectMsg = JSON.stringify(expected);
+ }
+ return actualMsg + ' is not deep equal ' + expectMsg;
+}
+
+function eq(a, b) {
+ let result = true;
+
+ if (a === b) {
+ result = a !== 0 || 1 / a === 1 / b;
+ return result;
+ }
+
+ if (a === null || b === null) {
+ result = a === b;
+ return result;
+ }
+ // 获取a的对象名称
+ const aClassName = Object.prototype.toString.call(a);
+ const bClassName = Object.prototype.toString.call(b);
+ // 不同类型不同对象
+ if (aClassName !== bClassName) {
+ return false;
+ }
+ if (aClassName === '[object String]' || aClassName === '[object Number]' || aClassName === '[object Date]' ||
+ aClassName === '[object Boolean]' || aClassName === '[object ArrayBuffer]' ||
+ aClassName === '[object RegExp]' || aClassName === '[object Error]') {
+ result = isEqualSampleObj(a, b);
+ return result;
+ }
+
+ if (typeof a !== 'object' || typeof b !== 'object') {
+ return false;
+ }
+
+ if (DeepTypeUtils.isDomNode(a) || DeepTypeUtils.isPromise(a) || DeepTypeUtils.isFunction(a)) {
+ result = isEqualNodeOrPromiseOrFunction(a, b);
+ return result;
+ }
+
+ if (aClassName === '[object Array]' || aClassName === '[object Map]' || aClassName === '[object Set]') {
+ result = isEqualCollection(a, b);
+ return result;
+ }
+
+ result = isEqualObj(a, b);
+ return result;
+}
+
+function isEqualNodeOrPromiseOrFunction(a, b) {
+ let equalNodeOrPromiseOrFunction = true;
+ if (DeepTypeUtils.isDomNode(a) && DeepTypeUtils.isDomNode(b)) {
+ const aIsDomNode = DeepTypeUtils.isDomNode(a);
+ const bIsDomNode = DeepTypeUtils.isDomNode(b);
+ if (aIsDomNode && bIsDomNode) {
+ // At first try to use DOM3 method isEqualNode
+ equalNodeOrPromiseOrFunction = a.isEqualNode(b);
+ return equalNodeOrPromiseOrFunction;
+ }
+ if (aIsDomNode || bIsDomNode) {
+ equalNodeOrPromiseOrFunction = false;
+ return false;
+ }
+ }
+
+ if (DeepTypeUtils.isPromise(a) && DeepTypeUtils.isPromise(b)) {
+ const aIsPromise = DeepTypeUtils.isPromise(a);
+ const bIsPromise = DeepTypeUtils.isPromise(b);
+ // 俩个Promise对象
+ if (aIsPromise && bIsPromise) {
+ equalNodeOrPromiseOrFunction = a === b;
+ return a === b;
+ }
+ }
+ if (DeepTypeUtils.isFunction(a) && DeepTypeUtils.isFunction(b)) {
+ // 俩个函数对象
+ const aCtor = a.constructor,
+ bCtor = b.constructor;
+ if (
+ aCtor !== bCtor &&
+ DeepTypeUtils.isFunction(aCtor) &&
+ DeepTypeUtils.isFunction(bCtor) &&
+ a instanceof aCtor &&
+ b instanceof bCtor &&
+ !(aCtor instanceof aCtor && bCtor instanceof bCtor)
+ ) {
+ equalNodeOrPromiseOrFunction = false;
+ return false;
+ }
+ }
+ return equalNodeOrPromiseOrFunction;
+}
+
+function isEqualCollection(a, b) {
+ let equalCollection = true;
+ // 获取a的对象名称
+ const aClassName = Object.prototype.toString.call(a);
+ const bClassName = Object.prototype.toString.call(b);
+ // 都是数组
+ if (aClassName === '[object Array]') {
+ equalCollection = isEqualArray(a, b);
+ return equalCollection;
+ }
+
+ // 都是Map
+ if (DeepTypeUtils.isMap(a) && DeepTypeUtils.isMap(b)) {
+ equalCollection = isEqualMap(a, b);
+ return equalCollection;
+ }
+
+ // 都是Set
+ if (DeepTypeUtils.isSet(a) && DeepTypeUtils.isSet(b)) {
+ equalCollection = isEqualSet(a, b);
+ return equalCollection;
+ }
+
+ return true;
+}
+
+function isEqualSampleObj(a, b) {
+ let equalSampleObj = true;
+ const aClassName = Object.prototype.toString.call(a);
+ const bClassName = Object.prototype.toString.call(b);
+ // 俩个string对象
+ if (aClassName === '[object String]') {
+ equalSampleObj = a === String(b);
+ return equalSampleObj;
+ }
+ // 俩个Number对象
+ if (aClassName === '[object Number]') {
+ equalSampleObj = a !== +a ? b !== +b : a === 0 && b === 0 ? 1 / a === 1 / b : a === +b;
+ return equalSampleObj;
+ }
+
+ // 俩个Date对象/ boolean对象
+ if (aClassName === '[object Date]' || aClassName === '[object Boolean]') {
+ equalSampleObj = +a === +b;
+ return equalSampleObj;
+ }
+
+ // 俩个ArrayBuffer
+ if (aClassName === '[object ArrayBuffer]') {
+ equalSampleObj = eq(new Uint8Array(a), new Uint8Array(b));
+ return equalSampleObj;
+ }
+
+ // 正则表达式
+ if (aClassName === '[object RegExp]') {
+ return (
+ a.source === b.source &&
+ a.global === b.global &&
+ a.multiline === b.multiline &&
+ a.ignoreCase === b.ignoreCase
+ );
+ }
+
+ if (a instanceof Error && b instanceof Error) {
+ equalSampleObj = a.message === b.message;
+ return equalSampleObj;
+ }
+
+ return equalSampleObj;
+}
+
+function isEqualObj(a, b) {
+ let equalObj = true;
+ const aClassName = Object.prototype.toString.call(a);
+ const bClassName = Object.prototype.toString.call(b);
+ const aKeys = DeepTypeUtils.keys(a, aClassName === '[object Array]');
+ let size = aKeys.length;
+
+ // 俩个对象属性长度不一致, 俩对象不相同
+ if (DeepTypeUtils.keys(b, bClassName === '[object Array]').length !== size) {
+ return false;
+ }
+
+ // 俩对象属性数量相同, 递归比较每个属性值得值
+ for (const key of aKeys) {
+ // b 没有 key 属性
+ if (!DeepTypeUtils.has(b, key)) {
+ equalObj = false;
+ continue;
+ }
+ if (!eq(a[key], b[key])) {
+ equalObj = false;
+ }
+ }
+ return equalObj;
+}
+
+function isEqualArray(a, b) {
+ let equalArray = true;
+ const aLength = a.length;
+ const bLength = b.length;
+ if (aLength !== bLength) {
+ // 数组长度不同,不是同一个对象
+ return false;
+ }
+ for (let i = 0; i < aLength || i < bLength; i++) {
+ // 递归每一个元素是否相同
+ equalArray = eq(i < aLength ? a[i] : void 0, i < bLength ? b[i] : void 0) && equalArray;
+ }
+ return equalArray;
+}
+
+function isEqualMap(a, b) {
+ let equalMap = true;
+ if (a.size !== b.size) {
+ return false;
+ }
+ const keysA = [];
+ const keysB = [];
+ a.forEach(function(valueA, keyA) {
+ keysA.push(keyA);
+ });
+ b.forEach(function(valueB, keyB) {
+ keysB.push(keyB);
+ });
+ const mapKeys = [keysA, keysB];
+ const cmpKeys = [keysB, keysA];
+ for (let i = 0; equalMap && i < mapKeys.length; i++) {
+ const mapIter = mapKeys[i];
+ const cmpIter = cmpKeys[i];
+
+ for (let j = 0; equalMap && j < mapIter.length; j++) {
+ const mapKey = mapIter[j];
+ const cmpKey = cmpIter[j];
+ const mapValueA = a.get(mapKey);
+ let mapValueB;
+ if (eq(mapKey, cmpKey)) {
+ mapValueB = b.get(cmpKey);
+ } else {
+ mapValueB = b.get(mapKey);
+ }
+ equalMap = eq(mapValueA, mapValueB);
+ }
+ }
+ return equalMap;
+}
+
+function isEqualSet(a, b) {
+ let equalSet = true;
+ if (a.size !== b.size) {
+ return false;
+ }
+ const valuesA = [];
+ a.forEach(function(valueA) {
+ valuesA.push(valueA);
+ });
+ const valuesB = [];
+ b.forEach(function(valueB) {
+ valuesB.push(valueB);
+ });
+ const setPairs = [[valuesA, valuesB], [valuesB, valuesA]];
+ for (let i = 0; equalSet && i < setPairs.length; i++) {
+ const baseValues = setPairs[i][0];
+ const otherValues = setPairs[i][1];
+ for (const baseValue of baseValues) {
+ let found = false;
+ for (let j = 0; !found && j < otherValues.length; j++) {
+ const otherValue = otherValues[j];
+ // 深度比较对象
+ found = eq(baseValue, otherValue);
+ }
+ equalSet = equalSet && found;
+ }
+ }
+ return equalSet;
+}
+
+export default assertDeepEquals;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/isPromiseLike.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/isPromiseLike.js
new file mode 100644
index 0000000000000000000000000000000000000000..015ab19a2a0c4872d7cb490b61f8e1dd6a8ac90b
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/assert/isPromiseLike.js
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function isPromiseLike(obj) {
+ return !!obj && isFunction_(obj.then);
+}
+
+function isFunction_(value) {
+ return isA_('Function', value);
+}
+
+function isA_(typeName, value) {
+ return getType_(value) === '[object ' + typeName + ']';
+}
+
+function getType_(value) {
+ return Object.prototype.toString.apply(value);
+}
+
+export default isPromiseLike;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/config/DataDriver.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/config/DataDriver.js
new file mode 100644
index 0000000000000000000000000000000000000000..639dffc9cdb912f1f33a6ccb61868c9ed7c695bf
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/config/DataDriver.js
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+const SUITES_KEY = 'suites';
+const SPECS_KEY = 'items';
+const DESCRIBE_KEY = 'describe';
+const IT_KEY = 'it';
+const PARAMS_KEY = 'params';
+const STRESS_KEY = 'stress';
+
+class ObjectUtils {
+ static get(object, name, defaultValue) {
+ let result = defaultValue;
+ for (const key in object) {
+ if (key === name) {
+ return object[key];
+ }
+ }
+ return result;
+ }
+
+ static has(object, key) {
+ return Object.prototype.hasOwnProperty.call(object, key);
+ }
+}
+
+class DataDriver {
+ constructor(attr) {
+ this.id = 'dataDriver';
+ this.data = attr.data || {};
+ }
+
+ init(coreContext) {
+ this.coreContext = coreContext;
+ this.suiteService = this.coreContext.getDefaultService('suite');
+ this.specService = this.coreContext.getDefaultService('spec');
+ }
+
+ getSpecParams() {
+ let specParams = [];
+ let suiteDesc = this.suiteService.getCurrentRunningSuite().description;
+ let specDesc = this.specService.getCurrentRunningSpec().description;
+ let suites = ObjectUtils.get(this.data, SUITES_KEY, []);
+ for (const suiteItem of suites) {
+ let describeValue = ObjectUtils.get(suiteItem, DESCRIBE_KEY, '');
+ if (ObjectUtils.has(suiteItem, DESCRIBE_KEY) && (typeof describeValue === 'object') && describeValue.constructor === Array && describeValue.includes(suiteDesc)) {
+ let specs = ObjectUtils.get(suiteItem, SPECS_KEY, []);
+ for (const specItem of specs) {
+ if (ObjectUtils.has(specItem, IT_KEY) && ObjectUtils.get(specItem, IT_KEY) === specDesc) {
+ return ObjectUtils.get(specItem, PARAMS_KEY, specParams);
+ }
+ }
+ }
+ }
+ return specParams;
+ }
+
+ getSuiteParams() {
+ let suiteParams = {};
+ let suiteDesc = this.suiteService.getCurrentRunningSuite().description;
+ let suites = ObjectUtils.get(this.data, SUITES_KEY, []);
+ for (const suiteItem of suites) {
+ let describeValue = ObjectUtils.get(suiteItem, DESCRIBE_KEY, []);
+ if (ObjectUtils.has(suiteItem, DESCRIBE_KEY) && (typeof describeValue === 'object') && describeValue.constructor === Array && describeValue.includes(suiteDesc)) {
+ suiteParams = Object.assign({}, suiteParams, ObjectUtils.get(suiteItem, PARAMS_KEY, suiteParams));
+ }
+ }
+ return suiteParams;
+ }
+
+ getSpecStress(specDesc) {
+ let stress = 1;
+ let suiteDesc = this.suiteService.getCurrentRunningSuite().description;
+ let suites = ObjectUtils.get(this.data, SUITES_KEY, []);
+ for (const suiteItem of suites) {
+ let describeValue = ObjectUtils.get(suiteItem, DESCRIBE_KEY, '');
+ if (ObjectUtils.has(suiteItem, DESCRIBE_KEY) && (typeof describeValue === 'object') && describeValue.constructor === Array && describeValue.includes(suiteDesc)) {
+ let specs = ObjectUtils.get(suiteItem, SPECS_KEY, []);
+ for (const specItem of specs) {
+ if (ObjectUtils.has(specItem, IT_KEY) && ObjectUtils.get(specItem, IT_KEY) === specDesc) {
+ let tempStress = ObjectUtils.get(specItem, STRESS_KEY, stress);
+ return (Number.isInteger(tempStress) && tempStress >= 1) ? tempStress : stress;
+ }
+ }
+ }
+ }
+ return stress;
+ }
+
+ getSuiteStress(suiteDesc) {
+ let stress = 1;
+ let suites = ObjectUtils.get(this.data, SUITES_KEY, []);
+ for (const suiteItem of suites) {
+ let describeValue = ObjectUtils.get(suiteItem, DESCRIBE_KEY, []);
+ if (ObjectUtils.has(suiteItem, DESCRIBE_KEY) && (typeof describeValue === 'object') && describeValue.constructor === Array && describeValue.includes(suiteDesc)) {
+ let tempStress = ObjectUtils.get(suiteItem, STRESS_KEY, stress);
+ return (Number.isInteger(tempStress) && tempStress >= 1) ? tempStress : stress;
+ }
+ }
+ return stress;
+ }
+}
+
+export default DataDriver;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/config/Filter.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/config/Filter.js
new file mode 100644
index 0000000000000000000000000000000000000000..b07e6c681bfff618cc9f5ca92ec85d1d9880202d
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/config/Filter.js
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { LEVEL, SIZE, TESTTYPE } from '../../Constant';
+
+class ClassFilter {
+ constructor(suiteName, itName, params) {
+ this.suiteName = suiteName;
+ this.itName = itName;
+ this.params = params;
+ }
+
+ filterSuite() {
+ return !this.params.split(',').map(item => item.split('#')[0]).map(item => item == this.suiteName).reduce((pre, cur) => pre || cur, false);
+ }
+
+ filterIt() {
+ let classArray = this.params.split(',') || [];
+ let suiteFilterResult = classArray.filter(item => !item.includes('#')).map(item => item == this.suiteName).reduce((pre, cur) => pre || cur, false);
+ let itFilterResult = classArray.filter(item => item.includes('#')).map(item => item == (this.suiteName + '#' + this.itName)).reduce((pre, cur) => pre || cur, false);
+ return !(suiteFilterResult || itFilterResult);
+ }
+}
+
+class NotClassFilter {
+ constructor(suiteName, itName, params) {
+ this.suiteName = suiteName;
+ this.itName = itName;
+ this.params = params;
+ }
+
+ filterSuite() {
+ return this.params.split(',').map(item => item == this.suiteName).reduce((pre, cur) => pre || cur, false);
+ }
+
+ filterIt() {
+ return this.params.split(',').some(item => item == (this.suiteName + '#' + this.itName));
+ }
+}
+
+class SuiteAndItNameFilter {
+ constructor(suiteName, itName, params) {
+ this.suiteName = suiteName;
+ this.itName = itName;
+ this.params = params;
+ }
+
+ filterSuite() {
+ return !this.params.split(',').map(item => item == this.suiteName).reduce((pre, cur) => pre || cur, false);
+ }
+
+ filterIt() {
+ return !this.params.split(',').map(item => item == this.itName).reduce((pre, cur) => pre || cur, false);
+ }
+}
+
+
+class TestTypesFilter {
+ constructor(suiteName, itName, fi, params) {
+ this.suiteName = suiteName;
+ this.itName = itName;
+ this.params = params;
+ this.fi = fi;
+ }
+
+ filterIt() {
+ return !((this.params === (this.fi & this.params)) || this.fi === 0);
+ }
+}
+
+class NestFilter {
+ filterNestName(targetSuiteArray, targetSpecArray, suiteStack, desc) {
+ let targetSuiteName = '';
+ for (let key in suiteStack) {
+ targetSuiteName = targetSuiteName + '.' + suiteStack[key].description;
+ }
+ targetSuiteName = targetSuiteName.substring(2);
+ const targetSpecName = targetSuiteName + '#' + desc;
+ let isFilter = true;
+ if (targetSpecArray.includes(targetSpecName)) {
+ return false;
+ }
+ for (let index in targetSuiteArray) {
+ if (targetSuiteName.startsWith(targetSuiteArray[index])) {
+ return false;
+ }
+ }
+ return isFilter;
+ }
+
+ filterNotClass(notClass, suiteStack, desc) {
+ let isFilterNotClass = false;
+ if (notClass != null) {
+ let notClassArray = notClass.split(',');
+ let targetSuiteName = '';
+ for (let key in suiteStack) {
+ targetSuiteName = targetSuiteName + '.' + suiteStack[key].description;
+ }
+ targetSuiteName = targetSuiteName.substring(2);
+ const targetSpecName = targetSuiteName + '#' + desc;
+ if (notClassArray.includes(targetSpecName) || notClassArray.some(key => targetSpecName.startsWith(key))) {
+ isFilterNotClass = true;
+ }
+ }
+ return isFilterNotClass;
+ }
+
+ filterLevelOrSizeOrTestType(level, size, testType, filter) {
+ let result = false;
+ if (filter === 0 || filter === '0') {
+ return result;
+ }
+ if (level == null && size == null && testType == null) {
+ return result;
+ }
+ if (level != null) {
+ let levelFilter = LEVEL[`${level}`];
+ result = result || filter === levelFilter;
+ }
+ if (size != null) {
+ let sizeFilter = SIZE[`${size}`];
+ result = result || filter === sizeFilter;
+ }
+ if (testType != null) {
+ let testTypeFilter = TESTTYPE[`${testType}`];
+ result = result || filter === testTypeFilter;
+ }
+ return !result;
+ }
+}
+export { ClassFilter, NotClassFilter, SuiteAndItNameFilter, TestTypesFilter, NestFilter };
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/config/configService.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/config/configService.js
new file mode 100644
index 0000000000000000000000000000000000000000..17674d8cf7e2343bcb4a14ad47eb11cd03c15aac
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/config/configService.js
@@ -0,0 +1,299 @@
+/*
+ * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { ClassFilter, NotClassFilter, SuiteAndItNameFilter, TestTypesFilter, NestFilter } from './Filter';
+import { TAG, TESTTYPE, LEVEL, SIZE, KEYSET } from '../../Constant';
+const STRESS_RULE = /^[1-9]\d*$/;
+
+class ConfigService {
+ constructor(attr) {
+ this.id = attr.id;
+ this.supportAsync = true; // 默认异步处理测试用例
+ this.random = false;
+ this.filterValid = [];
+ this.filter = 0;
+ this.flag = false;
+ this.suite = null;
+ this.itName = null;
+ this.testType = null;
+ this.level = null;
+ this.size = null;
+ this.class = null;
+ this.notClass = null;
+ this.timeout = null;
+ // 遇错即停模式配置
+ this.breakOnError = false;
+ // 压力测试配置
+ this.stress = null;
+ this.skipMessage = false;
+ this.runSkipped = '';
+ this.filterXdescribe = [];
+ }
+
+ init(coreContext) {
+ this.coreContext = coreContext;
+ }
+
+ isNormalInteger(str) {
+ const n = Math.floor(Number(str));
+ return n !== Infinity && String(n) === String(str) && n >= 0;
+ }
+
+
+ getStress() {
+ if (this.stress === undefined || this.stress === '' || this.stress === null) {
+ return 1;
+ }
+ return !this.stress.match(STRESS_RULE) ? 1 : Number.parseInt(this.stress);
+ }
+
+ basicParamValidCheck(params) {
+ let size = params.size;
+ if (size !== undefined && size !== '' && size !== null) {
+ let sizeArray = ['small', 'medium', 'large'];
+ if (sizeArray.indexOf(size) === -1) {
+ this.filterValid.push('size:' + size);
+ }
+ }
+ let level = params.level;
+ if (level !== undefined && level !== '' && level !== null) {
+ let levelArray = ['0', '1', '2', '3', '4'];
+ if (levelArray.indexOf(level) === -1) {
+ this.filterValid.push('level:' + level);
+ }
+ }
+ let testType = params.testType;
+ if (testType !== undefined && testType !== '' && testType !== null) {
+ let testTypeArray = ['function', 'performance', 'power', 'reliability', 'security',
+ 'global', 'compatibility', 'user', 'standard', 'safety', 'resilience'];
+ if (testTypeArray.indexOf(testType) === -1) {
+ this.filterValid.push('testType:' + testType);
+ }
+ }
+ }
+
+ filterParamValidCheck(params) {
+ let timeout = params.timeout;
+ if (timeout !== undefined && timeout !== '' && timeout !== null) {
+ if (!this.isNormalInteger(timeout)) {
+ this.filterValid.push('timeout:' + timeout);
+ }
+ }
+
+ let paramKeys = ['dryRun', 'random', 'breakOnError', 'coverage', 'skipMessage'];
+ for (const key of paramKeys) {
+ if (params[key] !== undefined && params[key] !== 'true' && params[key] !== 'false') {
+ this.filterValid.push(`${key}:${params[key]}`);
+ }
+ }
+
+ // 压力测试参数验证,正整数
+ if (params.stress !== undefined && params.stress !== '' && params.stress !== null) {
+ if (!params.stress.match(STRESS_RULE)) {
+ this.filterValid.push('stress:' + params.stress);
+ }
+ }
+
+ let nameRule = /^[A-Za-z]{1}[\w#,.]*$/;
+ let paramClassKeys = ['class', 'notClass'];
+ for (const key of paramClassKeys) {
+ if (params[key] !== undefined && params[key] !== '' && params[key] !== null) {
+ let classArray = params[key].split(',');
+ classArray.forEach(item => !item.match(nameRule) ? this.filterValid.push(`${key}:${params[key]}`) : null);
+ }
+ }
+ }
+
+ setConfig(params) {
+ this.basicParamValidCheck(params);
+ this.filterParamValidCheck(params);
+ try {
+ this.class = params.class;
+ this.notClass = params.notClass;
+ this.flag = params.flag || { flag: false };
+ this.suite = params.suite;
+ this.itName = params.itName;
+ this.filter = params.filter;
+ this.testType = params.testType;
+ this.level = params.level;
+ this.size = params.size;
+ this.timeout = params.timeout;
+ this.dryRun = params.dryRun;
+ this.breakOnError = params.breakOnError;
+ this.random = params.random === 'true' ? true : false;
+ this.stress = params.stress;
+ this.coverage = params.coverage;
+ this.skipMessage = params.skipMessage;
+ this.runSkipped = params.runSkipped;
+ this.filterParam = {
+ testType: TESTTYPE,
+ level: LEVEL,
+ size: SIZE
+ };
+ this.parseParams();
+ } catch (err) {
+ console.info(`${TAG}setConfig error: ${err.message}`);
+ }
+ }
+
+ parseParams() {
+ if (this.filter != null) {
+ return;
+ }
+ let testTypeFilter = 0;
+ let sizeFilter = 0;
+ let levelFilter = 0;
+ if (this.testType != null) {
+ testTypeFilter = this.testType.split(',')
+ .map(item => this.filterParam.testType[item] || 0)
+ .reduce((pre, cur) => pre | cur, 0);
+ }
+ if (this.level != null) {
+ levelFilter = this.level.split(',')
+ .map(item => this.filterParam.level[item] || 0)
+ .reduce((pre, cur) => pre | cur, 0);
+ }
+ if (this.size != null) {
+ sizeFilter = this.size.split(',')
+ .map(item => this.filterParam.size[item] || 0)
+ .reduce((pre, cur) => pre | cur, 0);
+ }
+ this.filter = testTypeFilter | sizeFilter | levelFilter;
+ console.info(`${TAG}filter params:${this.filter}`);
+ }
+
+ isCurrentSuite(description) {
+ if (this.suite !== undefined && this.suite !== '' && this.suite !== null) {
+ let suiteArray = this.suite.split(',');
+ return suiteArray.indexOf(description) !== -1;
+ }
+ return false;
+ }
+
+ filterSuite(currentSuiteName) {
+ let filterArray = [];
+ if (this.suite !== undefined && this.suite !== '' && this.suite !== null) {
+ filterArray.push(new SuiteAndItNameFilter(currentSuiteName, '', this.suite));
+ }
+ if (this.class !== undefined && this.class !== '' && this.class !== null) {
+ filterArray.push(new ClassFilter(currentSuiteName, '', this.class));
+ }
+ if (this.notClass !== undefined && this.notClass !== '' && this.notClass !== null) {
+ filterArray.push(new NotClassFilter(currentSuiteName, '', this.notClass));
+ }
+
+ let result = filterArray.map(item => item.filterSuite()).reduce((pre, cur) => pre || cur, false);
+ return result;
+ }
+
+ filterDesc(currentSuiteName, desc, fi, coreContext) {
+ let filterArray = [];
+ if (this.itName !== undefined && this.itName !== '' && this.itName !== null) {
+ filterArray.push(new SuiteAndItNameFilter(currentSuiteName, desc, this.itName));
+ }
+ if (this.class !== undefined && this.class !== '' && this.class !== null) {
+ filterArray.push(new ClassFilter(currentSuiteName, desc, this.class));
+ }
+ if (this.notClass !== undefined && this.notClass !== '' && this.notClass !== null) {
+ filterArray.push(new NotClassFilter(currentSuiteName, desc, this.notClass));
+ }
+ if (typeof (this.filter) !== 'undefined' && this.filter !== 0 && fi !== 0) {
+ filterArray.push(new TestTypesFilter('', '', fi, this.filter));
+ }
+ let result = filterArray.map(item => item.filterIt()).reduce((pre, cur) => pre || cur, false);
+ return result;
+ }
+
+ filterWithNest(desc, filter) {
+ let filterArray = [];
+ const nestFilter = new NestFilter();
+ const targetSuiteArray = this.coreContext.getDefaultService('suite').targetSuiteArray;
+ const targetSpecArray = this.coreContext.getDefaultService('suite').targetSpecArray;
+ const suiteStack = this.coreContext.getDefaultService('suite').suitesStack;
+ let isFilter = nestFilter.filterNestName(targetSuiteArray, targetSpecArray, suiteStack, desc);
+ const isFullRun = this.coreContext.getDefaultService('suite').fullRun;
+ if (typeof (this.filter) !== 'undefined' && this.filter !== 0 && filter !== 0) {
+ filterArray.push(new TestTypesFilter('', '', filter, this.filter));
+ return filterArray.map(item => item.filterIt()).reduce((pre, cur) => pre || cur, false);
+ }
+ if (isFilter && !isFullRun) {
+ return true;
+ }
+ return nestFilter.filterNotClass(this.notClass, suiteStack, desc);
+
+ }
+
+ isRandom() {
+ return this.random || false;
+ }
+
+ isBreakOnError() {
+ return this.breakOnError !== 'true' ? false : true;
+ }
+
+ setSupportAsync(value) {
+ this.supportAsync = value;
+ }
+
+ isSupportAsync() {
+ return this.supportAsync;
+ }
+
+ translateParams(parameters) {
+ const keySet = new Set(KEYSET);
+ let targetParams = {};
+ for (const key in parameters) {
+ if (keySet.has(key)) {
+ var newKey = key.replace('-s ', '');
+ targetParams[newKey] = parameters[key];
+ }
+ }
+ return targetParams;
+ }
+ translateParamsToString(parameters) {
+ const keySet = new Set(KEYSET);
+ let targetParams = '';
+ for (const key in parameters) {
+ if (keySet.has(key)) {
+ targetParams += ' ' + key + ' ' + parameters[key];
+ }
+ }
+ return targetParams.trim();
+ }
+
+ execute() {
+ }
+
+ checkIfSuiteInSkipRun(desc) {
+ return this.runSkipped.split(',').some(item => {
+ return item === desc || item.startsWith(desc + '.') || item.startsWith(desc + '#') || desc.startsWith(item + '.') || this.runSkipped === 'skipped';
+ });
+ }
+
+ checkIfSpecInSkipRun(desc) {
+ return this.runSkipped.split(',').some(item => {
+ if (item.includes('#')) {
+ return item === desc;
+ } else {
+ return desc.startsWith(item + '.') || desc.startsWith(item + '#') || this.runSkipped === 'skipped';
+ }
+ }
+ );
+ }
+}
+
+export {
+ ConfigService
+};
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/coverage/coverageCollect.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/coverage/coverageCollect.js
new file mode 100644
index 0000000000000000000000000000000000000000..334a33db9561dd2070c4081457632decf2589b83
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/coverage/coverageCollect.js
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2023 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import SysTestKit from '../kit/SysTestKit';
+import fs from '@ohos.file.fs';
+import {TAG} from '../../Constant';
+
+const jsCoverageFileName = 'js_coverage.json';
+
+export async function collectCoverageData() {
+ if (globalThis.__coverage__ === undefined) {
+ console.info(`${TAG} globalThis not have coverage`);
+ return;
+ }
+ const strJson = JSON.stringify(globalThis.__coverage__);
+ let testMode = globalThis.__testMode__;
+ console.info(`${TAG} coverage data testMode: ${testMode}`);
+ let savePath = globalThis.__savePath__;
+ console.info(`${TAG} write coverage data to: ${savePath}`);
+ let readPath = globalThis.__readPath__;
+ console.info(`${TAG} read coverage data in: ${readPath}`);
+
+ // run callback mode if local test or (save path and read path ) is not defined
+ if (!testMode || !isCoveragePathValid(savePath)) {
+ console.info(`${TAG} run coverage data in call back mode`);
+ const strLen = strJson.length;
+ const maxLen = 500;
+ const maxCount = Math.floor(strLen / maxLen);
+ const OHOS_REPORT_COVERAGE_DATA = 'OHOS_REPORT_COVERAGE_DATA:';
+ for (let count = 0; count <= maxCount; count++) {
+ console.info(`${OHOS_REPORT_COVERAGE_DATA} ${strJson.substring(count * maxLen, (count + 1) * maxLen)}`);
+ await SysTestKit.print(`${OHOS_REPORT_COVERAGE_DATA} ${strJson.substring(count * maxLen, (count + 1) * maxLen)}`);
+ }
+ return;
+ }
+ console.info(`${TAG} run coverage data in save file mode`);
+ if (fs.accessSync(savePath)) {
+ fs.unlinkSync(savePath);
+ }
+
+ let inputPathDir = savePath.substring(0, savePath.length - jsCoverageFileName.length);
+ if (!fs.accessSync(inputPathDir)) {
+ console.info(`${TAG} coverage data create dir: ${inputPathDir}`);
+ fs.mkdirSync(inputPathDir);
+ }
+
+ let file = fs.openSync(savePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
+ let writeLen = fs.writeSync(file.fd, strJson, {encoding:'utf-8'});
+ console.info(`${TAG} write coverage data success: ${writeLen}`);
+ fs.closeSync(file);
+ const OHOS_REPORT_COVERAGE_PATH = 'OHOS_REPORT_COVERAGE_PATH:';
+ await SysTestKit.print(`${OHOS_REPORT_COVERAGE_PATH} ${readPath}`);
+ console.info(`${OHOS_REPORT_COVERAGE_PATH} ${readPath}`);
+}
+
+function isCoveragePathValid(inputPath) {
+ if (!inputPath) {
+ return false;
+ }
+ if (inputPath.indexOf(jsCoverageFileName) === -1) {
+ return false;
+ }
+ return true;
+}
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/kit/SysTestKit.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/kit/SysTestKit.js
new file mode 100644
index 0000000000000000000000000000000000000000..6e2f256514cff87450f910098b1130943a40e39c
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/kit/SysTestKit.js
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {TAG} from '../../Constant';
+import Core from '../../core.js';
+
+export default class SysTestKit {
+
+ static delegator = null;
+ static systemTime = null;
+ static workerPort = null;
+
+ constructor() {
+ this.id = 'sysTestKit';
+ this.index = 0;
+ }
+
+ static getDescribeName() {
+ return Core.getInstance().getDefaultService('suite').getCurrentRunningSuite().description;
+ }
+
+ static getItName() {
+ return Core.getInstance().getDefaultService('spec').getCurrentRunningSpec().description;
+ }
+
+ static getItAttribute() {
+ return Core.getInstance().getDefaultService('spec').getCurrentRunningSpec().fi;
+ }
+
+ static actionStart(tag) {
+ console.info(`${TAG}${JSON.stringify(tag)}`);
+ var message = '\n' + 'OHOS_REPORT_ACTIONSTART: ' + JSON.stringify(tag) + '\n';
+ SysTestKit.print(message);
+ console.info(`${TAG}${JSON.stringify(tag)} actionStart print success`);
+ }
+
+ static actionEnd(tag) {
+ console.info(`${TAG}${JSON.stringify(tag)}`);
+ var message = '\n' + 'OHOS_REPORT_ACTIONEND: ' + JSON.stringify(tag) + '\n';
+ SysTestKit.print(message);
+ console.info(`${TAG}${JSON.stringify(tag)} actionEnd print success`);
+ }
+
+ static async existKeyword(keyword, timeout) {
+ let reg = new RegExp(/^[a-zA-Z0-9]{1,}$/);
+ if (!reg.test(keyword)) {
+ throw new Error('keyword must contain more than one string, and only letters and numbers are supported.');
+ }
+ timeout = timeout || 4;
+
+ let searchResult = false;
+ let cmd = 'hilog -x | grep -i \'' + keyword + '\' | wc -l';
+ await executePromise(cmd, timeout).then((data) => {
+ searchResult = data;
+ });
+ return searchResult;
+ }
+ static async print(message) {
+ if ('printSync' in SysTestKit.delegator) {
+ console.info(`${TAG}printSync called ...`);
+ SysTestKit.delegator.printSync(message);
+ } else {
+ await SysTestKit.delegator.print(message);
+ }
+ }
+
+ static async getRealTime() {
+ let currentTime = new Date().getTime();
+ if (SysTestKit.systemTime !== null && SysTestKit.systemTime !== undefined) {
+ await SysTestKit.systemTime.getRealTime().then((time) => {
+ console.info(`${TAG}systemTime.getRealTime success data: ${JSON.stringify(time)}`);
+ currentTime = time;
+ }).catch((error) => {
+ console.error(`${TAG}failed to systemTime.getRealTime because ${JSON.stringify(error)}`);
+ });
+ }
+ return currentTime;
+ }
+}
+
+function executePromise(cmd, timeout) {
+ return new Promise((resolve, reject) => {
+ SysTestKit.delegator.executeShellCommand(cmd, timeout,
+ (error, data) => {
+ console.info(`${TAG}existKeyword CallBack: err : ${JSON.stringify(error)}`);
+ console.info(`${TAG}existKeyword CallBack: data : ${JSON.stringify(data)}`);
+ resolve(parseInt(data.stdResult) > 3 ? true : false);
+ });
+ });
+}
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/mock/ArgumentMatchers.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/mock/ArgumentMatchers.js
new file mode 100644
index 0000000000000000000000000000000000000000..1e69ac401049589986968a8575ca45a02a299327
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/mock/ArgumentMatchers.js
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class ArgumentMatchers {
+ ANY = '';
+ ANY_STRING = '';
+ ANY_BOOLEAN = '';
+ ANY_NUMBER = '';
+ ANY_OBJECT = '';
+ ANY_FUNCTION = '';
+ MATCH_REGEXS = '';
+
+ static any() {
+ }
+
+ static anyString() {
+ }
+
+ static anyBoolean() {
+ }
+
+ static anyNumber() {
+ }
+
+ static anyObj() {
+ }
+
+ static anyFunction() {
+ }
+
+ static matchRegexs() {
+ let regex = arguments[0];
+ if (ArgumentMatchers.isRegExp(regex)) {
+ return regex;
+ }
+ throw Error('not a regex');
+ }
+
+ static isRegExp(value) {
+ return Object.prototype.toString.call(value) === '[object RegExp]';
+ }
+
+ matcheReturnKey() {
+ let arg = arguments[0];
+ let regex = arguments[1];
+ let stubSetKey = arguments[2];
+
+ if (stubSetKey && stubSetKey == this.ANY) {
+ return this.ANY;
+ }
+
+ if (typeof arg === 'string' && !regex) {
+ return this.ANY_STRING;
+ }
+
+ if (typeof arg === 'boolean' && !regex) {
+ return this.ANY_BOOLEAN;
+ }
+
+ if (typeof arg === 'number' && !regex) {
+ return this.ANY_NUMBER;
+ }
+
+ if (typeof arg === 'object' && !regex) {
+ return this.ANY_OBJECT;
+ }
+
+ if (typeof arg === 'function' && !regex) {
+ return this.ANY_FUNCTION;
+ }
+
+ if (typeof arg === 'string' && regex) {
+ return regex.test(arg);
+ }
+
+ return null;
+ }
+
+ matcheStubKey() {
+ let key = arguments[0];
+
+ if (key === ArgumentMatchers.any) {
+ return this.ANY;
+ }
+
+ if (key === ArgumentMatchers.anyString) {
+ return this.ANY_STRING;
+ }
+ if (key === ArgumentMatchers.anyBoolean) {
+ return this.ANY_BOOLEAN;
+ }
+ if (key === ArgumentMatchers.anyNumber) {
+ return this.ANY_NUMBER;
+ }
+ if (key === ArgumentMatchers.anyObj) {
+ return this.ANY_OBJECT;
+ }
+ if (key === ArgumentMatchers.anyFunction) {
+ return this.ANY_FUNCTION;
+ }
+
+ if (ArgumentMatchers.isRegExp(key)) {
+ return key;
+ }
+
+ return null;
+ }
+}
+
+export default ArgumentMatchers;
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/mock/ExtendInterface.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/mock/ExtendInterface.js
new file mode 100644
index 0000000000000000000000000000000000000000..c6a866a6df662ad10a7f6869dcbc2381fa47bcdc
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/mock/ExtendInterface.js
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class ExtendInterface {
+ constructor(mocker) {
+ this.mocker = mocker;
+ }
+
+ stub() {
+ this.params = arguments;
+ return this;
+ }
+
+ stubMockedCall(returnInfo) {
+ this.mocker.stubApply(this, this.params, returnInfo);
+ }
+
+ afterReturn(value) {
+ this.stubMockedCall(function () {
+ return value;
+ });
+ }
+
+ afterReturnNothing() {
+ this.stubMockedCall(function () {
+ return undefined;
+ });
+ }
+
+ afterAction(action) {
+ this.stubMockedCall(action);
+ }
+
+ afterThrow(msg) {
+ this.stubMockedCall(function () {
+ throw msg;
+ });
+ }
+
+ clear() {
+ this.mocker.clear();
+ }
+}
+
+export default ExtendInterface;
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/mock/MockKit.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/mock/MockKit.js
new file mode 100644
index 0000000000000000000000000000000000000000..5895666bc89ed4270582b436c82045745d5249b4
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/mock/MockKit.js
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import ExtendInterface from './ExtendInterface';
+import VerificationMode from './VerificationMode';
+import ArgumentMatchers from './ArgumentMatchers';
+
+class MockKit {
+
+ constructor() {
+ this.mFunctions = [];
+ this.stubs = new Map();
+ this.recordCalls = new Map();
+ this.currentSetKey = new Map();
+ this.mockObj = null;
+ this.recordMockedMethod = new Map();
+ }
+
+ init() {
+ this.reset();
+ }
+
+ reset() {
+ this.mFunctions = [];
+ this.stubs = {};
+ this.recordCalls = {};
+ this.currentSetKey = new Map();
+ this.mockObj = null;
+ this.recordMockedMethod = new Map();
+ }
+
+ clearAll() {
+ this.reset();
+ var props = Object.keys(this);
+ for (var i = 0; i < props.length; i++) {
+ delete this[props[i]];
+ }
+
+ var props = Object.getOwnPropertyNames(this);
+ for (var i = 0; i < props.length; i++) {
+ delete this[props[i]];
+ }
+ for (var key in this) {
+ delete this[key];
+ }
+ }
+
+ clear(obj) {
+ if (!obj) {
+ throw Error('Please enter an object to be cleaned');
+ }
+ if (typeof (obj) !== 'object' && typeof (obj) !== 'function') {
+ throw new Error('Not a object or static class');
+ }
+ this.recordMockedMethod.forEach(function (value, key, map) {
+ if (key) {
+ obj[key] = value;
+ }
+ });
+ }
+
+ ignoreMock(obj, method) {
+ if (typeof (obj) !== 'object' && typeof (obj) !== 'function') {
+ throw new Error('Not a object or static class');
+ }
+ if (typeof (method) !== 'function') {
+ throw new Error('Not a function');
+ }
+ let og = this.recordMockedMethod.get(method.propName);
+ if (og) {
+ obj[method.propName] = og;
+ this.recordMockedMethod.set(method.propName, undefined);
+ }
+ }
+
+ extend(dest, source) {
+ dest['stub'] = source['stub'];
+ dest['afterReturn'] = source['afterReturn'];
+ dest['afterReturnNothing'] = source['afterReturnNothing'];
+ dest['afterAction'] = source['afterAction'];
+ dest['afterThrow'] = source['afterThrow'];
+ dest['stubMockedCall'] = source['stubMockedCall'];
+ dest['clear'] = source['clear'];
+ return dest;
+ }
+
+ stubApply(f, params, returnInfo) {
+ let values = this.stubs.get(f);
+ if (!values) {
+ values = new Map();
+ }
+ let key = params[0];
+ if (typeof key == 'undefined') {
+ key = 'anonymous-mock-' + f.propName;
+ }
+ let matcher = new ArgumentMatchers();
+ if (matcher.matcheStubKey(key)) {
+ key = matcher.matcheStubKey(key);
+ if (key) {
+ this.currentSetKey.set(f, key);
+ }
+ }
+ values.set(key, returnInfo);
+ this.stubs.set(f, values);
+ }
+
+ getReturnInfo(f, params) {
+ let values = this.stubs.get(f);
+ if (!values) {
+ return undefined;
+ }
+ let retrunKet = params[0];
+ if (typeof retrunKet == 'undefined') {
+ retrunKet = 'anonymous-mock-' + f.propName;
+ }
+ let stubSetKey = this.currentSetKey.get(f);
+
+ if (stubSetKey && (typeof (retrunKet) !== 'undefined')) {
+ retrunKet = stubSetKey;
+ }
+ let matcher = new ArgumentMatchers();
+ if (matcher.matcheReturnKey(params[0], undefined, stubSetKey) && matcher.matcheReturnKey(params[0], undefined, stubSetKey) !== stubSetKey) {
+ retrunKet = params[0];
+ }
+
+ values.forEach(function (value, key, map) {
+ if (ArgumentMatchers.isRegExp(key) && matcher.matcheReturnKey(params[0], key)) {
+ retrunKet = key;
+ }
+ });
+
+ return values.get(retrunKet);
+ }
+
+ findName(obj, value) {
+ let properties = this.findProperties(obj);
+ let name = null;
+ properties.filter(item => (item !== 'caller' && item !== 'arguments')).forEach(
+ function (va1, idx, array) {
+ if (obj[va1] === value) {
+ name = va1;
+ }
+ }
+ );
+ return name;
+ }
+
+ isFunctionFromPrototype(f, container, propName) {
+ if (container.constructor !== Object && container.constructor.prototype !== container) {
+ return container.constructor.prototype[propName] === f;
+ }
+ return false;
+ }
+
+ findProperties(obj, ...arg) {
+ function getProperty(newObj) {
+ if (newObj.__proto__ === null) {
+ return [];
+ }
+ let properties = Object.getOwnPropertyNames(newObj);
+ return [...properties, ...getProperty(newObj.__proto__)];
+ }
+ return getProperty(obj);
+ }
+
+ recordMethodCall(originalMethod, args) {
+ Function.prototype.getName = function () {
+ return this.name || this.toString().match(/function\s*([^(]*)\(/)[1];
+ };
+ let name = originalMethod.getName();
+ let arglistString = name + '(' + Array.from(args).toString() + ')';
+ let records = this.recordCalls.get(arglistString);
+ if (!records) {
+ records = 0;
+ }
+ records++;
+ this.recordCalls.set(arglistString, records);
+ }
+
+ mockFunc(originalObject, originalMethod) {
+ let tmp = this;
+ this.originalMethod = originalMethod;
+ let f = function () {
+ let args = arguments;
+ let action = tmp.getReturnInfo(f, args);
+ if (originalMethod) {
+ tmp.recordMethodCall(originalMethod, args);
+ }
+ if (action) {
+ return action.apply(this, args);
+ }
+ };
+
+ f.container = null || originalObject;
+ f.original = originalMethod || null;
+
+ if (originalObject && originalMethod) {
+ if (typeof (originalMethod) !== 'function') {
+ throw new Error('Not a function');
+ }
+ var name = this.findName(originalObject, originalMethod);
+ originalObject[name] = f;
+ this.recordMockedMethod.set(name, originalMethod);
+ f.propName = name;
+ f.originalFromPrototype = this.isFunctionFromPrototype(f.original, originalObject, f.propName);
+ }
+ f.mocker = this;
+ this.mFunctions.push(f);
+ this.extend(f, new ExtendInterface(this));
+ return f;
+ }
+
+ verify(methodName, argsArray) {
+ if (!methodName) {
+ throw Error('not a function name');
+ }
+ let a = this.recordCalls.get(methodName + '(' + argsArray.toString() + ')');
+ return new VerificationMode(a ? a : 0);
+ }
+
+ mockObject(object) {
+ if (!object || typeof object === 'string') {
+ throw Error(`this ${object} cannot be mocked`);
+ }
+ const _this = this;
+ let mockedObject = {};
+ let keys = Reflect.ownKeys(object);
+ keys.filter(key => (typeof Reflect.get(object, key)) === 'function')
+ .forEach(key => {
+ mockedObject[key] = object[key];
+ mockedObject[key] = _this.mockFunc(mockedObject, mockedObject[key]);
+ });
+ return mockedObject;
+ }
+}
+
+function ifMockedFunction(f) {
+ if (Object.prototype.toString.call(f) !== '[object Function]' &&
+ Object.prototype.toString.call(f) !== '[object AsyncFunction]') {
+ throw Error('not a function');
+ }
+ if (!f.stub) {
+ throw Error('not a mock function');
+ }
+ return true;
+}
+
+function when(f) {
+ if (ifMockedFunction(f)) {
+ return f.stub.bind(f);
+ }
+}
+
+export {MockKit, when};
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/mock/VerificationMode.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/mock/VerificationMode.js
new file mode 100644
index 0000000000000000000000000000000000000000..aaf2fdfae00135d3d2055320fc5ea403b44d0bf3
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/mock/VerificationMode.js
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {expect} from '../../interface';
+
+class VerificationMode {
+ constructor(times) {
+ this.doTimes = times;
+ }
+
+ times(count) {
+ expect(count).assertEqual(this.doTimes);
+ }
+
+ never() {
+ console.info(this.doTimes);
+ expect(0).assertEqual(this.doTimes);
+ }
+
+ once() {
+ expect(1).assertEqual(this.doTimes);
+ }
+
+ atLeast(count) {
+ if (count > this.doTimes) {
+ throw Error('failed ' + count + ' greater than the actual execution times of method');
+ }
+ }
+
+ atMost(count) {
+ if (count < this.doTimes) {
+ throw Error('failed ' + count + ' less than the actual execution times of method');
+ }
+ }
+}
+
+export default VerificationMode;
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/report/LogExpectError.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/report/LogExpectError.js
new file mode 100644
index 0000000000000000000000000000000000000000..5a94cecb4625205797ae886c19ac592f189c2232
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/report/LogExpectError.js
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class LogExpectError {
+ static getErrorMsg(matcherName, actualValue, expect, originMsg) {
+ if (matcherName === 'assertNull') {
+ return 'expect not null, actualValue is ' + (actualValue);
+ }
+ if (matcherName === 'assertTrue') {
+ return 'expect not true, actualValue is ' + (actualValue);
+ }
+ if (matcherName === 'assertFalse') {
+ return 'expect not false, actualValue is ' + (actualValue);
+ }
+ if (matcherName === 'assertEqual') {
+ return 'expect not Equal, actualValue is ' + actualValue + ' equals ' + expect;
+ }
+ if (matcherName === 'assertContain') {
+ return 'expect not have, ' + actualValue + ' have ' + expect;
+ }
+ if (matcherName === 'assertInstanceOf') {
+ return 'expect not InstanceOf, ' + actualValue + ' is ' +
+ Object.prototype.toString.call(actualValue) + expect;
+ }
+ if (matcherName === 'assertLarger') {
+ return 'expect not Larger, ' +
+ (actualValue) + ' is larger than ' + expect;
+ }
+ if (matcherName === 'assertLargerOrEqual') {
+ return 'expect not LargerOrEqual, ' + (actualValue) + ' larger than ' + expect;
+ }
+ if (matcherName === 'assertLess') {
+ return 'expect not Less, ' + (actualValue) + ' less than ' + expect;
+ }
+ if (matcherName === 'assertLessOrEqual') {
+ return 'expect not LessOrEqual, ' + (actualValue) + ' is less than ' + expect;
+ }
+ if (matcherName === 'assertNaN') {
+ return 'expect not NaN, actualValue is ' + (actualValue);
+ }
+ if (matcherName === 'assertNegUnlimited') {
+ return 'expect not NegUnlimited, actualValue is ' + (actualValue);
+ }
+ if (matcherName === 'assertPosUnlimited') {
+ return 'expect not PosUnlimited, actualValue is ' + (actualValue);
+ }
+ if (matcherName === 'assertUndefined') {
+ return 'expect not Undefined, actualValue is ' + (actualValue);
+ }
+ return originMsg;
+ }
+}
+export default LogExpectError;
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/report/OhReport.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/report/OhReport.js
new file mode 100644
index 0000000000000000000000000000000000000000..653e56be9e88e810f6ab1f3d58049cf08d2ac0b6
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/report/OhReport.js
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import SysTestKit from "../kit/SysTestKit";
+import { collectCoverageData } from '../coverage/coverageCollect';
+import { TAG, PrintTag } from '../../Constant';
+
+class OhReport {
+ constructor(attr) {
+ this.delegator = attr.delegator;
+ this.abilityDelegatorArguments = attr.abilityDelegatorArguments;
+ this.id = 'report';
+ this.index = 0;
+ this.duration = 0;
+ this.currentThreadName = 'mainThread';
+ }
+
+ init(coreContext) {
+ this.coreContext = coreContext;
+ this.suiteService = this.coreContext.getDefaultService('suite');
+ this.specService = this.coreContext.getDefaultService('spec');
+ if (SysTestKit.workerPort !== null) {
+ this.currentThreadName = SysTestKit.workerPort.name;
+ }
+ }
+
+ taskStart() {
+ }
+
+ async taskDone() {
+ let summary = this.suiteService.getSummary();
+ if (this.abilityDelegatorArguments !== null) {
+ this.taskDoneTime = new Date().getTime();
+ const configService = this.coreContext.getDefaultService('config');
+ const suiteService = this.coreContext.getDefaultService('suite');
+ const specService = this.coreContext.getDefaultService('spec');
+ if (configService['coverage'] === 'true') {
+ await collectCoverageData();
+ }
+ let message = '\n' + `${PrintTag.OHOS_REPORT_RESULT}: stream=Tests run: ` + summary.total + ', Failure: ' + summary.failure;
+ message += ', Error: ' + summary.error;
+ message += ', Pass: ' + summary.pass;
+ message += ', Ignore: ' + summary.ignore;
+ if (specService.skipSpecNum > 0) {
+ message += ', SkipSpec: ' + specService.skipSpecNum;
+ }
+ message += '\n' + `${PrintTag.OHOS_REPORT_CODE}: ` + (summary.failure > 0 ? -1 : 0) + '\n';
+ let isHasError = summary.failure > 0 || summary.error > 0;
+ let config = this.coreContext.getDefaultService('config');
+ if (config.isBreakOnError() && isHasError) {
+ // 未执行全部说明
+ message += '\n' + `${PrintTag.OHOS_REPORT_RESULT}: breakOnError model, Stopping whole test suite if one specific test case failed or error` + '\n';
+ }
+ message += `${PrintTag.OHOS_REPORT_STATUS}: taskconsuming=` + summary.duration + '\n';
+ console.info(`${message}`);
+ await SysTestKit.print(message);
+ }
+ if (SysTestKit.workerPort === null || SysTestKit.workerPort === undefined) {
+ // 主线程执行完成 结束任务。
+ console.info(`${TAG}report print success`);
+ this.delegator.finishTest('your test finished!!!', 0, () => { });
+ } else {
+ // worker线程执行完成将数据发送到主线程中。
+ let sendData = {
+ currentThreadName: this.currentThreadName,
+ summary: summary
+ };
+ console.info(`${TAG}, send data to mainThread, ${this.currentThreadName}, ${JSON.stringify(sendData)}`);
+ SysTestKit.workerPort.postMessage(sendData);
+ }
+ }
+
+ incorrectFormat() {
+ if (this.coreContext.getDefaultService('config').filterValid.length !== 0) {
+ var value = this.coreContext.getDefaultService('config').filterValid;
+ var message = 'this param ' + value.join(',') + ' is invalid' + '\n';
+ this.delegator.finishTest(message, 0, () => {
+ });
+ }
+ }
+
+ incorrectTestSuiteFormat() {
+ if (this.coreContext.getDefaultService('config').filterXdescribe.length !== 0) {
+ let value = this.coreContext.getDefaultService('config').filterXdescribe;
+ let message = 'xdescribe ' + value.join(',') + ' should not contain it' + '\n';
+ this.delegator.finishTest(message, 0, () => {
+ });
+ }
+ }
+ async suiteStart() {
+ if (this.abilityDelegatorArguments !== null) {
+ let specArr = [];
+ this.suiteService.getAllChildSuiteNum(this.suiteService.getCurrentRunningSuite(), specArr);
+ let message = '\n' + `${PrintTag.OHOS_REPORT_SUM}: ` + specArr.length;
+ this.suiteService.setCurrentRunningSuiteDesc(this.suiteService.getRootSuite(), this.suiteService.getCurrentRunningSuite(), '');
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: class=` + this.suiteService.getCurrentRunningSuiteDesc() + '\n';
+ if (this.suiteService.currentRunningSuite.isSkip) {
+ message += `${PrintTag.OHOS_REPORT_STATUS}: skipReason=` + this.suiteService.currentRunningSuite.skipReason + '\n';
+ }
+ if (SysTestKit.workerPort !== null) {
+ message += `${PrintTag.OHOS_REPORT_STATUS}: currentWorkerName=` + this.currentThreadName;
+ }
+ console.info(`${message}`);
+ await SysTestKit.print(message);
+ console.info(`${TAG}${this.suiteService.getCurrentRunningSuite().description} suiteStart print success`);
+ }
+ }
+
+ async suiteDone() {
+ if (this.abilityDelegatorArguments !== null) {
+ const currentRunningSuite = this.suiteService.getCurrentRunningSuite();
+ this.suiteService.setCurrentRunningSuiteDesc(this.suiteService.getRootSuite(), this.suiteService.getCurrentRunningSuite(), '');
+ let message = '\n' + `${PrintTag.OHOS_REPORT_STATUS}: class=` + this.suiteService.getCurrentRunningSuiteDesc();
+ if (this.suiteService.currentRunningSuite.isSkip && this.suiteService.currentRunningSuite.skipReason !== '') {
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: skipReason=` + this.suiteService.currentRunningSuite.skipReason;
+ }
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: suiteconsuming=` + this.suiteService.getCurrentRunningSuite().duration;
+ if (currentRunningSuite.hookError) {
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: ${currentRunningSuite.hookError.message}`;
+ }
+ message += '\n';
+ if (SysTestKit.workerPort !== null) {
+ message += `${PrintTag.OHOS_REPORT_STATUS}: currentWorkerName=` + this.currentThreadName;
+ }
+ console.info(`${message}`);
+ await SysTestKit.print(message);
+ console.info(`${TAG}${this.suiteService.getCurrentRunningSuite().description} suiteDone print success`);
+ }
+ }
+
+ async specStart() {
+ if (this.abilityDelegatorArguments !== null) {
+ let message = '\n' + `${PrintTag.OHOS_REPORT_STATUS}: class=` + this.suiteService.getCurrentRunningSuiteDesc();
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: current=` + (++this.index);
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: id=JS`;
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: numtests=` + this.specService.getTestTotal();
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: stream=`;
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: test=` + this.specService.currentRunningSpec.description;
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS_CODE}: 1` + '\n';
+ if (this.specService.currentRunningSpec.isSkip) {
+ message += `${PrintTag.OHOS_REPORT_STATUS}: skipReason=` + this.specService.currentRunningSpec.skipReason + '\n';
+ }
+ if (SysTestKit.workerPort !== null) {
+ message += `${PrintTag.OHOS_REPORT_STATUS}: currentWorkerName=` + this.currentThreadName;
+ }
+ console.info(`${message}`);
+ await SysTestKit.print(message);
+ console.info(`${TAG}${this.specService.currentRunningSpec.description} specStart start print success`);
+ }
+ }
+
+ async specDone() {
+ if (this.abilityDelegatorArguments !== null) {
+ let message = '\n' + `${PrintTag.OHOS_REPORT_STATUS}: class=` + this.suiteService.getCurrentRunningSuiteDesc();
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: current=` + (this.index);
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: id=JS`;
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: numtests=` + this.specService.getTestTotal();
+ let messageStack = '';
+ let messageCode = '';
+ if (this.specService.currentRunningSpec.error) {
+ messageStack = `${PrintTag.OHOS_REPORT_STATUS}: stack=` + this.specService.currentRunningSpec.error?.stack?.slice(0, -1);
+ messageCode += `${PrintTag.OHOS_REPORT_STATUS}: stream=`;
+ messageCode += this.specService.currentRunningSpec.expectMsg !== '' ?
+ `message: ${this.specService.currentRunningSpec.expectMsg}, Error in ${this.specService.currentRunningSpec.description}, ${this.specService.currentRunningSpec.error?.message}` :
+ `Error in ${this.specService.currentRunningSpec.description}, ${this.specService.currentRunningSpec.error?.message}`;
+ messageCode += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: test=` + this.specService.currentRunningSpec.description;
+ messageCode += '\n' + `${PrintTag.OHOS_REPORT_STATUS_CODE}: -1` + '\n';
+ } else if (this.specService.currentRunningSpec) {
+ if (this.specService.currentRunningSpec.fail) {
+ messageStack += `${PrintTag.OHOS_REPORT_STATUS}: stack=` + this.specService.currentRunningSpec.fail?.stack?.slice(0, -1);
+ messageCode += `${PrintTag.OHOS_REPORT_STATUS}: stream=`;
+ messageCode += this.specService.currentRunningSpec.expectMsg !== '' ?
+ `message: ${this.specService.currentRunningSpec.expectMsg}, Error in ${this.specService.currentRunningSpec.description}, ${this.specService.currentRunningSpec.fail?.message}` :
+ `Error in ${this.specService.currentRunningSpec.description}, ${this.specService.currentRunningSpec.fail?.message}`;
+ messageCode += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: test=` + this.specService.currentRunningSpec.description;
+ messageCode += '\n' + `${PrintTag.OHOS_REPORT_STATUS_CODE}: -2` + '\n';
+ } else {
+ messageStack += `${PrintTag.OHOS_REPORT_STATUS}: stream=`;
+ messageCode += `${PrintTag.OHOS_REPORT_STATUS}: test=` + this.specService.currentRunningSpec.description;
+ messageCode += '\n' + `${PrintTag.OHOS_REPORT_STATUS_CODE}: 0` + '\n';
+ messageCode += this.specService.currentRunningSpec.isSkip ? (`${PrintTag.OHOS_REPORT_STATUS}: skipReason=` + this.specService.currentRunningSpec.skipReason + '\n') : '';
+ }
+ } else {
+ messageCode += '\n';
+ }
+ messageCode += `${PrintTag.OHOS_REPORT_STATUS}: consuming=` + this.specService.currentRunningSpec.duration + '\n';
+ if (SysTestKit.workerPort !== null) {
+ messageCode += `${PrintTag.OHOS_REPORT_STATUS}: currentWorkerName=` + this.currentThreadName;
+ }
+ console.info(`${message}`);
+ console.info(`\n${messageStack}`);
+ console.info(`\n${messageCode}`);
+ await SysTestKit.print(message);
+ await SysTestKit.print(messageStack);
+ await SysTestKit.print(messageCode);
+ console.info(`${TAG}${this.specService.currentRunningSpec.description} specDone end print success`);
+ }
+ }
+}
+
+export default OhReport;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/report/ReportExtend.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/report/ReportExtend.js
new file mode 100644
index 0000000000000000000000000000000000000000..852fbcd5cbf97e776ebe5177a029df0f516594a5
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/module/report/ReportExtend.js
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class ReportExtend {
+ constructor(fileModule) {
+ this.id = 'extend';
+ this.fileModule = fileModule;
+ }
+
+ init(coreContext) {
+ this.coreContext = coreContext;
+ this.suiteService = this.coreContext.getDefaultService('suite');
+ }
+
+ taskStart() {
+
+ }
+
+ taskDone() {
+ const report = {
+ tag: 'testsuites',
+ name: 'summary_report',
+ timestamp: new Date().toDateString(),
+ time: '1',
+ errors: 0,
+ failures: 0,
+ tests: 0,
+ children: []
+ };
+ const rootSuite = this.suiteService.rootSuite;
+ if (rootSuite && rootSuite.childSuites) {
+ for (let testsuite of rootSuite.childSuites) {
+ let suiteReport = {
+ tag: 'testsuite',
+ name: testsuite['description'],
+ errors: 0,
+ tests: 0,
+ failures: 0,
+ time: '0.1',
+ children: []
+ };
+ let specs = testsuite['specs'];
+ for (let testcase of specs) {
+ report.tests++;
+ suiteReport.tests++;
+ let caseReport = {
+ tag: 'testcase',
+ name: testcase['description'],
+ status: 'run',
+ time: '0.0',
+ classname: testsuite['description']
+ };
+ if (testcase.error) {
+ caseReport['result'] = false;
+ caseReport['children'] = [{
+ tag: 'error',
+ type: '',
+ message: testcase.error.message
+ }];
+ report.errors++;
+ suiteReport.errors++;
+ } else if (testcase.result.failExpects.length > 0) {
+ caseReport['result'] = false;
+ let message = '';
+ testcase.result.failExpects.forEach(failExpect => {
+ message += failExpect.message || ('expect ' + failExpect.actualValue + ' ' + failExpect.checkFunc + ' ' + (failExpect.expectValue || '')) + ';';
+ });
+ caseReport['children'] = [{
+ tag: 'failure',
+ type: '',
+ message: message
+ }];
+ report.failures++;
+ suiteReport.failures++;
+ } else {
+ caseReport['result'] = true;
+ }
+ suiteReport.children.push(caseReport);
+ }
+ report.children.push(suiteReport);
+ }
+ }
+
+ let reportXml = '\n' + json2xml(report);
+ this.fileModule.writeText({
+ uri: 'internal://app/report.xml',
+ text: reportXml,
+ success: function () {
+ console.info('call success callback success');
+ },
+ fail: function (data, code) {
+ console.info('call fail callback success:');
+ },
+ complete: function () {
+ console.info('call complete callback success');
+ }
+ });
+ }
+}
+
+function json2xml(json) {
+ let tagName;
+ let hasChildren = false;
+ let childrenStr = '';
+ let attrStr = '';
+ for (let key in json) {
+ if (key === 'tag') {
+ tagName = json[key];
+ } else if (key === 'children') {
+ if (json[key].length > 0) {
+ hasChildren = true;
+ for (let child of json[key]) {
+ childrenStr += json2xml(child);
+ }
+ }
+ } else {
+ attrStr += ` ${key}="${json[key]}"`;
+ }
+ }
+ let xml = `<${tagName}${attrStr}`;
+ xml += hasChildren ? `>${childrenStr}${tagName}>` : '/>';
+ return xml;
+}
+
+export default ReportExtend;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/service.js b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/service.js
new file mode 100644
index 0000000000000000000000000000000000000000..92d46b77959af314f40bd601ede62b9b6d8b9ba2
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/service.js
@@ -0,0 +1,1230 @@
+/*
+ * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import SysTestKit from './module/kit/SysTestKit';
+import { TAG } from './Constant';
+import LogExpectError from './module/report/LogExpectError';
+import { NestFilter } from './module/config/Filter';
+
+class AssertException extends Error {
+ constructor(message) {
+ super();
+ this.name = 'AssertException';
+ this.message = message;
+ }
+}
+
+function getFuncWithArgsZero(func, timeout, isStressTest) {
+ return new Promise(async (resolve, reject) => {
+ let timer = null;
+ if (!isStressTest) {
+ timer = setTimeout(() => {
+ reject(new Error('execute timeout ' + timeout + 'ms'));
+ }, timeout);
+ }
+ try {
+ await func();
+ } catch (err) {
+ reject(err);
+ }
+ timer !== null ? clearTimeout(timer) : null;
+ resolve();
+ });
+}
+
+function getFuncWithArgsOne(func, timeout, isStressTest) {
+ return new Promise(async (resolve, reject) => {
+ let timer = null;
+ if (!isStressTest) {
+ timer = setTimeout(() => {
+ reject(new Error('execute timeout ' + timeout + 'ms'));
+ }, timeout);
+ }
+
+ function done() {
+ timer !== null ? clearTimeout(timer) : null;
+ resolve();
+ }
+
+ try {
+ await func(done);
+ } catch (err) {
+ timer !== null ? clearTimeout(timer) : null;
+ reject(err);
+ }
+ });
+}
+
+function getFuncWithArgsTwo(func, timeout, paramItem, isStressTest) {
+ return new Promise(async (resolve, reject) => {
+ let timer = null;
+ if (!isStressTest) {
+ timer = setTimeout(() => {
+ reject(new Error('execute timeout ' + timeout + 'ms'));
+ }, timeout);
+ }
+
+ function done() {
+ timer !== null ? clearTimeout(timer) : null;
+ resolve();
+ }
+
+ try {
+ await func(done, paramItem);
+ } catch (err) {
+ timer !== null ? clearTimeout(timer) : null;
+ reject(err);
+ }
+ });
+}
+
+function processFunc(coreContext, func) {
+ let argNames = ((func || '').toString()
+ .replace(/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg, '')
+ .match(/^(function)?\s*[^\(]*\(\s*([^\)]*)\)/m) || ['', '', ''])[2]
+ .split(',') // split parameters
+ .map(item => item.replace(/^\s*(_?)(.+?)\1\s*$/, name => name.split('=')[0].trim()))
+ .filter(String);
+ let funcLen = func.length;
+ let processedFunc;
+ const config = coreContext.getDefaultService('config');
+ config.setSupportAsync(true);
+ const timeout = + (config.timeout === undefined ? 5000 : config.timeout);
+ const isStressTest = (coreContext.getServices('dataDriver') !== undefined || config.getStress() > 1);
+ switch (funcLen) {
+ case 0: {
+ processedFunc = function () {
+ return getFuncWithArgsZero(func, timeout, isStressTest);
+ };
+ break;
+ }
+ case 1: {
+ if (argNames[0] === 'data') {
+ processedFunc = function (paramItem) {
+ func(paramItem);
+ };
+ } else {
+ processedFunc = function () {
+ return getFuncWithArgsOne(func, timeout, isStressTest);
+ };
+ }
+ break;
+ }
+ default: {
+ processedFunc = function (paramItem) {
+ return getFuncWithArgsTwo(func, timeout, paramItem, isStressTest);
+ };
+ break;
+ }
+ }
+ return processedFunc;
+}
+
+function secureRandomNumber() {
+ return crypto.randomBytes(8).readUInt32LE() / 0xffffffff;
+}
+
+class SuiteService {
+ constructor(attr) {
+ this.id = attr.id;
+ this.rootSuite = new SuiteService.Suite({});
+ this.currentRunningSuite = this.rootSuite;
+ this.suitesStack = [this.rootSuite];
+ this.targetSuiteArray = [];
+ this.targetSpecArray = [];
+ this.currentRunningSuiteDesc = null;
+ this.fullRun = false;
+ this.isSkipSuite = false;
+ this.suiteSkipReason = null;
+ }
+
+ describe(desc, func) {
+ const configService = this.coreContext.getDefaultService('config');
+ if (this.suitesStack.some(suite => { return suite.description === desc })) {
+ console.error(`${TAG} Loop nesting occurs : ${desc}`);
+ this.suiteSkipReason = '';
+ this.isSkipSuite = false;
+ return;
+ }
+ let isFilter = this.analyzeConfigServiceClass(configService.class, desc);
+ if (configService.filterSuite(desc) && isFilter) {
+ if (this.currentRunningSuite.description === '' || this.currentRunningSuite.description == null) {
+ console.info(`${TAG}filter suite : ${desc}`);
+ this.suiteSkipReason = '';
+ this.isSkipSuite = false;
+ return;
+ }
+ }
+ const suite = new SuiteService.Suite({ description: desc });
+ if (this.isSkipSuite) {
+ suite.isSkip = true;
+ suite.skipReason = this.suiteSkipReason;
+ }
+ this.suiteSkipReason = '';
+ this.isSkipSuite = false;
+ if (typeof this.coreContext.getServices('dataDriver') !== 'undefined' && configService['dryRun'] !== 'true') {
+ let suiteStress = this.coreContext.getServices('dataDriver').dataDriver.getSuiteStress(desc);
+ for (let i = 1; i < suiteStress; i++) {
+ this.currentRunningSuite.childSuites.push(suite);
+ }
+ }
+ this.currentRunningSuite.childSuites.push(suite);
+ this.currentRunningSuite = suite;
+ this.suitesStack.push(suite);
+ func.call();
+ this.suitesStack.pop();
+ this.currentRunningSuite = this.suitesStack.pop();
+ this.suitesStack.push(this.currentRunningSuite);
+ }
+ xdescribe(desc, func, reason) {
+ const configService = this.coreContext.getDefaultService('config');
+ if (!configService.skipMessage && configService.runSkipped !== 'all') {
+ if (configService.runSkipped != null && configService.runSkipped !== '') {
+ let finalDesc = '';
+ this.suitesStack.map(suite => {
+ finalDesc = finalDesc + '.' + suite.description;
+ });
+ finalDesc = (finalDesc + '.' + desc).substring(2);
+ console.info(`${TAG} finalDesc ${finalDesc}`);
+ if (configService.checkIfSuiteInSkipRun(finalDesc)) {
+ console.info(`${TAG} runSkipped suite: ${desc}`);
+ } else {
+ console.info(reason == null ? `${TAG} skip suite: ${desc}` : `${TAG} skip suite: ${desc}, and the reason is ${reason}`);
+ return;
+ }
+ } else {
+ console.info(reason == null ? `${TAG} skip suite: ${desc}` : `${TAG} skip suite: ${desc}, and the reason is ${reason}`);
+ return;
+ }
+ }
+ this.isSkipSuite = true;
+ this.suiteSkipReason = reason;
+ this.describe(desc, func);
+ }
+
+ beforeAll(func) {
+ this.currentRunningSuite.beforeAll.push(processFunc(this.coreContext, func));
+ }
+
+ beforeEach(func) {
+ this.currentRunningSuite.beforeEach.push(processFunc(this.coreContext, func));
+ }
+
+ beforeItSpecified(itDescs, func) {
+ this.currentRunningSuite.beforeItSpecified.set(itDescs, processFunc(this.coreContext, func));
+ }
+
+ afterItSpecified(itDescs, func) {
+ this.currentRunningSuite.afterItSpecified.set(itDescs, processFunc(this.coreContext, func));
+ }
+
+ afterAll(func) {
+ this.currentRunningSuite.afterAll.push(processFunc(this.coreContext, func));
+ }
+
+ afterEach(func) {
+ this.currentRunningSuite.afterEach.push(processFunc(this.coreContext, func));
+ }
+
+ getCurrentRunningSuite() {
+ return this.currentRunningSuite;
+ }
+
+ setCurrentRunningSuite(suite) {
+ this.currentRunningSuite = suite;
+ }
+
+ getRootSuite() {
+ return this.rootSuite;
+ }
+
+ getCurrentRunningSuiteDesc() {
+ return this.currentRunningSuiteDesc;
+ }
+
+
+ setCurrentRunningSuiteDesc(suite, currentSuite, prefix) {
+ if (suite != null && suite === currentSuite) {
+ this.currentRunningSuiteDesc = prefix;
+ } else if (suite != null && suite !== currentSuite) {
+ suite.childSuites.forEach(it => {
+ let temp = prefix;
+ if (it.description != null || it.description !== '') {
+ temp = prefix === '' ? it.description : prefix + '.' + it.description;
+ }
+ this.setCurrentRunningSuiteDesc(it, currentSuite, temp);
+ }
+ );
+ }
+ }
+ analyzeConfigServiceClass(configServiceClass, desc) {
+ if (configServiceClass == null || configServiceClass === '') {
+ this.fullRun = true
+ return false;
+ }
+ if (this.targetSuiteArray.length === 0) {
+ const targetArray = configServiceClass.split(',');
+ for (let index in targetArray) {
+ if (targetArray[index].includes('#')) {
+ this.targetSpecArray.push(targetArray[index]);
+ } else {
+ this.targetSuiteArray.push(targetArray[index]);
+ }
+ }
+
+ }
+ return !configServiceClass.includes(desc);
+
+ }
+ traversalResults(suite, obj, breakOnError) {
+ if (suite.childSuites.length === 0 && suite.specs.length === 0) {
+ return obj;
+ }
+ if (suite.specs.length > 0) {
+ for (const itItem of suite.specs) {
+ obj.total++;
+ let itInfo = {
+ currentThreadName: 'mainThread',
+ description: suite.description + '#' + itItem.description,
+ result: -3
+ };
+ if (SysTestKit.workerPort !== null) {
+ itInfo.currentThreadName = SysTestKit.workerPort.name;
+ }
+ obj.itItemList.push(itInfo);
+ if (breakOnError && (obj.error > 0 || obj.failure > 0)) { // breakOnError模式
+ continue;
+ }
+ if (itItem.error) {
+ obj.error++;
+ itInfo.result = -1;
+ } else if (itItem.fail) {
+ obj.failure++;
+ itInfo.result = -2;
+ } else if (itItem.pass === true) {
+ obj.pass++;
+ itInfo.result = 0;
+ }
+ }
+ }
+
+ obj.duration += suite.duration;
+
+ if (suite.childSuites.length > 0) {
+ for (const suiteItem of suite.childSuites) {
+ this.traversalResults(suiteItem, obj, breakOnError);
+ }
+ }
+ }
+
+ async setSuiteResults(suite, error, coreContext) {
+ if (suite.childSuites.length === 0 && suite.specs.length === 0) {
+ return obj;
+ }
+ if (suite.specs.length > 0) {
+ const specService = coreContext.getDefaultService('spec');
+ for (const specItem of suite.specs) {
+ specService.setCurrentRunningSpec(specItem);
+ if (error instanceof AssertException) {
+ specItem.fail = error;
+ } else {
+ specItem.error = error;
+ }
+ await coreContext.fireEvents('spec', 'specStart', specItem);
+ await coreContext.fireEvents('spec', 'specDone', specItem);
+ }
+ }
+ if (suite.childSuites.length > 0) {
+ for (const suiteItem of suite.childSuites) {
+ await this.setSuiteResults(suiteItem, error, coreContext);
+ }
+ }
+ }
+
+ getSummary() {
+ let suiteService = this.coreContext.getDefaultService('suite');
+ let rootSuite = suiteService.rootSuite;
+ const specService = this.coreContext.getDefaultService('spec');
+ const configService = this.coreContext.getDefaultService('config');
+ let breakOnError = configService.isBreakOnError();
+ let isError = specService.getStatus();
+ let isBreaKOnError = breakOnError && isError;
+ // itItemList 保存当前用例执行情况, 发送到主线程用例计算最终结果
+ let obj = { total: 0, failure: 0, error: 0, pass: 0, ignore: 0, duration: 0, itItemList: []};
+ for (const suiteItem of rootSuite.childSuites) {
+ this.traversalResults(suiteItem, obj, isBreaKOnError);
+ }
+ obj.ignore = obj.total - obj.pass - obj.failure - obj.error;
+ return obj;
+ }
+
+ init(coreContext) {
+ this.coreContext = coreContext;
+ }
+
+ traversalSuites(suite, obj, configService) {
+ if (suite.childSuites.length === 0 && suite.specs.length === 0) {
+ return [];
+ }
+ if (suite.specs.length > 0) {
+ let itArray = [];
+ for (const itItem of suite['specs']) {
+ if (!configService.filterDesc(suite.description, itItem.description, itItem.fi, null)) {
+ itArray.push({ 'itName': itItem.description });
+ }
+ }
+ obj[suite.description] = itArray;
+ }
+ if (suite.childSuites.length > 0) {
+ let suiteArray = [];
+ for (const suiteItem of suite.childSuites) {
+ let suiteObj = {};
+ this.traversalSuites(suiteItem, suiteObj, configService);
+ if (!configService.filterSuite(suiteItem.description)) {
+ suiteArray.push(suiteObj);
+ }
+ }
+ obj.suites = suiteArray;
+ }
+ }
+
+ async dryRun(abilityDelegator) {
+ console.info(`${TAG} rootSuite : ` + JSON.stringify(this.rootSuite));
+ let obj = this.rootSuite;
+ let prefixStack = [];
+ let suiteArray = [];
+ let skipSuiteArray = [];
+ this.analyzeSuitesArray(prefixStack, suiteArray, skipSuiteArray, obj);
+ const configService = this.coreContext.getDefaultService('config');
+ let result;
+ if (configService.skipMessage) {
+ result = { 'suites': suiteArray, 'skipSuites': skipSuiteArray };
+ } else {
+ result = { 'suites': suiteArray };
+ }
+ let strJson = JSON.stringify(result);
+ let strLen = strJson.length;
+ let maxLen = 500;
+ let maxCount = Math.floor(strLen / maxLen);
+ for (let count = 0; count <= maxCount; count++) {
+ await SysTestKit.print(strJson.substring(count * maxLen, (count + 1) * maxLen));
+ }
+ console.info(`${TAG}dryRun print success`);
+ abilityDelegator.finishTest('dry run finished!!!', 0, () => { });
+ }
+
+ //将suitesArray的嵌套结构展开成三层结构
+ analyzeSuitesArray(prefixStack, suiteArray, skipSuiteArray, obj) {
+ obj.childSuites.map(suite => {
+ if (suite.description != null && suite.description !== '') {
+ let prefix = '';
+ if (prefixStack.length > 0) {
+ prefix = prefixStack.join('.') + '.' + suite.description;
+ } else {
+ prefix = suite.description;
+ }
+ prefixStack.push(suite.description);
+ let temp = {};
+ temp[prefix] = [];
+ let skipTemp = {};
+ skipTemp[prefix] = [];
+ suite.specs.map(spec => {
+ let it = { 'itName': spec.description };
+ spec.isSkip ? skipTemp[prefix].push(it) : temp[prefix].push(it);
+ });
+ suiteArray.push(temp);
+ skipSuiteArray.push(skipTemp);
+ }
+ this.analyzeSuitesArray(prefixStack, suiteArray, skipSuiteArray, suite);
+ prefixStack.pop();
+ });
+ }
+ //获取当前测试套下的所有测试用例数量
+ getAllChildSuiteNum(suite, specArray) {
+ if (suite.specs != null) {
+ suite.specs.forEach(spec => specArray.push(spec));
+ }
+ if (suite.childSuites != null) {
+ suite.childSuites.forEach(it => this.getAllChildSuiteNum(it, specArray));
+ }
+ }
+
+ execute() {
+ const configService = this.coreContext.getDefaultService('config');
+ if (configService.filterValid.length !== 0) {
+ this.coreContext.fireEvents('task', 'incorrectFormat');
+ return;
+ }
+ if (configService.filterXdescribe.length !== 0) {
+ this.coreContext.fireEvents('task', 'incorrectTestSuiteFormat');
+ return;
+ }
+ if (configService.isRandom() && this.rootSuite.childSuites.length > 0) {
+ this.rootSuite.childSuites.sort(function () {
+ return Math.random().toFixed(1) > 0.5 ? -1 : 1;
+ });
+ this.currentRunningSuite = this.rootSuite.childSuites[0];
+ }
+ if (configService.isSupportAsync()) {
+ console.info(`${TAG} rootSuite:` + JSON.stringify(this.rootSuite));
+ let asyncExecute = async () => {
+ await this.coreContext.fireEvents('task', 'taskStart');
+ await this.rootSuite.asyncRun(this.coreContext);
+ };
+ asyncExecute().then(async () => {
+ await this.coreContext.fireEvents('task', 'taskDone');
+ });
+ } else {
+ console.info('${TAG} rootSuite:' + JSON.stringify(this.rootSuite));
+ this.coreContext.fireEvents('task', 'taskStart');
+ this.rootSuite.run(this.coreContext);
+ this.coreContext.fireEvents('task', 'taskDone');
+ }
+ }
+
+ apis() {
+ const _this = this;
+ return {
+ describe: function (desc, func) {
+ return _this.describe(desc, func);
+ },
+ xdescribe: function (desc, func, reason) {
+ return _this.xdescribe(desc, func, reason);
+ },
+ beforeItSpecified: function (itDescs, func) {
+ return _this.beforeItSpecified(itDescs, func);
+ },
+ afterItSpecified: function (itDescs, func) {
+ return _this.afterItSpecified(itDescs, func);
+ },
+ beforeAll: function (func) {
+ return _this.beforeAll(func);
+ },
+ beforeEach: function (func) {
+ return _this.beforeEach(func);
+ },
+ afterAll: function (func) {
+ return _this.afterAll(func);
+ },
+ afterEach: function (func) {
+ return _this.afterEach(func);
+ }
+ };
+ }
+}
+
+SuiteService.Suite = class {
+ constructor(attrs) {
+ this.description = attrs.description || '';
+ this.childSuites = [];
+ this.specs = [];
+ this.beforeAll = [];
+ this.afterAll = [];
+ this.beforeItSpecified = new Map();
+ this.afterItSpecified = new Map();
+ this.beforeEach = [];
+ this.afterEach = [];
+ this.duration = 0;
+ this.hookError = null;
+ this.isSkip = false;
+ this.skipReason = '';
+ }
+
+ pushSpec(spec) {
+ this.specs.push(spec);
+ }
+
+ removeSpec(desc) {
+ this.specs = this.specs.filter((item, index) => {
+ return item.description !== desc;
+ });
+ }
+
+ getSpecsNum() {
+ return this.specs.length;
+ }
+
+ isRun(coreContext) {
+ const configService = coreContext.getDefaultService('config');
+ const suiteService = coreContext.getDefaultService('suite');
+ const specService = coreContext.getDefaultService('spec');
+ let breakOnError = configService.isBreakOnError();
+ let isError = specService.getStatus();
+ return breakOnError && isError;
+ }
+
+ run(coreContext) {
+ const suiteService = coreContext.getDefaultService('suite');
+ suiteService.setCurrentRunningSuite(this);
+ if (this.description !== '') {
+ coreContext.fireEvents('suite', 'suiteStart', this);
+ }
+ this.runHookFunc('beforeAll');
+ if (this.specs.length > 0) {
+ const configService = coreContext.getDefaultService('config');
+ if (configService.isRandom()) {
+ this.specs.sort(function () {
+ return Math.random().toFixed(1) > 0.5 ? -1 : 1;
+ });
+ }
+ for (let spec in this.specs) {
+ let isBreakOnError = this.isRun(coreContext);
+ if (isBreakOnError) {
+ break;
+ }
+ this.runHookFunc('beforeEach');
+ spec.run(coreContext);
+ this.runHookFunc('afterEach');
+ }
+ }
+ if (this.childSuites.length > 0) {
+ for (let suite in this.childSuites) {
+ let isBreakOnError = this.isRun(coreContext);
+ if (isBreakOnError) {
+ break;
+ }
+ suite.run(coreContext);
+ suiteService.setCurrentRunningSuite(suite);
+ }
+ }
+ this.runHookFunc('afterAll');
+ if (this.description !== '') {
+ coreContext.fireEvents('suite', 'suiteDone');
+ }
+ }
+
+ async asyncRunSpecs(coreContext) {
+ const configService = coreContext.getDefaultService('config');
+ if (configService.isRandom()) {
+ this.specs.sort(function () {
+ return Math.random().toFixed(1) > 0.5 ? -1 : 1;
+ });
+ }
+ const specService = coreContext.getDefaultService('spec');
+ for (let specItem of this.specs) {
+ specService.setCurrentRunningSpec(specItem);
+ // 遇错即停模式,发现用例有问题,直接返回,不在执行后面的it
+ let isBreakOnError = this.isRun(coreContext);
+ if (isBreakOnError) {
+ console.info('break description :' + this.description);
+ break;
+ }
+ await coreContext.fireEvents('spec', 'specStart', specItem);
+ try {
+ for (const [itNames, hookFunc] of this.beforeItSpecified) {
+ if ((Object.prototype.toString.call(itNames) === '[object Array]' && itNames.includes(specItem.description)) ||
+ (Object.prototype.toString.call(itNames) === '[object String]' && itNames === specItem.description)) {
+ await Reflect.apply(hookFunc, null, []);
+ }
+ break;
+ }
+ await this.runAsyncHookFunc('beforeEach');
+ await specItem.asyncRun(coreContext);
+ for (const [itNames, hookFunc] of this.afterItSpecified) {
+ if ((Object.prototype.toString.call(itNames) === '[object Array]' && itNames.includes(specItem.description)) ||
+ (Object.prototype.toString.call(itNames) === '[object String]' && itNames === specItem.description)) {
+ await Reflect.apply(hookFunc, null, []);
+ }
+ break;
+ }
+ await this.runAsyncHookFunc('afterEach');
+ } catch (e) {
+ console.error(`${TAG}stack:${e?.stack}`);
+ console.error(`${TAG}stack end`);
+ if (e instanceof AssertException) {
+ specItem.fail = e;
+ } else {
+ specItem.error = e;
+ }
+ specService.setStatus(true);
+ }
+ specItem.setResult();
+ await coreContext.fireEvents('spec', 'specDone', specItem);
+ specService.setCurrentRunningSpec(null);
+ }
+ }
+
+ async asyncRunChildSuites(coreContext) {
+ for (let i = 0; i < this.childSuites.length; i++) {
+ // 遇错即停模式, 发现用例有问题,直接返回,不在执行后面的description
+ let isBreakOnError = this.isRun(coreContext);
+ if (isBreakOnError) {
+ console.info(`${TAG}break description : ${this.description}`);
+ break;
+ }
+ await this.childSuites[i].asyncRun(coreContext);
+ }
+ }
+
+ async asyncRun(coreContext) {
+ const suiteService = coreContext.getDefaultService('suite');
+ const specService = coreContext.getDefaultService('spec');
+
+ suiteService.setCurrentRunningSuite(this);
+ suiteService.suitesStack.push(this);
+ if (this.description !== '') {
+ await coreContext.fireEvents('suite', 'suiteStart', this);
+ }
+
+ try {
+ await this.runAsyncHookFunc('beforeAll');
+ } catch (error) {
+ console.error(`${TAG}${error?.stack}`);
+ this.hookError = error;
+ }
+
+ if (this.hookError !== null) {
+ specService.setStatus(true);
+ await suiteService.setSuiteResults(this, this.hookError, coreContext);
+ }
+
+ if (this.specs.length > 0 && this.hookError === null) {
+ await this.asyncRunSpecs(coreContext);
+ }
+
+ if (this.childSuites.length > 0 && this.hookError === null) {
+ await this.asyncRunChildSuites(coreContext);
+ }
+
+ try {
+ await this.runAsyncHookFunc('afterAll');
+ } catch (error) {
+ console.error(`${TAG}${error?.stack}`);
+ this.hookError = error;
+ specService.setStatus(true);
+ }
+
+ if (this.description !== '') {
+ await coreContext.fireEvents('suite', 'suiteDone');
+ let childSuite = suiteService.suitesStack.pop();
+ let currentRunningSuite = suiteService.suitesStack.pop();
+ suiteService.setCurrentRunningSuite(currentRunningSuite);
+ suiteService.suitesStack.push(currentRunningSuite);
+ }
+ }
+
+ runHookFunc(hookName) {
+ if (this[hookName] && this[hookName].length > 0) {
+ this[hookName].forEach(func => {
+ try {
+ func();
+ } catch (e) {
+ console.error(`${TAG}${e.stack}`);
+ }
+ });
+ }
+ }
+
+ async runAsyncHookFunc(hookName) {
+ for (const hookItem of this[hookName]) {
+ try {
+ await hookItem();
+ } catch (error) {
+ error['message'] += `, error in ${hookName} function`;
+ throw error;
+ }
+
+ }
+ }
+};
+
+class SpecService {
+ constructor(attr) {
+ this.id = attr.id;
+ this.totalTest = 0;
+ this.hasError = false;
+ this.skipSpecNum = 0;
+ this.isSkipSpec = false;
+ this.specSkipReason = '';
+ }
+
+ init(coreContext) {
+ this.coreContext = coreContext;
+ }
+
+ setCurrentRunningSpec(spec) {
+ this.currentRunningSpec = spec;
+ }
+
+ setStatus(obj) {
+ this.hasError = obj;
+ }
+
+ getStatus() {
+ return this.hasError;
+ }
+
+ getTestTotal() {
+ return this.totalTest;
+ }
+
+ getCurrentRunningSpec() {
+ return this.currentRunningSpec;
+ }
+
+
+ getSkipSpecNum() {
+ return this.skipSpecNum;
+ }
+
+ initSpecService() {
+ this.isSkipSpec = false;
+ this.specSkipReason = '';
+ }
+
+ it(desc, filter, func) {
+ const suiteService = this.coreContext.getDefaultService('suite');
+ const configService = this.coreContext.getDefaultService('config');
+ let isFilter = new NestFilter().filterNestName(suiteService.targetSuiteArray, suiteService.targetSpecArray, suiteService.suitesStack, desc);
+ if (configService.filterWithNest(desc, filter)) {
+ console.info(`${TAG}filter it :${desc}`);
+ this.initSpecService();
+ return;
+ }
+ if (configService.filterDesc(suiteService.currentRunningSuite.description, desc, filter, this.coreContext) && isFilter && !suiteService.fullRun) {
+ console.info(`${TAG}filter it :${desc}`);
+ this.initSpecService();
+ } else {
+ let processedFunc = processFunc(this.coreContext, func);
+ const spec = new SpecService.Spec({ description: desc, fi: filter, fn: processedFunc });
+ if (this.isSkipSpec) {
+ spec.isSkip = true;
+ spec.skipReason = this.specSkipReason;
+ }
+ this.initSpecService();
+ if (configService.runSkipped === 'skipped' && !spec.isSkip) {
+ console.info(`${TAG} runSkipped is skipped , just run xit, don't run it: ${spec.description}`);
+ return;
+ }
+ if (suiteService.getCurrentRunningSuite().isSkip && !spec.isSkip) {
+ configService.filterXdescribe.push(suiteService.getCurrentRunningSuite().description);
+ }
+ if (typeof this.coreContext.getServices('dataDriver') !== 'undefined' && configService['dryRun'] !== 'true') {
+ let specStress = this.coreContext.getServices('dataDriver').dataDriver.getSpecStress(desc);
+ for (let i = 1; i < specStress; i++) {
+ this.totalTest++;
+ suiteService.getCurrentRunningSuite().pushSpec(spec);
+ }
+ }
+ // dryRun 状态下不统计压力测试重复数据
+ if (configService['dryRun'] !== 'true') {
+ let stress = configService.getStress(); // 命令配置压力测试
+ console.info(`${TAG}stress length : ${stress}`);
+ for (let i = 1; i < stress; i++) {
+ this.totalTest++;
+ suiteService.getCurrentRunningSuite().pushSpec(spec);
+ }
+ }
+ this.totalTest++;
+ suiteService.getCurrentRunningSuite().pushSpec(spec);
+ }
+ }
+
+ xit(desc, filter, func, reason) {
+ const configService = this.coreContext.getDefaultService('config');
+ const suiteService = this.coreContext.getDefaultService('suite');
+ if (!configService.skipMessage && configService.runSkipped !== 'all') {
+ if (configService.runSkipped != null && configService.runSkipped !== '') {
+ let finalDesc = '';
+ suiteService.suitesStack.map(suite => {
+ finalDesc = finalDesc + '.' + suite.description;
+ });
+ finalDesc = (finalDesc + '#' + desc).substring(2);
+ if (configService.checkIfSpecInSkipRun(finalDesc)) {
+ console.info(`${TAG} runSkipped spec: ${desc}`);
+ } else {
+ console.info(reason == null ? `${TAG} skip spec: ${desc}` : `${TAG} skip spec: ${desc}, and the reason is ${reason}`);
+ return;
+ }
+ } else {
+ console.info(reason == null ? `${TAG} skip spec: ${desc}` : `${TAG} skip spec: ${desc}, and the reason is ${reason}`);
+ return;
+ }
+ }
+ this.skipSpecNum++;
+ this.isSkipSpec = true;
+ this.specSkipReason = reason;
+ this.it(desc, filter, func);
+ }
+
+ apis() {
+ const _this = this;
+ return {
+ it: function (desc, filter, func) {
+ return _this.it(desc, filter, func);
+ },
+ xit: function (desc, filter, func, reason) {
+ return _this.xit(desc, filter, func, reason);
+ }
+ };
+ }
+}
+
+SpecService.Spec = class {
+ constructor(attrs) {
+ this.description = attrs.description || '';
+ this.fi = attrs.fi;
+ this.fn = attrs.fn || function () {
+ };
+ this.fail = undefined;
+ this.error = undefined;
+ this.duration = 0;
+ this.startTime = 0;
+ this.isExecuted = false; // 当前用例是否执行
+ this.isSkip = false;
+ this.skipReason = '';
+ this.expectMsg = '';
+ }
+
+ setResult() {
+ if (this.fail) {
+ this.pass = false;
+ } else {
+ this.pass = true;
+ }
+ }
+
+ run(coreContext) {
+ const specService = coreContext.getDefaultService('spec');
+ specService.setCurrentRunningSpec(this);
+ coreContext.fireEvents('spec', 'specStart', this);
+ this.isExecuted = true;
+ try {
+ let dataDriver = coreContext.getServices('dataDriver');
+ if (typeof dataDriver === 'undefined') {
+ this.fn();
+ } else {
+ let suiteParams = dataDriver.dataDriver.getSuiteParams();
+ let specParams = dataDriver.dataDriver.getSpecParams();
+ console.info(`${TAG}[suite params] ${JSON.stringify(suiteParams)}`);
+ console.info(`${TAG}[spec params] ${JSON.stringify(specParams)}`);
+ if (this.fn.length === 0) {
+ this.fn();
+ } else if (specParams.length === 0) {
+ this.fn(suiteParams);
+ } else {
+ specParams.forEach(paramItem => this.fn(Object.assign({}, paramItem, suiteParams)));
+ }
+ }
+ this.setResult();
+ } catch (e) {
+ this.error = e;
+ specService.setStatus(true);
+ }
+ coreContext.fireEvents('spec', 'specDone', this);
+ }
+
+ async asyncRun(coreContext) {
+ const dataDriver = coreContext.getServices('dataDriver');
+ if (typeof dataDriver === 'undefined') {
+ await this.fn();
+ } else {
+ const suiteParams = dataDriver.dataDriver.getSuiteParams();
+ const specParams = dataDriver.dataDriver.getSpecParams();
+ console.info(`[suite params] ${JSON.stringify(suiteParams)}`);
+ console.info(`[spec params] ${JSON.stringify(specParams)}`);
+ if (this.fn.length === 0) {
+ await this.fn();
+ } else if (specParams.length === 0) {
+ await this.fn(suiteParams);
+ } else {
+ for (const paramItem of specParams) {
+ await this.fn(Object.assign({}, paramItem, suiteParams));
+ }
+ }
+ }
+
+ this.isExecuted = true;
+ }
+
+ filterCheck(coreContext) {
+ const specService = coreContext.getDefaultService('spec');
+ specService.setCurrentRunningSpec(this);
+ return true;
+ }
+};
+
+class ExpectService {
+ constructor(attr) {
+ this.id = attr.id;
+ this.matchers = {};
+ this.customMatchers = [];
+ }
+
+ expect(actualValue) {
+ return this.wrapMatchers(actualValue);
+ }
+
+ init(coreContext) {
+ this.coreContext = coreContext;
+ this.addMatchers(this.basicMatchers());
+ }
+
+ addMatchers(matchers) {
+ for (const matcherName in matchers) {
+ if (Object.prototype.hasOwnProperty.call(matchers, matcherName)) {
+ this.matchers[matcherName] = matchers[matcherName];
+ }
+ }
+ }
+
+ removeMatchers(customAssertionName) {
+ if (customAssertionName === 'all') {
+ for (const matcherName in this.matchers) {
+ this.matchers[matcherName] = this.customMatchers.includes(matcherName) ? (() => {throw new Error(`${matcherName} is unregistered`)}) : undefined;
+ }
+ }else {
+ this.matchers[customAssertionName] = () => {
+ throw new Error(`${customAssertionName} is unregistered`)
+ };
+ }
+ }
+
+ basicMatchers() {
+ return {
+ assertTrue: function (actualValue) {
+ return {
+ pass: (actualValue) === true,
+ message: 'expect true, actualValue is ' + actualValue
+ };
+ },
+ assertEqual: function (actualValue, args) {
+ let msg = 'expect ' + actualValue + ' equals ' + args[0];
+ if (actualValue == args[0]) { // 数值相同,提示数据类型
+ const aClassName = Object.prototype.toString.call(actualValue);
+ const bClassName = Object.prototype.toString.call(args[0]);
+ msg = 'expect ' + actualValue + aClassName + ' equals ' + args[0] + bClassName + 'strict mode inspect type';
+ }
+ return {
+ pass: (actualValue) === args[0],
+ expectValue: args[0],
+ message: msg
+ };
+ },
+ assertThrow: function (actual, args) {
+ const result = {
+ pass: false
+ };
+ if (typeof actual !== 'function') {
+ result.message = 'toThrow\'s Actual should be a Function';
+ } else {
+ let hasThrow = false;
+ let throwError;
+ try {
+ actual();
+ } catch (e) {
+ hasThrow = true;
+ throwError = e;
+ }
+ if (!hasThrow) {
+ result.message = 'function did not throw an exception';
+ } else if (throwError && throwError.message === args[0]) {
+ result.pass = true;
+ } else {
+ result.message = `expect to throw ${args[0]} , actual throw ${throwError.message}`;
+ }
+ }
+ return result;
+ }
+ };
+ }
+
+ initWrapMatchers(currentRunningSpec) {
+ return {
+ // 翻转标识
+ isNot: false,
+ // 翻转方法
+ not: function () {
+ this.isNot = true;
+ return this;
+ },
+ message: function (msg) {
+ currentRunningSpec.expectMsg = msg;
+ console.info(`${TAG} msg: ${msg}`);
+ return this;
+ }
+ };
+
+ }
+ wrapMatchers(actualValue) {
+ const _this = this;
+ const specService = _this.coreContext.getDefaultService('spec');
+ const currentRunningSpec = specService.getCurrentRunningSpec();
+ const wrappedMatchers = this.initWrapMatchers(currentRunningSpec);
+ const currentRunningSuite = _this.coreContext.getDefaultService('suite').getCurrentRunningSuite();
+ for (const matcherName in this.matchers) {
+ let result = Object.prototype.hasOwnProperty.call(this.matchers, matcherName);
+ if (!result) {
+ continue;
+ }
+ if (matcherName.search('assertPromise') == 0) {
+ wrappedMatchers[matcherName] = async function () {
+ await _this.matchers[matcherName](actualValue, arguments).then(function (result) {
+ if (wrappedMatchers.isNot) {
+ result.pass = !result.pass;
+ }
+ result.actualValue = actualValue;
+ result.checkFunc = matcherName;
+ if (!result.pass) {
+ const assertError = new AssertException(result.message);
+ currentRunningSpec ? currentRunningSpec.fail = assertError : currentRunningSuite.hookError = assertError;
+ throw assertError;
+ }
+ });
+ };
+ } else {
+ wrappedMatchers[matcherName] = function () {
+ const result = _this.customMatchers.includes(matcherName) ? _this.matchers[matcherName](actualValue, arguments[0]) : _this.matchers[matcherName](actualValue, arguments);
+ if (wrappedMatchers.isNot) {
+ result.pass = !result.pass;
+ result.message = LogExpectError.getErrorMsg(matcherName, actualValue, arguments[0], result.message);
+ }
+ result.actualValue = actualValue;
+ result.checkFunc = matcherName;
+ if (!result.pass) {
+ const assertError = new AssertException(result.message);
+ currentRunningSpec ? currentRunningSpec.fail = assertError : currentRunningSuite.hookError = assertError;
+ throw assertError;
+ }
+ };
+ }
+ }
+ return wrappedMatchers;
+ }
+
+ apis() {
+ const _this = this;
+ return {
+ expect: function (actualValue) {
+ return _this.expect(actualValue);
+ }
+ };
+ }
+}
+
+class ReportService {
+ constructor(attr) {
+ this.id = attr.id;
+ }
+
+ init(coreContext) {
+ this.coreContext = coreContext;
+ this.specService = this.coreContext.getDefaultService('spec');
+ this.suiteService = this.coreContext.getDefaultService('suite');
+ this.duration = 0;
+ }
+
+ taskStart() {
+ console.info(`${TAG}[start] start run suites`);
+ }
+
+ async suiteStart() {
+ console.info(`${TAG}[suite start]${this.suiteService.getCurrentRunningSuite().description}`);
+ }
+
+ async specStart() {
+ console.info(`${TAG}start running case '${this.specService.currentRunningSpec.description}'`);
+ this.index = this.index + 1;
+ let spec = this.specService.currentRunningSpec;
+ spec.startTime = await SysTestKit.getRealTime();
+ }
+
+ async specDone() {
+ let msg = '';
+ let spec = this.specService.currentRunningSpec;
+ let suite = this.suiteService.currentRunningSuite;
+ spec.duration = await SysTestKit.getRealTime() - spec.startTime;
+ suite.duration += spec.duration;
+ if (spec.error) {
+ this.formatPrint('error', spec.description + ' ; consuming ' + spec.duration + 'ms');
+ this.formatPrint('errorDetail', spec.error);
+ } else if (spec.fail) {
+ this.formatPrint('fail', spec.description + ' ; consuming ' + spec.duration + 'ms');
+ this.formatPrint('failDetail', spec.fail?.message);
+ } else {
+ this.formatPrint('pass', spec.description + ' ; consuming ' + spec.duration + 'ms');
+ }
+ this.formatPrint(this.specService.currentRunningSpec.error, msg);
+ }
+
+ suiteDone() {
+ let suite = this.suiteService.currentRunningSuite;
+ let message = suite.hookError ? `, ${suite.hookError?.message}` : '';
+ console.info(`[suite end] ${suite.description} consuming ${suite.duration} ms${message}`);
+ }
+
+ taskDone() {
+ let msg = '';
+ let summary = this.suiteService.getSummary();
+ msg = 'total cases:' + summary.total + ';failure ' + summary.failure + ',' + 'error ' + summary.error;
+ msg += ',pass ' + summary.pass + '; consuming ' + summary.duration + 'ms';
+ console.info(`${TAG}${msg}`);
+ console.info(`${TAG}[end] run suites end`);
+ }
+
+ incorrectFormat() {
+ if (this.coreContext.getDefaultService('config').filterValid.length !== 0) {
+ this.coreContext.getDefaultService('config').filterValid.forEach(function (item) {
+ console.info(`${TAG}this param ${item} is invalid`);
+ });
+ }
+ }
+
+ incorrectTestSuiteFormat() {
+ if (this.coreContext.getDefaultService('config').filterXdescribe.length !== 0) {
+ this.coreContext.getDefaultService('config').filterXdescribe.forEach(function (item) {
+ console.info(`${TAG}xdescribe: ${item} should not contain it`);
+ })
+ }
+ }
+
+ formatPrint(type, msg) {
+ switch (type) {
+ case 'pass':
+ console.info(`${TAG}[pass]${msg}`);
+ break;
+ case 'fail':
+ console.info(`${TAG}[fail]${msg}`);
+ break;
+ case 'failDetail':
+ console.info(`${TAG}[failDetail]${msg}`);
+ break;
+ case 'error':
+ console.info(`${TAG}[error]${msg}`);
+ break;
+ case 'errorDetail':
+ console.info(`${TAG}[errorDetail]${msg}`);
+ break;
+ }
+ }
+
+ sleep(numberMillis) {
+ var now = new Date();
+ var exitTime = now.getTime() + numberMillis;
+ while (true) {
+ now = new Date();
+ if (now.getTime() > exitTime) {
+ return;
+ }
+ }
+ }
+}
+
+export {
+ SuiteService,
+ SpecService,
+ ExpectService,
+ ReportService
+};
diff --git a/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/testrunner/OpenHarmonyTestRunner.ts b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/testrunner/OpenHarmonyTestRunner.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e6f4c1b12dd69714ed5a4524671abca1fbcaa58c
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/.ohpm/oh_modules/@ohos/hypium/src/main/testrunner/OpenHarmonyTestRunner.ts
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2023-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { abilityDelegatorRegistry, TestRunner } from '@kit.TestKit';
+import { BusinessError } from '@kit.BasicServicesKit';
+import { hilog } from '@kit.PerformanceAnalysisKit';
+import { resourceManager } from '@kit.LocalizationKit';
+import { util } from '@kit.ArkTS';
+import { Hypium } from '@ohos/hypium';
+import testsuite from '../test/List.test';
+
+let abilityDelegator: abilityDelegatorRegistry.AbilityDelegator;
+let abilityDelegatorArguments: abilityDelegatorRegistry.AbilityDelegatorArgs;
+let jsonPath: string = 'mock/mock-config.json';
+let domain: number = 0x0000; //日志标识,0x0000作为测试框架的业务标识
+let tag: string = 'testTag'; //日志标识字符串,作为tag标识当前runner类下的测试行为
+
+export default class OpenHarmonyTestRunner implements TestRunner {
+ constructor() {
+ }
+
+ onPrepare() {
+ hilog.info(domain, tag, '%{public}s', 'OpenHarmonyTestRunner OnPrepare');
+ }
+
+ async onRun() {
+ hilog.info(domain, tag, '%{public}s', 'OpenHarmonyTestRunner onRun run');
+ abilityDelegatorArguments = abilityDelegatorRegistry.getArguments();
+ abilityDelegator = abilityDelegatorRegistry.getAbilityDelegator();
+ let moduleName = abilityDelegatorArguments.parameters['-m'];
+ let context = abilityDelegator.getAppContext().getApplicationContext().createModuleContext(moduleName);
+ let mResourceManager = context.resourceManager;
+ await checkMock(abilityDelegator, mResourceManager);
+ hilog.info(domain, tag, '%{public}s', 'start run testcase!!!');
+ Hypium.hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite);
+ hilog.info(domain, tag, '%{public}s', 'OpenHarmonyTestRunner onRun end');
+ }
+}
+
+async function checkMock(abilityDelegator: abilityDelegatorRegistry.AbilityDelegator, resourceManager: resourceManager.ResourceManager) {
+ let rawFile: Uint8Array;
+ try {
+ rawFile = resourceManager.getRawFileContentSync(jsonPath);
+ hilog.info(domain, tag, 'MockList file exists');
+ let mockStr: string = util.TextDecoder.create("utf-8", { ignoreBOM: true }).decodeWithStream(rawFile);
+ let mockMap: Record = getMockList(mockStr);
+ try {
+ abilityDelegator.setMockList(mockMap);
+ } catch (error) {
+ let code = (error as BusinessError).code;
+ let message = (error as BusinessError).message;
+ hilog.error(domain, tag, `abilityDelegator.setMockList failed, error code: ${code}, message: ${message}.`);
+ }
+ } catch (error) {
+ let code = (error as BusinessError).code;
+ let message = (error as BusinessError).message;
+ hilog.error(domain, tag, `ResourceManager:callback getRawFileContent failed, error code: ${code}, message: ${message}.`);
+ }
+}
+
+function getMockList(jsonStr: string) {
+ let jsonObj: Record = JSON.parse(jsonStr);
+ let map: Map = new Map(Object.entries(jsonObj));
+ let mockList: Record = {};
+ map.forEach((value: object, key: string) => {
+ let realValue: string = value['source'].toString();
+ mockList[key] = realValue;
+ });
+ hilog.info(domain, tag, '%{public}s', 'mock-json value:' + JSON.stringify(mockList) ?? '');
+ return mockList;
+}
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/BuildProfile.ets b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/BuildProfile.ets
new file mode 100644
index 0000000000000000000000000000000000000000..b054e98af7ad6092740cef28d7dcf6207e514dcb
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/BuildProfile.ets
@@ -0,0 +1,5 @@
+export default class BuildProfile {
+ static readonly HAR_VERSION = '1.0.19';
+ static readonly BUILD_MODE_NAME = 'debug';
+ static readonly DEBUG = true;
+}
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/CHANGELOG.md b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/CHANGELOG.md
new file mode 100644
index 0000000000000000000000000000000000000000..309d707c3d19f506f5582509edf1d0db9011a5b1
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/CHANGELOG.md
@@ -0,0 +1,24 @@
+## 1.0.14
+- 堆栈信息打印到cmd
+## 1.0.15
+- 支持获取测试代码的失败堆栈信息
+- mock代码迁移至harmock包
+- 适配arkts语法
+- 修复覆盖率数据容易截断的bug
+## 1.0.16
+- 修改覆盖率文件生成功能
+- 修改静态方法无法ignoreMock函数
+- ## 1.0.17
+- 修改not断言失败提示日志
+- 自定义错误message信息
+- 添加xdescribe, xit API功能
+- ## 1.0.18
+- 添加全局变量存储API get set
+- 自定义断言功能
+## 1.0.18-rc.0
+添加框架worker执行能力
+## 1.0.18-rc.1
+规范日志格式
+## 1.0.19
+- 规范日志格式
+- 代码规范整改
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/LICENSE b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..4947287f7b5ccb5d1e8b7b2d3aa5d89f322c160d
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/LICENSE
@@ -0,0 +1,177 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/README.md b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..6d795105533a9b3b9949e91d2c3dd14e8f867433
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/README.md
@@ -0,0 +1,219 @@
+Hypium
+A unit test framework for OpenHarmonyOS application
+
+## Hypium是什么?
+***
+- Hypium是OpenHarmony上的测试框架,提供测试用例编写、执行、结果显示能力,用于OpenHarmony系统应用接口以及应用界面测试。
+- Hypium结构化模型:hypium工程主要由List.test.js与TestCase.test.js组成。
+```
+rootProject // Hypium工程根目录
+├── moduleA
+│ ├── src
+│ ├── main // 被测试应用目录
+│ ├── ohosTest // 测试用例目录
+│ ├── js/ets
+│ └── test
+│ └── List.test.js // 测试用例加载脚本,ets目录下为.ets后缀
+│ └── TestCase.test.js // 测试用例脚本,ets目录下为.ets后缀
+└── moduleB
+ ...
+│ └── List.test.js // 测试用例加载脚本,ets目录下为.ets后缀
+│ └── TestCase.test.js // 测试用例脚本,ets目录下为.ets后缀
+```
+
+## 安装使用
+***
+- 在DevEco Studio内使用Hypium
+- 工程级package.json内配置:
+```json
+"dependencies": {
+ "@ohos/hypium": "1.0.19"
+}
+```
+注:
+hypium服务于OpenHarmonyOS应用对外接口测试、系统对外接口测试(SDK中接口),完成HAP自动化测试。详细指导:
+[Deveco Studio](https://developer.harmonyos.com/cn/develop/deveco-studio)
+
+#### 通用语法
+
+- 测试用例采用业内通用语法,describe代表一个测试套, it代表一条用例。
+
+| No. | API | 功能说明 |
+| --- | ---------- | ---------------------------------------------------------------------------------------------------------------------- |
+| 1 | describe | 定义一个测试套,支持两个参数:测试套名称和测试套函数 |
+| 2 | beforeAll | 在测试套内定义一个预置条件,在所有测试用例开始前执行且仅执行一次,支持一个参数:预置动作函数 |
+| 3 | beforeEach | 在测试套内定义一个单元预置条件,在每条测试用例开始前执行,执行次数与it定义的测试用例数一致,支持一个参数:预置动作函数 |
+| 4 | afterEach | 在测试套内定义一个单元清理条件,在每条测试用例结束后执行,执行次数与it定义的测试用例数一致,支持一个参数:清理动作函数 |
+| 5 | afterAll | 在测试套内定义一个清理条件,在所有测试用例结束后执行且仅执行一次,支持一个参数:清理动作函数 |
+| 6 | it | 定义一条测试用例,支持三个参数:用例名称,过滤参数和用例函数 |
+| 7 | expect | 支持bool类型判断等多种断言方法 |
+
+#### 断言库
+
+- 示例代码:
+
+```javascript
+ expect(${actualvalue}).assertX(${expectvalue})
+```
+
+- 断言功能列表:
+
+| No. | API | 功能说明 |
+| :--- | :------------------------------- | ---------------------------------------------------------------------------------------------- |
+| 1 | assertClose | 检验actualvalue和expectvalue(0)的接近程度是否是expectValue(1) |
+| 2 | assertContain | 检验actualvalue中是否包含expectvalue |
+| 3 | assertDeepEquals | @since1.0.4 检验actualvalue和expectvalue(0)是否是同一个对象 |
+| 4 | assertEqual | 检验actualvalue是否等于expectvalue[0] |
+| 5 | assertFail | 抛出一个错误 |
+| 6 | assertFalse | 检验actualvalue是否是false |
+| 7 | assertTrue | 检验actualvalue是否是true |
+| 8 | assertInstanceOf | 检验actualvalue是否是expectvalue类型 |
+| 9 | assertLarger | 检验actualvalue是否大于expectvalue |
+| 10 | assertLess | 检验actualvalue是否小于expectvalue |
+| 11 | assertNaN | @since1.0.4 检验actualvalue是否是NaN |
+| 12 | assertNegUnlimited | @since1.0.4 检验actualvalue是否等于Number.NEGATIVE_INFINITY |
+| 13 | assertNull | 检验actualvalue是否是null |
+| 14 | assertPosUnlimited | @since1.0.4 检验actualvalue是否等于Number.POSITIVE_INFINITY |
+| 15 | assertPromiseIsPending | @since1.0.4 检验actualvalue是否处于Pending状态【actualvalue为promse对象】 |
+| 16 | assertPromiseIsRejected | @since1.0.4 检验actualvalue是否处于Rejected状态【同15】 |
+| 17 | assertPromiseIsRejectedWith | @since1.0.4 检验actualvalue是否处于Rejected状态,并且比较执行的结果值【同15】 |
+| 18 | assertPromiseIsRejectedWithError | @since1.0.4 检验actualvalue是否处于Rejected状态并有异常,同时比较异常的类型和message值【同15】 |
+| 19 | assertPromiseIsResolved | @since1.0.4 检验actualvalue是否处于Resolved状态【同15】 |
+| 20 | assertPromiseIsResolvedWith | @since1.0.4 检验actualvalue是否处于Resolved状态,并且比较执行的结果值【同15】 |
+| 21 | assertThrowError | 检验actualvalue抛出Error内容是否是expectValue |
+| 22 | assertUndefined | 检验actualvalue是否是undefined |
+| 23 | not | @since1.0.4 断言结果取反 |
+
+
+示例代码:
+
+```javascript
+ import { describe, it, expect } from '@ohos/hypium';
+
+ export default async function assertCloseTest() {
+ describe('assertClose', function () {
+ it('assertClose_success', 0, function () {
+ let a = 100;
+ let b = 0.1;
+ expect(a).assertClose(99, b);
+ })
+ })
+ }
+```
+
+#### 公共系统能力
+
+| No. | API | 功能描述 |
+| ---- | ------------------------------------------------------- | ------------------------------------------------------------ |
+| 1 | existKeyword(keyword: string, timeout: number): boolean | @since1.0.3 hilog日志中查找指定字段是否存在,keyword是待查找关键字,timeout为设置的查找时间 |
+| 2 | actionStart(tag: string): void | @since1.0.3 cmd窗口输出开始tag |
+| 3 | actionEnd(tag: string): void | @since1.0.3 cmd窗口输出结束tag |
+
+示例代码:
+
+```javascript
+import { describe, it, expect, SysTestKit} from '@ohos/hypium';
+
+export default function existKeywordTest() {
+ describe('existKeywordTest', function () {
+ it('existKeyword',DEFAULT, async function () {
+ console.info("HelloTest");
+ let isExist = await SysTestKit.existKeyword('HelloTest');
+ console.info('isExist ------>' + isExist);
+ })
+ })
+}
+```
+```javascript
+import { describe, it, expect, SysTestKit} from '@ohos/hypium';
+
+export default function actionTest() {
+ describe('actionTest', function () {
+ it('existKeyword',DEFAULT, async function () {
+ let tag = '[MyTest]';
+ SysTestKit.actionStart(tag);
+ //do something
+ SysTestKit.actionEnd(tag);
+ })
+ })
+}
+```
+
+#### 专项能力
+
+- 测试用例属性筛选能力:hypium支持根据用例属性筛选执行指定测试用例,使用方式是先在测试用例上标记用例属性后,再在测试应用的启动shell命令后新增" -s ${Key} ${Value}"。
+
+| Key | 含义说明 | Value取值范围 |
+| -------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| level | 用例级别 | "0","1","2","3","4", 例如:-s level 1 |
+| size | 用例粒度 | "small","medium","large", 例如:-s size small |
+| testType | 用例测试类型 | "function","performance","power","reliability","security","global","compatibility","user","standard","safety","resilience", 例如:-s testType function |
+
+示例代码
+
+```javascript
+import { describe, it, expect, TestType, Size, Level } from '@ohos/hypium';
+
+export default function attributeTest() {
+ describe('attributeTest', function () {
+ it("testAttributeIt", TestType.FUNCTION | Size.SMALLTEST | Level.LEVEL0, function () {
+ console.info('Hello Test');
+ })
+ })
+}
+```
+
+示例命令
+```shell
+XX -s level 1 -s size small -s testType function
+```
+该命令的作用是:筛选测试应用中同时满足a)用例级别是1 b)用例粒度是small c)用例测试类型是function 三个条件的用例执行。
+
+- 测试套/测试用例名称筛选能力(测试套与用例名称用“#”号连接,多个用“,”英文逗号分隔)
+
+| Key | 含义说明 | Value取值范围 |
+| -------- | ----------------------- | -------------------------------------------------------------------------------------------- |
+| class | 指定要执行的测试套&用例 | ${describeName}#${itName},${describeName} , 例如:-s class attributeTest#testAttributeIt |
+| notClass | 指定不执行的测试套&用例 | ${describeName}#${itName},${describeName} , 例如:-s notClass attributeTest#testAttributeIt |
+
+示例命令
+```shell
+XX -s class attributeTest#testAttributeIt,abilityTest#testAbilityIt
+```
+该命令的作用是:筛选测试应用中attributeTest测试套下的testAttributeIt测试用例,abilityTest测试套下的testAbilityIt测试用例,只执行这两条用例。
+
+- 其他能力
+
+| 能力项 | Key | 含义说明 | Value取值范围 |
+| ------------ | ------- | ---------------------------- | ---------------------------------------------- |
+| 随机执行能力 | random | 测试套&测试用例随机执行 | true, 不传参默认为false, 例如:-s random true |
+| 空跑能力 | dryRun | 显示要执行的测试用例信息全集 | true , 不传参默认为false,例如:-s dryRun true |
+| 异步超时能力 | timeout | 异步用例执行的超时时间 | 正整数 , 单位ms,例如:-s timeout 5000 |
+
+##### 约束限制
+随机执行能力和空跑能力从npm包1.0.3版本开始支持
+
+#### Mock能力
+
+##### 约束限制
+
+单元测试框架Mock能力从npm包[1.0.1版本](https://repo.harmonyos.com/#/cn/application/atomService/@ohos%2Fhypium/v/1.0.1)开始支持
+
+## 约束
+
+***
+ 本模块首批接口从OpenHarmony SDK API version 8开始支持。
+
+## Hypium开放能力隐私声明
+
+- 我们如何收集和使用您的个人信息
+ 您在使用集成了Hypium开放能力的测试应用时,Hypium不会处理您的个人信息。
+- SDK处理的个人信息
+ 不涉及。
+- SDK集成第三方服务声明
+ 不涉及。
+- SDK数据安全保护
+ 不涉及。
+- SDK版本更新声明
+ 为了向您提供最新的服务,我们会不时更新Hypium版本。我们强烈建议开发者集成使用最新版本的Hypium。
+
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/build-profile.json5 b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/build-profile.json5
new file mode 100644
index 0000000000000000000000000000000000000000..312d38eb08629793b3484c7373213f22840c8d82
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/build-profile.json5
@@ -0,0 +1,28 @@
+{
+ "apiType": "stageMode",
+ "buildOption": {
+ },
+ "buildOptionSet": [
+ {
+ "name": "release",
+ "arkOptions": {
+ "obfuscation": {
+ "ruleOptions": {
+ "enable": true,
+ "files": [
+ "./obfuscation-rules.txt"
+ ]
+ },
+ "consumerFiles": [
+ "./consumer-rules.txt"
+ ]
+ }
+ },
+ },
+ ],
+ "targets": [
+ {
+ "name": "default"
+ }
+ ]
+}
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/hvigorfile.ts b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/hvigorfile.ts
new file mode 100644
index 0000000000000000000000000000000000000000..42187071482d292588ad40babeda74f7b8d97a23
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/hvigorfile.ts
@@ -0,0 +1,6 @@
+import { harTasks } from '@ohos/hvigor-ohos-plugin';
+
+export default {
+ system: harTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
+ plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
+}
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/index.d.ts b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/index.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7272b5fa839a2cd510d0c70d517bb6800133dba2
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/index.d.ts
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export const DEFAULT = 0B0000
+
+export const when: when;
+
+export enum TestType {
+ FUNCTION = 0B1,
+ PERFORMANCE = 0B1 << 1,
+ POWER = 0B1 << 2,
+ RELIABILITY = 0B1 << 3,
+ SECURITY = 0B1 << 4,
+ GLOBAL = 0B1 << 5,
+ COMPATIBILITY = 0B1 << 6,
+ USER = 0B1 << 7,
+ STANDARD = 0B1 << 8,
+ SAFETY = 0B1 << 9,
+ RESILIENCE = 0B1 << 10
+}
+
+export enum Size {
+ SMALLTEST = 0B1 << 16,
+ MEDIUMTEST = 0B1 << 17,
+ LARGETEST = 0B1 << 18
+}
+
+export enum Level {
+ LEVEL0 = 0B1 << 24,
+ LEVEL1 = 0B1 << 25,
+ LEVEL2 = 0B1 << 26,
+ LEVEL3 = 0B1 << 27,
+ LEVEL4 = 0B1 << 28
+}
+export { xdescribe, xit, describe, it } from './index';
+
+
+
+export function beforeItSpecified(testCaseNames: Array | string, callback: Function): void
+
+export function afterItSpecified(testCaseNames: Array | string, callback: Function): void
+
+export function beforeEach(callback: Function): void
+
+export function afterEach(callback: Function): void
+
+export function beforeAll(callback: Function): void
+
+export function afterAll(callback: Function): void
+
+
+export interface Assert {
+ assertClose(expectValue: number, precision: number): void
+ assertContain(expectValue: any): void
+ assertEqual(expectValue: any): void
+ assertFail(): void
+ assertFalse(): void
+ assertTrue(): void
+ assertInstanceOf(expectValue: string): void
+ assertLarger(expectValue: number): void
+ assertLess(expectValue: number): void
+ assertNull(): void
+ assertThrowError(expectValue: string | Function): void
+ assertUndefined(): void
+ assertLargerOrEqual(expectValue: number): void
+ assertLessOrEqual(expectValue: number): void
+ assertNaN(): void
+ assertNegUnlimited(): void
+ assertPosUnlimited(): void
+ not(): Assert;
+ assertDeepEquals(expectValue: any): void
+ assertPromiseIsPending(): Promise
+ assertPromiseIsRejected(): Promise
+ assertPromiseIsRejectedWith(expectValue?: any): Promise
+ assertPromiseIsRejectedWithError(...expectValue): Promise
+ assertPromiseIsResolved(): Promise
+ assertPromiseIsResolvedWith(expectValue?: any): Promise
+ message(msg: string): Assert
+}
+
+export function expect(actualValue?: any): Assert
+
+export class ArgumentMatchers {
+ static any;
+ static anyString;
+ static anyBoolean;
+ static anyNumber;
+ static anyObj;
+ static anyFunction;
+ static matchRegexs(Regex: RegExp): void
+}
+
+declare interface when {
+ afterReturn(value: any): any
+ afterReturnNothing(): undefined
+ afterAction(action: any): any
+ afterThrow(e_msg: string): string
+ (argMatchers?: any): when;
+}
+
+export interface VerificationMode {
+ times(count: Number): void
+ never(): void
+ once(): void
+ atLeast(count: Number): void
+ atMost(count: Number): void
+}
+
+export class MockKit {
+ constructor()
+ mockFunc(obj: Object, func: Function): Function
+ mockObject(obj: Object): Object
+ verify(methodName: String, argsArray: Array): VerificationMode
+ ignoreMock(obj: Object, func: Function): void
+ clear(obj: Object): void
+ clearAll(): void
+}
+
+export class SysTestKit {
+ static getDescribeName(): string;
+ static getItName(): string;
+ static getItAttribute(): TestType | Size | Level
+ static actionStart(tag: string): void
+ static actionEnd(tag: string): void
+ static existKeyword(keyword: string, timeout?: number): boolean
+}
+
+export class Hypium {
+ static setData(data: { [key: string]: any }): void
+ static setTimeConfig(systemTime: any)
+ static hypiumTest(abilityDelegator: any, abilityDelegatorArguments: any, testsuite: Function): void
+ static set(key: string, value: any): void
+ static get(key: string): any
+ static registerAssert(customAssertion: Function): void
+ static unregisterAssert(customAssertion: string | Function): void
+ static hypiumWorkerTest(abilityDelegator: Object, abilityDelegatorArguments: Object, testsuite: Function, workerPort: Object): void;
+ static hypiumInitWorkers(abilityDelegator: Object, scriptURL: string, workerNum: number, params: Object): void;
+}
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/index.ets b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/index.ets
new file mode 100644
index 0000000000000000000000000000000000000000..02a237f1c999d1f48b3974b6076d5dae9213245a
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/index.ets
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Core from './src/main/core';
+import {TestType, Size, Level, DEFAULT} from './src/main/Constant';
+import DataDriver from './src/main/module/config/DataDriver';
+import ExpectExtend from './src/main/module/assert/ExpectExtend';
+import OhReport from './src/main/module/report/OhReport';
+export { xdescribe, xit, describe, it } from './index.ts';
+
+export declare class Hypium {
+ static setData(data: Object): void
+ static setTimeConfig(systemTime: Object): void
+ static hypiumTest(abilityDelegator: Object, abilityDelegatorArguments: Object, testsuite: Function): void
+ static set(key: string, value: Object): void
+ static get(key: string): Object
+ static registerAssert(customAssertion: Function): void
+ static unregisterAssert(customAssertion: string | Function): void
+ static hypiumWorkerTest(abilityDelegator: Object, abilityDelegatorArguments: Object,
+ testsuite: Function, workerPort: Object): void;
+ static hypiumInitWorkers(abilityDelegator: Object, scriptURL: string, workerNum: number, params: Object): void;
+}
+
+export {
+ Core,
+ DataDriver,
+ ExpectExtend,
+ OhReport,
+ TestType,
+ Size,
+ Level,
+ DEFAULT
+};
+
+type allExpectType = Object | undefined | null
+
+export declare function beforeItSpecified(testCaseNames: Array | string, callback: Function): void
+
+export declare function afterItSpecified(testCaseNames: Array | string, callback: Function): void
+
+export declare function beforeEach(callback: Function): void
+
+export declare function afterEach(callback: Function): void
+
+export declare function beforeAll(callback: Function): void
+
+export declare function afterAll(callback: Function): void
+
+export declare interface Assert {
+ assertClose(expectValue: number, precision: number): void
+ assertContain(expectValue: allExpectType): void
+ assertEqual(expectValue: allExpectType): void
+ assertFail(): void
+ assertFalse(): void
+ assertTrue(): void
+ assertInstanceOf(expectValue: string): void
+ assertLarger(expectValue: number): void
+ assertLess(expectValue: number): void
+ assertNull(): void
+ assertThrowError(expectValue: string | Function): void
+ assertUndefined(): void
+ assertLargerOrEqual(expectValue: number):void
+ assertLessOrEqual(expectValue: number):void
+ assertNaN():void
+ assertNegUnlimited(): void
+ assertPosUnlimited(): void
+ not(): Assert;
+ assertDeepEquals(expectValue: allExpectType):void
+ assertPromiseIsPending(): Promise
+ assertPromiseIsRejected(): Promise
+ assertPromiseIsRejectedWith(expectValue?: allExpectType): Promise
+ assertPromiseIsRejectedWithError(...expectValue: allExpectType[]): Promise
+ assertPromiseIsResolved(): Promise
+ assertPromiseIsResolvedWith(expectValue?: allExpectType): Promise
+ message(msg: string): Assert
+}
+
+export declare function expect(actualValue?: allExpectType): Assert
+
+export declare class ArgumentMatchers {
+ public static any: allExpectType;
+ public static anyString: string;
+ public static anyBoolean: Boolean;
+ public static anyNumber: Number;
+ public static anyObj: Object;
+ public static anyFunction: Function;
+ public static matchRegexs(regex: RegExp): void
+}
+
+declare interface whenResult {
+ afterReturn: (value: allExpectType) => allExpectType
+ afterReturnNothing: () => undefined
+ afterAction: (action: allExpectType) => allExpectType
+ afterThrow: (e_msg: string) => string
+}
+
+export declare function when(f:Function): (f?: allExpectType | void) => whenResult
+
+export declare interface VerificationMode {
+ times(count: Number): void
+ never(): void
+ once(): void
+ atLeast(count: Number): void
+ atMost(count: Number): void
+}
+
+export declare class MockKit {
+ constructor()
+ mockFunc(obj: Object, func: Function): Function
+ mockObject(obj: Object): Object
+ verify(methodName: String, argsArray: Array): VerificationMode
+ ignoreMock(obj: Object, func: Function): void
+ clear(obj: Object): void
+ clearAll(): void
+}
+
+export declare class SysTestKit {
+ static getDescribeName(): string;
+ static getItName(): string;
+ static getItAttribute(): TestType | Size | Level
+ static actionStart(tag: string): void
+ static actionEnd(tag: string): void
+ static existKeyword(keyword: string, timeout?: number): boolean
+}
+
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/index.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..02d06d9d1b4b478aa2aec70ba3a73a5e123c98db
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/index.js
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License")
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Core from './src/main/core';
+import { DEFAULT, TestType, Size, Level, TAG, PrintTag } from './src/main/Constant';
+import DataDriver from './src/main/module/config/DataDriver';
+import ExpectExtend from './src/main/module/assert/ExpectExtend';
+import OhReport from './src/main/module/report/OhReport';
+import SysTestKit from './src/main/module/kit/SysTestKit';
+import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, beforeItSpecified, afterItSpecified, xdescribe, xit } from './src/main/interface';
+import { MockKit, when } from './src/main/module/mock/MockKit';
+import ArgumentMatchers from './src/main/module/mock/ArgumentMatchers';
+import worker from '@ohos.worker';
+
+class Hypium {
+ static context = new Map();
+ static setData(data) {
+ const core = Core.getInstance();
+ const dataDriver = new DataDriver({ data });
+ core.addService('dataDriver', dataDriver);
+ }
+
+ static setTimeConfig(systemTime) {
+ SysTestKit.systemTime = systemTime;
+ }
+
+ static set(key, value) {
+ Hypium.context.set(key, value);
+ }
+
+ static get(key) {
+ return Hypium.context.get(key);
+ }
+
+ static hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite) {
+ const core = Core.getInstance();
+ const expectExtend = new ExpectExtend({
+ 'id': 'extend'
+ });
+ core.addService('expect', expectExtend);
+ const ohReport = new OhReport({
+ 'delegator': abilityDelegator,
+ 'abilityDelegatorArguments': abilityDelegatorArguments
+ });
+ SysTestKit.delegator = abilityDelegator;
+ core.addService('report', ohReport);
+ core.init();
+ core.subscribeEvent('spec', ohReport);
+ core.subscribeEvent('suite', ohReport);
+ core.subscribeEvent('task', ohReport);
+ const configService = core.getDefaultService('config');
+ if (abilityDelegatorArguments !== null) {
+ let testParameters = configService.translateParams(abilityDelegatorArguments.parameters);
+ console.info(`${TAG}parameters:${JSON.stringify(testParameters)}`);
+ configService.setConfig(testParameters);
+ }
+ testsuite();
+ core.execute(abilityDelegator);
+ }
+ static async hypiumInitWorkers(abilityDelegator, scriptURL, workerNum = 8, params) {
+ console.info(`${TAG}, hypiumInitWorkers call,${scriptURL}`);
+ let workerPromiseArray = [];
+
+ // 开始统计时间
+ let startTime = await SysTestKit.getRealTime();
+ for (let i = 0; i < workerNum; i++) {
+ // 创建worker线程
+ const workerPromise = Hypium.createWorkerPromise(scriptURL, i, params);
+ workerPromiseArray.push(workerPromise);
+ }
+ const ret = {total: 0, failure: 0, error: 0, pass: 0, ignore: 0, duration: 0};
+ Promise.all(workerPromiseArray).then(async (items) => {
+ console.info(`${TAG}, all result from workers, ${JSON.stringify(items)}`);
+ let allItemList = new Array();
+ // 统计执行结果
+ Hypium.handleWorkerTestResult(ret, allItemList, items);
+ console.info(`${TAG}, all it result, ${JSON.stringify(allItemList)}`);
+ // 统计用例执行结果
+ const retResult = {total: 0, failure: 0, error: 0, pass: 0, ignore: 0, duration: 0};
+ // 标记用例执行结果
+ Hypium.configWorkerItTestResult(retResult, allItemList);
+ // 打印用例结果
+ Hypium.printWorkerTestResult(abilityDelegator, allItemList);
+ // 用例执行完成统计时间
+ let endTime = await SysTestKit.getRealTime();
+ const taskConsuming = endTime - startTime;
+ const message =
+ `\n${PrintTag.OHOS_REPORT_ALL_RESULT}: stream=Test run: runTimes: ${ret.total},total: ${retResult.total}, Failure: ${retResult.failure}, Error: ${retResult.error}, Pass: ${retResult.pass}, Ignore: ${retResult.ignore}` +
+ `\n${PrintTag.OHOS_REPORT_ALL_CODE}: ${retResult.failure > 0 || retResult.error > 0 ? -1 : 0}` +
+ `\n${PrintTag.OHOS_REPORT_ALL_STATUS}: taskconsuming=${taskConsuming > 0 ? taskConsuming : ret.duration}`;
+ abilityDelegator.printSync(message);
+ console.info(`${TAG}, [end] you worker test`);
+ abilityDelegator.finishTest('you worker test finished!!!', 0, () => {});
+ }).catch((e) => {
+ console.info(`${TAG}, [end] error you worker test, ${JSON.stringify(e)}`);
+ abilityDelegator.finishTest('you worker test error finished!!!', 0, () => {});
+ }).finally(() => {
+ console.info(`${TAG}, all promise finally end`);
+ });
+ }
+ // 创建worker线程
+ static createWorkerPromise(scriptURL, i, params) {
+ console.info(`${TAG}, createWorkerPromiser, ${scriptURL}, ${i}`);
+ const workerPromise = new Promise((resolve, reject) => {
+ const workerInstance = new worker.ThreadWorker(scriptURL, {name: `worker_${i}`});
+ console.info(`${TAG}, send data to worker`);
+ // 发送数据到worker线程中
+ workerInstance.postMessage(params);
+ workerInstance.onmessage = function (e) {
+ let currentThreadName = e.data?.currentThreadName;
+ console.info(`${TAG}, receview data from ${currentThreadName}, ${JSON.stringify(e.data)}`);
+ //
+ resolve(e.data?.summary);
+ console.info(`${TAG}, ${currentThreadName} finish`);
+ workerInstance.terminate();
+ };
+ workerInstance.onerror = function (e) {
+ console.info(`${TAG}, worker error, ${JSON.stringify(e)}`);
+ reject(e);
+ workerInstance.terminate();
+ };
+ workerInstance.onmessageerror = function (e) {
+ console.info(`${TAG}, worker message error, ${JSON.stringify(e)}`);
+ reject(e);
+ workerInstance.terminate();
+ };
+ });
+ return workerPromise;
+ }
+ static handleWorkerTestResult(ret, allItemList, items) {
+ console.info(`${TAG}, handleWorkerTestResult, ${JSON.stringify(items)}`);
+ for (const {total, failure, error, pass, ignore, duration, itItemList} of items) {
+ ret.total += total;
+ ret.failure += failure;
+ ret.error += error;
+ ret.pass += pass;
+ ret.ignore += ignore;
+ ret.duration += duration;
+ Hypium.handleItResult(allItemList, itItemList);
+ }
+ }
+ static handleItResult(allItemList, itItemList) {
+ // 遍历所有的用例结果统计最终结果
+ for (const {currentThreadName, description, result} of itItemList) {
+ let item = allItemList.find((it) => it.description === description);
+ if (item) {
+ let itResult = item.result;
+ // 当在worker中出现一次failure就标记为failure, 出现一次error就标记为error, 所有线程都pass才标记为pass
+ if (itResult === 0) {
+ item.result = result;
+ item.currentThreadName = currentThreadName;
+ }
+ } else {
+ let it = {
+ description: description,
+ currentThreadName: currentThreadName,
+ result: result
+ };
+ allItemList.push(it);
+ }
+ }
+ }
+ static configWorkerItTestResult(retResult, allItemList) {
+ console.info(`${TAG}, configWorkerItTestResult, ${JSON.stringify(allItemList)}`);
+ for (const {currentThreadName, description, result} of allItemList) {
+ console.info(`${TAG}, description, ${description}, result,${result}`);
+ retResult.total ++;
+ if (result === 0) {
+ retResult.pass ++;
+ } else if (result === -1) {
+ retResult.error ++;
+ } else if (result === -2) {
+ retResult.failure ++;
+ } else {
+ retResult.ignore ++;
+ }
+ }
+ }
+ static printWorkerTestResult(abilityDelegator, allItemList) {
+ console.info(`${TAG}, printWorkerTestResult, ${JSON.stringify(allItemList)}`);
+ let index = 1;
+ for (const {currentThreadName, description, result} of allItemList) {
+ console.info(`${TAG}, description print, ${description}, result,${result}`);
+ let itArray = description.split('#');
+ let des;
+ let itName;
+ if (itArray.length > 1) {
+ des = itArray[0];
+ itName = itArray[1];
+ } else if (itArray.length > 1) {
+ des = itArray[0];
+ itName = itArray[0];
+ } else {
+ des = 'undefined';
+ itName = 'undefined';
+ }
+
+ let msg = `\n${PrintTag.OHOS_REPORT_WORKER_STATUS}: class=${des}`;
+ msg += `\n${PrintTag.OHOS_REPORT_WORKER_STATUS}: test=${itName}`;
+ msg += `\n${PrintTag.OHOS_REPORT_WORKER_STATUS}: current=${index}`;
+ msg += `\n${PrintTag.OHOS_REPORT_WORKER_STATUS}: CODE=${result}`;
+ abilityDelegator.printSync(msg);
+ index ++;
+ }
+ }
+ static hypiumWorkerTest(abilityDelegator, abilityDelegatorArguments, testsuite, workerPort) {
+ console.info(`${TAG}, hypiumWorkerTest call`);
+ SysTestKit.workerPort = workerPort;
+ let currentWorkerName = workerPort.name;
+ console.info(`${TAG}, hypiumWorkerTest_currentWorkerName: ${currentWorkerName}`);
+ Hypium.hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite);
+
+ }
+
+ static registerAssert(customAssertion) {
+ const core = Core.getInstance();
+ const expectService = core.getDefaultService('expect');
+ let matchers = {};
+ matchers[customAssertion.name] = customAssertion;
+ expectService.addMatchers(matchers);
+ expectService.customMatchers.push(customAssertion.name);
+ console.info(`${TAG}success to register the ${customAssertion.name}`);
+ }
+
+ static unregisterAssert(customAssertion) {
+ const core = Core.getInstance();
+ const expectService = core.getDefaultService('expect');
+ let customAssertionName = typeof customAssertion === 'function' ? customAssertion.name : customAssertion;
+ expectService.removeMatchers(customAssertionName);
+ console.info(`${TAG}success to unregister the ${customAssertionName}`);
+ }
+
+}
+
+export {
+ Hypium,
+ Core,
+ DEFAULT,
+ TestType,
+ Size,
+ Level,
+ DataDriver,
+ ExpectExtend,
+ OhReport,
+ SysTestKit,
+ describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, beforeItSpecified, afterItSpecified, xdescribe, xit,
+ MockKit, when,
+ ArgumentMatchers
+};
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/index.ts b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b7082ebc98214b58d41e8681791809f1aee48f12
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/index.ts
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { TestType, Size, Level } from "./src/main/Constant";
+
+export declare function xdescribe(testSuiteName: string, func: Function): void;
+
+export declare namespace xdescribe {
+ function reason(reason: string): any;
+};
+
+export declare function describe(testSuiteName: string, func: Function): void;
+
+export declare function xit(testCaseName: string, attribute: TestType | Size | Level, func: Function): void;
+
+export declare namespace xit {
+ function reason(reason: string): any;
+};
+
+export declare function it(testCaseName: string, attribute: TestType | Size | Level, func: Function): void;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/oh-package.json5 b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/oh-package.json5
new file mode 100644
index 0000000000000000000000000000000000000000..d91344eda60f35477a5caf4bf5c116ffac2e53db
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/oh-package.json5
@@ -0,0 +1 @@
+{"name":"@ohos/hypium","version":"1.0.19","description":"A unit test framework for OpenHarmony application","main":"index.js","keywords":["测试框架","except","mock"],"author":"huawei","license":"Apache-2.0","repository":"https://gitee.com/openharmony/testfwk_arkxtest","homepage":"https://gitee.com/openharmony/testfwk_arkxtest","dependencies":{}}
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/Constant.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/Constant.js
new file mode 100644
index 0000000000000000000000000000000000000000..f470d69cd9a3302b19d45c147ca7d7c1dd8a3b18
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/Constant.js
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * define the testcase type : TestType, Size , Level
+ */
+export const TAG = '[Hypium]';
+
+export const DEFAULT = 0B0000;
+
+export class PrintTag {
+ static OHOS_REPORT_WORKER_STATUS = 'OHOS_REPORT_WORKER_STATUS';
+ static OHOS_REPORT_ALL_RESULT = 'OHOS_REPORT_ALL_RESULT';
+ static OHOS_REPORT_ALL_CODE = 'OHOS_REPORT_ALL_CODE';
+ static OHOS_REPORT_ALL_STATUS = 'OHOS_REPORT_ALL_STATUS';
+ static OHOS_REPORT_RESULT = 'OHOS_REPORT_RESULT';
+ static OHOS_REPORT_CODE = 'OHOS_REPORT_CODE';
+ static OHOS_REPORT_STATUS = 'OHOS_REPORT_STATUS';
+ static OHOS_REPORT_SUM = 'OHOS_REPORT_SUM';
+ static OHOS_REPORT_STATUS_CODE = 'OHOS_REPORT_STATUS_CODE';
+};
+
+export class TestType {
+ static FUNCTION = 0B1;
+ static PERFORMANCE = 0B1 << 1;
+ static POWER = 0B1 << 2;
+ static RELIABILITY = 0B1 << 3;
+ static SECURITY = 0B1 << 4;
+ static GLOBAL = 0B1 << 5;
+ static COMPATIBILITY = 0B1 << 6;
+ static USER = 0B1 << 7;
+ static STANDARD = 0B1 << 8;
+ static SAFETY = 0B1 << 9;
+ static RESILIENCE = 0B1 << 10;
+}
+
+export class Size {
+ static SMALLTEST = 0B1 << 16;
+ static MEDIUMTEST = 0B1 << 17;
+ static LARGETEST = 0B1 << 18;
+}
+
+export class Level {
+ static LEVEL0 = 0B1 << 24;
+ static LEVEL1 = 0B1 << 25;
+ static LEVEL2 = 0B1 << 26;
+ static LEVEL3 = 0B1 << 27;
+ static LEVEL4 = 0B1 << 28;
+}
+
+export const TESTTYPE = {
+ 'function': 1,
+ 'performance': 1 << 1,
+ 'power': 1 << 2,
+ 'reliability': 1 << 3,
+ 'security': 1 << 4,
+ 'global': 1 << 5,
+ 'compatibility': 1 << 6,
+ 'user': 1 << 7,
+ 'standard': 1 << 8,
+ 'safety': 1 << 9,
+ 'resilience': 1 << 10,
+}
+
+export const LEVEL = {
+ '0': 1 << 24,
+ '1': 1 << 25,
+ '2': 1 << 26,
+ '3': 1 << 27,
+ '4': 1 << 28,
+}
+
+export const SIZE = {
+ 'small': 1 << 16,
+ 'medium': 1 << 17,
+ 'large': 1 << 18,
+}
+
+export const KEYSET = [
+ '-s class', '-s notClass', '-s suite', '-s itName',
+ '-s level', '-s testType', '-s size', '-s timeout',
+ '-s dryRun', '-s random', '-s breakOnError', '-s stress',
+ '-s coverage', '-s skipMessage', '-s runSkipped',
+ 'class', 'notClass', 'suite', 'itName',
+ 'level', 'testType', 'size', 'timeout', 'dryRun', 'random',
+ 'breakOnError', 'stress', 'coverage', 'skipMessage', 'runSkipped'
+]
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/core.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/core.js
new file mode 100644
index 0000000000000000000000000000000000000000..cfcb5f17287208f5e6869b4248faf6c9093002d9
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/core.js
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {SuiteService, SpecService, ExpectService, ReportService} from './service';
+import {ConfigService} from './module/config/configService';
+import {SpecEvent, TaskEvent, SuiteEvent} from './event';
+
+/**
+ * core service for execute testcase.
+ */
+class Core {
+ static getInstance() {
+ if (!this.instance) {
+ this.instance = new Core();
+ }
+ return this.instance;
+ }
+
+ constructor() {
+ this.instance = null;
+ this.services = {
+ suite: {},
+ spec: {},
+ config: {},
+ expect: {},
+ log: {},
+ report: {}
+
+ };
+ this.events = {
+ suite: {},
+ spec: {},
+ task: {}
+ };
+ }
+
+ addService(name, service) {
+ let serviceObj = {};
+ if (!this.services[name]) {
+ this.services[name] = serviceObj;
+ } else {
+ serviceObj = this.services[name];
+ }
+ serviceObj[service.id] = service;
+ }
+
+ getDefaultService(name) {
+ return this.services[name].default;
+ }
+
+ getServices(name) {
+ return this.services[name];
+ }
+
+ registerEvent(serviceName, event) {
+ let eventObj = {};
+ if (!this.events[serviceName]) {
+ this.events[serviceName] = eventObj;
+ } else {
+ eventObj = this.events[serviceName];
+ }
+ eventObj[event.id] = event;
+ }
+
+ unRegisterEvent(serviceName, eventID) {
+ const eventObj = this.events[serviceName];
+ if (eventObj) {
+ delete eventObj[eventID];
+ }
+ }
+
+ subscribeEvent(serviceName, serviceObj) {
+ const eventObj = this.events[serviceName];
+ if (eventObj) {
+ for (const attr in eventObj) {
+ eventObj[attr]['subscribeEvent'](serviceObj);
+ }
+ }
+ }
+
+ async fireEvents(serviceName, eventName) {
+ const eventObj = this.events[serviceName];
+ if (!eventObj) {
+ return;
+ }
+ for (const attr in eventObj) {
+ await eventObj[attr][eventName]();
+ }
+ }
+
+ addToGlobal(apis) {
+ if (typeof globalThis !== 'undefined') {
+ for (let api in apis) {
+ globalThis[api] = apis[api];
+ }
+ }
+ for (const api in apis) {
+ this[api] = apis[api];
+ }
+ }
+
+ init() {
+ this.addService('suite', new SuiteService({id: 'default'}));
+ this.addService('spec', new SpecService({id: 'default'}));
+ this.addService('expect', new ExpectService({id: 'default'}));
+ this.addService('report', new ReportService({id: 'default'}));
+ this.addService('config', new ConfigService({id: 'default'}));
+ this.registerEvent('task', new TaskEvent({id: 'default', coreContext: this}));
+ this.registerEvent('suite', new SuiteEvent({id: 'default', coreContext: this}));
+ this.registerEvent('spec', new SpecEvent({id: 'default', coreContext: this}));
+ this.subscribeEvent('spec', this.getDefaultService('report'));
+ this.subscribeEvent('suite', this.getDefaultService('report'));
+ this.subscribeEvent('task', this.getDefaultService('report'));
+ const context = this;
+ for (const key in this.services) {
+ const serviceObj = this.services[key];
+ for (const serviceID in serviceObj) {
+ const service = serviceObj[serviceID];
+ service.init(context);
+
+ if (typeof service.apis !== 'function') {
+ continue;
+ }
+ const apis = service.apis();
+ if (apis) {
+ this.addToGlobal(apis);
+ }
+ }
+ }
+ }
+
+ execute(abilityDelegator) {
+ const suiteService = this.getDefaultService('suite');
+ const configService = this.getDefaultService('config');
+ if (configService['dryRun'] === 'true') {
+ (async function () {
+ await suiteService.dryRun(abilityDelegator);
+ })();
+ return;
+ }
+ setTimeout(() => {
+ suiteService.execute();
+ }, 10);
+ }
+}
+
+export default Core;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/event.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/event.js
new file mode 100644
index 0000000000000000000000000000000000000000..3be0211f01646c9c269c2425cbee82c87ac6d9ea
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/event.js
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class SpecEvent {
+ constructor(attr) {
+ this.id = attr.id;
+ this.coreContext = attr.context;
+ this.eventMonitors = [];
+ }
+
+ subscribeEvent(service) {
+ this.eventMonitors.push(service);
+ }
+
+ async specStart() {
+ for (const monitor of this.eventMonitors) {
+ await monitor['specStart']();
+ }
+ }
+
+ async specDone() {
+ for (const monitor of this.eventMonitors) {
+ await monitor['specDone']();
+ }
+ }
+}
+
+class SuiteEvent {
+ constructor(attr) {
+ this.id = attr.id;
+ this.suiteContext = attr.coreContext;
+ this.eventMonitors = [];
+ }
+
+ subscribeEvent(service) {
+ this.eventMonitors.push(service);
+ }
+
+ async suiteStart() {
+ for (const monitor of this.eventMonitors) {
+ await monitor['suiteStart']();
+ }
+ }
+
+ async suiteDone() {
+ for (const monitor of this.eventMonitors) {
+ await monitor['suiteDone']();
+ }
+ }
+}
+
+class TaskEvent {
+ constructor(attr) {
+ this.id = attr.id;
+ this.coreContext = attr.coreContext;
+ this.eventMonitors = [];
+ }
+
+ subscribeEvent(service) {
+ this.eventMonitors.push(service);
+ }
+
+ async taskStart() {
+ for (const monitor of this.eventMonitors) {
+ await monitor['taskStart']();
+ }
+ }
+
+ async taskDone() {
+ for (const monitor of this.eventMonitors) {
+ await monitor['taskDone']();
+ }
+ }
+
+ incorrectFormat() {
+ for (const monitor of this.eventMonitors) {
+ monitor['incorrectFormat']();
+ }
+ }
+
+ incorrectTestSuiteFormat() {
+ for (const monitor of this.eventMonitors) {
+ monitor.incorrectTestSuiteFormat();
+ }
+ }
+}
+
+export { SpecEvent, TaskEvent, SuiteEvent };
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/interface.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/interface.js
new file mode 100644
index 0000000000000000000000000000000000000000..1bf43509ac3f70f1275e1da79388e1511e72a3f9
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/interface.js
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Core from './core';
+
+const core = Core.getInstance();
+
+const describe = function (desc, func) {
+ return Reflect.has(core, 'describe') ? core.describe(desc, func) : (desc, func) => { };
+};
+const it = function (desc, filter, func) {
+ return Reflect.has(core, 'it') ? core.it(desc, filter, func) : (desc, filter, func) => { };
+};
+const beforeItSpecified = function (itDescs, func) {
+ return Reflect.has(core, 'beforeItSpecified') ? core.beforeItSpecified(itDescs, func) : (itDescs, func) => { };
+};
+
+const afterItSpecified = function (itDescs, func) {
+ return Reflect.has(core, 'afterItSpecified') ? core.afterItSpecified(itDescs, func) : (itDescs, func) => { };
+};
+const beforeEach = function (func) {
+ return Reflect.has(core, 'beforeEach') ? core.beforeEach(func) : (func) => { };
+};
+const afterEach = function (func) {
+ return Reflect.has(core, 'afterEach') ? core.afterEach(func) : (func) => { };
+};
+const beforeAll = function (func) {
+ return Reflect.has(core, 'beforeAll') ? core.beforeAll(func) : (func) => { };
+};
+const afterAll = function (func) {
+ return Reflect.has(core, 'afterAll') ? core.afterAll(func) : (func) => { };
+};
+const expect = function (actualValue) {
+ return Reflect.has(core, 'expect') ? core.expect(actualValue) : (actualValue) => { };
+};
+
+const xdescribe = function (desc, func) {
+ return Reflect.has(core, 'xdescribe') ? core.xdescribe(desc, func, null) : (desc, func, reason) => { };
+};
+xdescribe.reason = (reason) => {
+ return (desc, func) => {
+ return Reflect.has(core, 'xdescribe') ? core.xdescribe(desc, func, reason) : (desc, func, reason) => { };
+ };
+};
+const xit = function (desc, filter, func) {
+ return Reflect.has(core, 'xit') ? core.xit(desc, filter, func, null) : (desc, filter, func, reason) => { };
+};
+xit.reason = (reason) => {
+ return (desc, filter, func) => {
+ return Reflect.has(core, 'xit') ? core.xit(desc, filter, func, reason) : (desc, filter, func, reason) => { };
+ };
+};
+
+export {
+ describe, it, beforeAll, beforeEach, afterEach, afterAll, expect, beforeItSpecified, afterItSpecified, xdescribe, xit
+};
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module.json b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module.json
new file mode 100644
index 0000000000000000000000000000000000000000..b0e022bd13205c4c3310480d6732db4707193b3a
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module.json
@@ -0,0 +1,26 @@
+{
+ "app": {
+ "bundleName": "com.ohos.myapplication",
+ "debug": true,
+ "versionCode": 1000000,
+ "versionName": "1.0.0",
+ "minAPIVersion": 40100011,
+ "targetAPIVersion": 40100011,
+ "apiReleaseType": "Beta1",
+ "compileSdkVersion": "4.1.0.55",
+ "compileSdkType": "HarmonyOS",
+ "bundleType": "app"
+ },
+ "module": {
+ "name": "hypium",
+ "type": "har",
+ "deviceTypes": [
+ "default",
+ "tablet",
+ "tv",
+ "wearable",
+ "car"
+ ],
+ "installationFree": false
+ }
+}
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/ExpectExtend.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/ExpectExtend.js
new file mode 100644
index 0000000000000000000000000000000000000000..d10d15e6f9955c6d04610101f8766c951ee1a35d
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/ExpectExtend.js
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import assertNull from './assertNull';
+import assertClose from './assertClose';
+import assertContain from './assertContain';
+import assertLess from './assertLess';
+import assertLarger from './assertLarger';
+import assertFail from './assertFail';
+import assertUndefined from './assertUndefined';
+import assertFalse from './assertFalse';
+import assertInstanceOf from './assertInstanceOf';
+import assertThrowError from './assertThrowError';
+import assertLargerOrEqual from './assertLargerOrEqual'
+import assertLessOrEqual from './assertLessOrEqual'
+import assertNaN from './assertNaN'
+import assertNegUnlimited from './assertNegUnlimited'
+import assertPosUnlimited from './assertPosUnlimited'
+import assertDeepEquals from './deepEquals/assertDeepEquals'
+import assertPromiseIsPending from './assertPromiseIsPending';
+import assertPromiseIsRejected from './assertPromiseIsRejected';
+import assertPromiseIsRejectedWith from './assertPromiseIsRejectedWith';
+import assertPromiseIsRejectedWithError from './assertPromiseIsRejectedWithError';
+import assertPromiseIsResolved from './assertPromiseIsResolved';
+import assertPromiseIsResolvedWith from './assertPromiseIsResolvedWith';
+class ExpectExtend {
+ constructor(attr) {
+ this.id = attr.id;
+ this.matchers = {};
+ }
+
+ extendsMatchers() {
+ this.matchers.assertNull = assertNull;
+ this.matchers.assertClose = assertClose;
+ this.matchers.assertContain = assertContain;
+ this.matchers.assertLess = assertLess;
+ this.matchers.assertLarger = assertLarger;
+ this.matchers.assertFail = assertFail;
+ this.matchers.assertUndefined = assertUndefined;
+ this.matchers.assertFalse = assertFalse;
+ this.matchers.assertInstanceOf = assertInstanceOf;
+ this.matchers.assertThrowError = assertThrowError;
+ this.matchers.assertLargerOrEqual = assertLargerOrEqual;
+ this.matchers.assertLessOrEqual = assertLessOrEqual;
+ this.matchers.assertNaN = assertNaN;
+ this.matchers.assertNegUnlimited = assertNegUnlimited;
+ this.matchers.assertPosUnlimited = assertPosUnlimited;
+ this.matchers.assertDeepEquals = assertDeepEquals;
+ this.matchers.assertPromiseIsPending = assertPromiseIsPending;
+ this.matchers.assertPromiseIsRejected = assertPromiseIsRejected;
+ this.matchers.assertPromiseIsRejectedWith = assertPromiseIsRejectedWith;
+ this.matchers.assertPromiseIsRejectedWithError = assertPromiseIsRejectedWithError;
+ this.matchers.assertPromiseIsResolved = assertPromiseIsResolved;
+ this.matchers.assertPromiseIsResolvedWith = assertPromiseIsResolvedWith;
+ }
+
+ init(coreContext) {
+ this.coreContext = coreContext;
+ this.extendsMatchers();
+ const expectService = this.coreContext.getDefaultService('expect');
+ expectService.addMatchers(this.matchers);
+ }
+
+ apis() {
+ return {
+ 'expect': function (actualValue) {
+ return this.coreContext.getDefaultService('expect').expect(actualValue);
+ }
+ };
+ }
+}
+
+export default ExpectExtend;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertClose.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertClose.js
new file mode 100644
index 0000000000000000000000000000000000000000..7e692bd25f1c026640978a042a9c9f64b0e8d5d3
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertClose.js
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertClose(actualValue, expected) {
+ if (actualValue === null && expected[0] === null) {
+ throw new Error('actualValue and expected can not be both null!!!');
+ }
+ let result;
+ let diff = Math.abs(expected[0] - actualValue);
+ let actualAbs = Math.abs(actualValue);
+ if ((actualAbs - 0) === 0) {
+ if ((diff - 0) === 0) {
+ result = true;
+ } else {
+ result = false;
+ }
+ } else if (diff / actualAbs < expected[1]) {
+ result = true;
+ } else {
+ result = false;
+ }
+ return {
+ pass: result,
+ message: '|' + actualValue + ' - ' + expected[0] + '|/' + actualValue + ' is not less than ' + expected[1]
+ };
+}
+
+export default assertClose;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertContain.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertContain.js
new file mode 100644
index 0000000000000000000000000000000000000000..7fba0d9755503e5e926f6c1a4e425e0d1cf47570
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertContain.js
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertContain(actualValue, expect) {
+ let result = false;
+ if (Object.prototype.toString.call(actualValue).indexOf('Array')) {
+ for (let i in actualValue) {
+ if (actualValue[i] == expect[0]) {
+ result = true;
+ }
+ }
+ }
+ let type = Object.prototype.toString.call(actualValue);
+ if (type === '[object String]') {
+ result = actualValue.indexOf(expect[0]) >= 0;
+ }
+ return {
+ pass: result,
+ message: 'expect false, ' + actualValue + ' do not have ' + expect[0]
+ };
+}
+
+export default assertContain;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertFail.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertFail.js
new file mode 100644
index 0000000000000000000000000000000000000000..8ab4ac5caef712c75c4eac49dfbbb91d33669d9a
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertFail.js
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertFail() {
+ return {
+ pass: false,
+ message: 'fail '
+ };
+}
+
+export default assertFail;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertFalse.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertFalse.js
new file mode 100644
index 0000000000000000000000000000000000000000..c5008e94f4b2ce13ed35b604811793c76b542347
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertFalse.js
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertFalse(actualValue) {
+ return {
+ pass: (actualValue) === false,
+ message: 'expect false, actualValue is ' + actualValue
+ };
+}
+
+export default assertFalse;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertInstanceOf.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertInstanceOf.js
new file mode 100644
index 0000000000000000000000000000000000000000..1e11b93f7251c67f5455c5007cd7be268aa53b32
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertInstanceOf.js
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertInstanceOf(actualValue, expected) {
+ if (Object.prototype.toString.call(actualValue) == '[object ' + expected[0] + ']') {
+ return {
+ pass: true
+ };
+ } else {
+ return {
+ pass: false,
+ message: actualValue + ' is ' + Object.prototype.toString.call(actualValue) + 'not ' + expected[0]
+ };
+ }
+}
+
+export default assertInstanceOf;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertLarger.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertLarger.js
new file mode 100644
index 0000000000000000000000000000000000000000..a74f4a8cedaf3add9c2dc2d3799081a83198732f
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertLarger.js
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertLarger(actualValue, expected) {
+ return {
+ pass: (actualValue) > expected[0],
+ message: (actualValue) + ' is not larger than ' + expected[0]
+ };
+}
+
+export default assertLarger;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertLargerOrEqual.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertLargerOrEqual.js
new file mode 100644
index 0000000000000000000000000000000000000000..e847e6c217364b7f69c173c66fb98d10efc45ef1
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertLargerOrEqual.js
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertLargerOrEqual(actualValue, expected) {
+ return {
+ pass: (actualValue) >= expected[0],
+ message: (actualValue) + ' is not larger than ' + expected[0]
+ };
+}
+
+export default assertLargerOrEqual;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertLess.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertLess.js
new file mode 100644
index 0000000000000000000000000000000000000000..17e84b0abaeb20804048a5a15c19e0603634846d
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertLess.js
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertLess(actualValue, expected) {
+ return {
+ pass: (actualValue) < expected[0],
+ message: (actualValue) + ' is not less than ' + expected[0]
+ };
+}
+
+export default assertLess;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertLessOrEqual.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertLessOrEqual.js
new file mode 100644
index 0000000000000000000000000000000000000000..f754f97ffa9d24e7852efe2423a1dd35d448af82
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertLessOrEqual.js
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertLessOrEqual(actualValue, expected) {
+ return {
+ pass: (actualValue) <= expected[0],
+ message: (actualValue) + ' is not less than ' + expected[0]
+ };
+}
+
+export default assertLessOrEqual;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertNaN.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertNaN.js
new file mode 100644
index 0000000000000000000000000000000000000000..8d45d6a93b86c5ed325a68b32ff014835993a58e
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertNaN.js
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertNaN(actualValue) {
+ return {
+ pass: actualValue !== actualValue,
+ message: 'expect NaN, actualValue is ' + actualValue
+ };
+}
+
+export default assertNaN;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertNegUnlimited.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertNegUnlimited.js
new file mode 100644
index 0000000000000000000000000000000000000000..ceac555afc826e057970e6cfe9c73b322c672aa2
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertNegUnlimited.js
@@ -0,0 +1,23 @@
+/*
+* Copyright (c) 2022 Huawei Device Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+function assertNegUnlimited(actualValue) {
+ return {
+ pass: actualValue === Number.NEGATIVE_INFINITY,
+ message: 'Expected actualValue not to be -Infinity. actualValue is,' + actualValue
+ };
+}
+
+export default assertNegUnlimited;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertNull.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertNull.js
new file mode 100644
index 0000000000000000000000000000000000000000..53a7bad827323a98d3302a4e7eea679551b459c5
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertNull.js
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertNull(actualValue) {
+ return {
+ pass: (actualValue) === null,
+ message: 'expect null, actualValue is ' + (actualValue)
+ };
+}
+
+export default assertNull;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertPosUnlimited.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertPosUnlimited.js
new file mode 100644
index 0000000000000000000000000000000000000000..6e68c0e2b6c499f4dc3dd56c13e9ea1073a3c54c
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertPosUnlimited.js
@@ -0,0 +1,23 @@
+/*
+* Copyright (c) 2022 Huawei Device Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+function assertPosUnlimited(actualValue) {
+ return {
+ pass: actualValue === Number.POSITIVE_INFINITY,
+ message: 'Expected actualValue is POSITIVE_INFINITY. actualValue is,' + actualValue
+ };
+}
+
+export default assertPosUnlimited;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsPending.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsPending.js
new file mode 100644
index 0000000000000000000000000000000000000000..7e2ca2ce14d50c39554fc1157d6d4eb9329d5c39
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsPending.js
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import isPromiseLike from './isPromiseLike';
+
+function assertPromiseIsPending(actualPromise) {
+ if (!isPromiseLike(actualPromise)) {
+ return Promise.reject().then(function () {
+ }, function () {
+ return {pass: false, message: 'Expected not be called on a promise.'};
+ });
+ }
+ const helper = {};
+ return Promise.race([actualPromise, Promise.resolve(helper)]).then(
+ function (got) {
+ return helper === got ? {pass: true, message: 'actualValue is isPending'}
+ : {
+ pass: false,
+ message: 'expect isPending, actualValue is resolve'
+ };
+ },
+ function () {
+ return {
+ pass: false
+ , message: 'expect isPending, actualValue is reject'
+ };
+ });
+}
+
+export default assertPromiseIsPending;
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsRejected.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsRejected.js
new file mode 100644
index 0000000000000000000000000000000000000000..380075a369a84d6856e7f2db366f704e04302a8d
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsRejected.js
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import isPromiseLike from './isPromiseLike';
+
+function assertPromiseIsRejected(actualPromise) {
+ if (!isPromiseLike(actualPromise)) {
+ return Promise.reject().then(function () {
+ }, function () {
+ return {pass: false, message: 'Expected not be called on a promise.'};
+ });
+ }
+ return actualPromise.then(
+ function (got) {
+ return {
+ pass: false,
+ message: 'expect isRejected, but actualValue is resolve'
+ };
+ },
+ function () {
+ return {pass: true, message: 'actualValue is isRejected'};
+ }
+ );
+}
+
+export default assertPromiseIsRejected;
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsRejectedWith.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsRejectedWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..8179589d5580f9c305d2200b4b197d64ac9d53ae
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsRejectedWith.js
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import isPromiseLike from './isPromiseLike';
+
+function assertPromiseIsRejectedWith(actualPromise, expectedValue) {
+
+ if (!isPromiseLike(actualPromise)) {
+ return Promise.reject().then(function () {
+ }, function () {
+ return {pass: false, message: 'Expected not be called on a promise.'};
+ });
+ }
+
+ function tips(passed) {
+ return ('Expected a promise ' + (passed ? 'not ' : '') +
+ 'to be rejected with ' + JSON.stringify(expectedValue[0]));
+ }
+
+ return actualPromise.then(
+ function (got) {
+ return {
+ pass: false,
+ message: tips(false) + ' but actualValue is resolve'
+ };
+ },
+ function (actualValue) {
+ if (JSON.stringify(actualValue) == JSON.stringify(expectedValue[0])) {
+ return {
+ pass: true,
+ message: 'actualValue was rejected with ' + JSON.stringify(actualValue) + '.'
+ };
+ } else {
+ return {
+ pass: false,
+ message: tips(false) + ' but it was rejected with ' + JSON.stringify(actualValue) + '.'
+ };
+ }
+ }
+ );
+}
+
+export default assertPromiseIsRejectedWith;
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsRejectedWithError.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsRejectedWithError.js
new file mode 100644
index 0000000000000000000000000000000000000000..291af8e5032b7bcd9bcb3e996a39a4fa8ba23157
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsRejectedWithError.js
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import isPromiseLike from './isPromiseLike';
+
+function assertPromiseIsRejectedWithError(actualPromise, expectedValue) {
+ if (!isPromiseLike(actualPromise)) {
+ return Promise.reject().then(function () {
+ }, function () {
+ return {pass: false, message: 'Expected not be called on a promise.'};
+ });
+ }
+ return actualPromise.then(
+ function (got) {
+ return {
+ pass: false,
+ message: 'Expected a promise to be rejected but actualValue is resolve'
+ };
+ },
+ function (actualValue) {
+ return matchError(actualValue, expectedValue);
+ }
+ );
+
+}
+
+function matchError(actualValue, expectedValue) {
+ if (expectedValue.length == 1 && typeof expectedValue[0] === 'function') {
+ if (expectedValue[0].name === actualValue.__proto__.name) {
+ return {pass: true, message: 'actual error type is ' + actualValue.name + '.'};
+ }
+ return {pass: false, message: `except error type is ${expectedValue[0].name},but actual is ${actualValue.name}.`};
+ }
+
+ if (expectedValue.length == 1 && typeof expectedValue[0] === 'string') {
+ if (expectedValue[0] === actualValue.message) {
+ return {pass: true, message: `actual error message is ${actualValue.message}.`};
+ }
+ return {pass: false, message: `except error message ${expectedValue[0]},but actual is ${actualValue.message}.`};
+ }
+
+ if (expectedValue.length == 1) {
+ return {pass: false, message: 'When only one parameter, it should be error type or error message.'};
+ }
+
+ if (expectedValue.length == 2 && typeof expectedValue[0] === 'function' && expectedValue[0].name === actualValue.name) {
+ if (typeof expectedValue[1] === 'string' && actualValue.message === expectedValue[1]) {
+ return {pass: true, message: 'actual error message is ' + actualValue.message + '.'};
+ }
+ return {pass: false, message: `except error message is ${expectedValue[1]},but actual is ${actualValue.message}.`};
+ }
+
+ if (expectedValue.length == 2 && typeof expectedValue[0] === 'function' && expectedValue[0].name !== actualValue.name) {
+ if (typeof expectedValue[1] === 'string' && actualValue.message === expectedValue[1]) {
+ return {pass: false, message: `except error type is ${expectedValue[0].name},but actual is ${actualValue.name}.`};
+ }
+ return {pass: false, message: 'except error type and message are incorrect.'};
+ }
+ if (expectedValue.length > 2) {
+ return {pass: false, message: 'Up to two parameters are supported.'};
+ }
+}
+
+export default assertPromiseIsRejectedWithError;
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsResolved.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsResolved.js
new file mode 100644
index 0000000000000000000000000000000000000000..86f559c32873f27b95d635452d760029de0ed657
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsResolved.js
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import isPromiseLike from './isPromiseLike';
+
+function assertPromiseIsResolved(actualPromise) {
+ if (!isPromiseLike(actualPromise)) {
+ return Promise.reject().then(function () {
+ }, function () {
+ return {pass: false, message: 'Expected not be called on a promise.'};
+ });
+ }
+
+ return actualPromise.then(
+ function (got) {
+ return {pass: true, message: 'actualValue is isResolved'};
+ },
+ function (rej) {
+ return {
+ pass: false,
+ message: 'Expected a promise to be resolved but it was ' +
+ 'rejected with ' + JSON.stringify(rej) + '.'
+ };
+ }
+ );
+}
+
+export default assertPromiseIsResolved;
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsResolvedWith.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsResolvedWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..c6f0ef68fde5b04a589a9fa3c6e2ab2b39acf4d3
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertPromiseIsResolvedWith.js
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import isPromiseLike from './isPromiseLike';
+
+function assertPromiseIsResolvedWith(actualPromise, expectedValue) {
+ if (!isPromiseLike(actualPromise)) {
+ return Promise.reject().then(function () {
+ }, function () {
+ return {pass: false, message: 'Expected not be called on a promise.'};
+ });
+ }
+
+ function tips(passed) {
+ return (
+ 'Expected a promise ' + (passed ? 'not ' : '') +
+ 'to be resolved with ' + JSON.stringify(expectedValue[0]));
+ }
+
+ return actualPromise.then(
+ function (got) {
+ if (JSON.stringify(got) == JSON.stringify(expectedValue[0])) {
+ return {
+ pass: true,
+ message: 'actualValue was resolved with ' + JSON.stringify(got) + '.'
+ };
+ }
+ return {
+ pass: false,
+ message: tips(false) + ' but it was resolved with ' +
+ JSON.stringify(got) + '.'
+ };
+ },
+ function (rej) {
+ return {
+ pass: false,
+ message: tips(false) + ' but it was rejected with ' + JSON.stringify(rej) + '.'
+ };
+ }
+ );
+}
+
+export default assertPromiseIsResolvedWith;
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertThrowError.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertThrowError.js
new file mode 100644
index 0000000000000000000000000000000000000000..c4544a7f825bcecd1a07d5e98dd9a7b99d237278
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertThrowError.js
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertThrowError(actualValue, expected) {
+ let result = false;
+ let message = '';
+ let err;
+ if (typeof actualValue !== 'function') {
+ throw new Error('actualValue is not a function');
+ }
+ try {
+ actualValue();
+ return {
+ pass: result,
+ message: ' An error is not thrown while it is expected!'
+ };
+ } catch (e) {
+ err = e;
+ }
+ if (err instanceof Error) {
+ let type = typeof expected[0];
+ if (type === 'function') {
+ result = err.constructor.name === expected[0].name;
+ message = 'expected throw failed , ' + err.constructor.name + ' is not ' + expected[0].name;
+ }else if(type === 'string'){
+ result = err.message.includes(expected[0]);
+ message = 'expected throw failed , ' + err.message + ' is not ' + expected[0];
+ }
+ }
+ return {
+ pass: result,
+ message: message
+ };
+}
+
+export default assertThrowError;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertUndefined.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertUndefined.js
new file mode 100644
index 0000000000000000000000000000000000000000..61f092d715dd1630297518b59ff13ef0940991e1
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/assertUndefined.js
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function assertUndefined(actualValue) {
+ return {
+ pass: undefined === (actualValue),
+ message: 'expect Undefined, actualValue is ' + (actualValue)
+ };
+}
+
+export default assertUndefined;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/deepEquals/DeepTypeUtils.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/deepEquals/DeepTypeUtils.js
new file mode 100644
index 0000000000000000000000000000000000000000..916824d9cb77a75d1fb35bc3500d7598bfc73e80
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/deepEquals/DeepTypeUtils.js
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class DeepTypeUtils {
+ static getType(value) {
+ return Object.prototype.toString.apply(value);
+ }
+ static isA(typeName, value) {
+ return this.getType(value) === '[object ' + typeName + ']';
+ }
+ static isAsymmetricEqualityTester(obj) {
+ return obj ? this.isA('Function', obj.asymmetricMatch) : false;
+ }
+
+ /**
+ * 是否是function
+ * @param value
+ */
+ static isFunction(value) {
+ return this.isA('Function', value);
+ }
+
+ /**
+ * 是否是undefined
+ * @param obj
+ */
+ static isUndefined(obj) {
+ return obj === void 0;
+ }
+
+ /**
+ * 是否是Node
+ * @param obj
+ */
+ static isDomNode(obj) {
+ return obj !== null &&
+ typeof obj === 'object' &&
+ typeof obj.nodeType === 'number' &&
+ typeof obj.nodeName === 'string';
+ }
+
+ /**
+ * 是否是promise对象
+ * @param obj
+ */
+ static isPromise(obj) {
+ return !!obj && obj.constructor === Promise;
+ };
+ /**
+ * 是否是map对象
+ * @param obj
+ */
+ static isMap(obj) {
+ return (
+ obj !== null &&
+ typeof obj !== 'undefined' &&
+ obj.constructor === Map
+ );
+ }
+
+ /**
+ * 是否是set对象
+ * @param obj 对象
+ */
+ static isSet(obj) {
+ return (
+ obj !== null &&
+ typeof obj !== 'undefined' &&
+ obj.constructor === Set
+ );
+ }
+
+ /**
+ * 对象是否有key属性
+ * @param obj 对象
+ * @param key 对象属性名称
+ */
+ static has(obj, key) {
+ return Object.prototype.hasOwnProperty.call(obj, key);
+ }
+
+ /**
+ * 获取对象的自有属性
+ * @param obj 对象
+ * @param isArray 是否是数组,[object Array]
+ */
+ static keys(obj, isArray) {
+ const extraKeys = [];
+ // 获取对象所有属性
+ const allKeys = this.getAllKeys(obj);
+ if (!isArray) {
+ return allKeys;
+ }
+ if (allKeys.length === 0) {
+ return allKeys;
+ }
+ for (const k of allKeys) {
+ if (typeof k === 'symbol' || !/^[0-9]+$/.test(k)) {
+ extraKeys.push(k);
+ }
+ }
+ return extraKeys;
+ }
+
+ /**
+ * 获取obj对象的所有属性
+ * @param obj obj对象
+ */
+ static getAllKeys(obj) {
+ const keys = [];
+ for (let key in obj) {
+ if (this.has(obj, key)) {
+ keys.push(key);
+ }
+ }
+ const symbols = Object.getOwnPropertySymbols(obj);
+ for (const sym of symbols) {
+ // obj.propertyIsEnumerable(sym)
+ if (Object.prototype.propertyIsEnumerable.call(obj, sym)) {
+ keys.push(sym);
+ }
+ }
+ return keys;
+ }
+
+}
+export default DeepTypeUtils;
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/deepEquals/assertDeepEquals.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/deepEquals/assertDeepEquals.js
new file mode 100644
index 0000000000000000000000000000000000000000..60de33f7e1afdcfaf205c8c56484ef33dfda8160
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/deepEquals/assertDeepEquals.js
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import DeepTypeUtils from './DeepTypeUtils';
+function assertDeepEquals(actualValue, expected) {
+ let result = eq(actualValue, expected[0])
+ let msg = logMsg(actualValue, expected[0]);
+ return {
+ pass: result,
+ message: msg
+ };
+}
+
+/**
+ * 获取失败显示日志
+ * @param actualValue 实际对象
+ * @param expected 期待比较对象
+ */
+function logMsg(actualValue, expected) {
+ // 获取a的对象名称
+ const aClassName = Object.prototype.toString.call(actualValue);
+ const bClassName = Object.prototype.toString.call(expected);
+ let actualMsg;
+ let expectMsg;
+ if (aClassName == '[object Function]') {
+ actualMsg = 'actualValue Function';
+ } else if (aClassName == '[object Promise]') {
+ actualMsg = 'actualValue Promise';
+ } else if (aClassName == '[object Set]' || aClassName == '[object Map]') {
+ actualMsg = JSON.stringify(Array.from(actualValue));
+ } else if (aClassName == '[object RegExp]') {
+ actualMsg = JSON.stringify(actualValue.source.replace('\\',''));
+ } else if (aClassName == '[object BigInt]') {
+ actualMsg = actualValue;
+ } else if (aClassName == '[object Error]') {
+ actualMsg = actualValue.message;
+ } else if (aClassName == '[object ArrayBuffer]') {
+ actualMsg = actualValue.byteLength;
+ }
+ else {
+ actualMsg = JSON.stringify(actualValue);
+ }
+ if (bClassName == '[object Function]') {
+ expectMsg = 'expected Function';
+ } else if (bClassName == '[object Promise]') {
+ expectMsg = 'expected Promise';
+ } else if (bClassName == '[object Set]' || bClassName == '[object Map]') {
+ expectMsg = JSON.stringify(Array.from(expected));
+ } else if (bClassName == '[object RegExp]') {
+ expectMsg = JSON.stringify(expected.source.replace('\\',''));
+ } else if (bClassName == '[object BigInt]') {
+ expectMsg = expected;
+ } else if (bClassName == '[object Error]') {
+ expectMsg = expected.message;
+ } else if (bClassName == '[object ArrayBuffer]') {
+ expectMsg = expected.byteLength;
+ }
+ else {
+ expectMsg = JSON.stringify(expected);
+ }
+ return actualMsg + ' is not deep equal ' + expectMsg;
+}
+
+function eq(a, b) {
+ let result = true;
+
+ if (a === b) {
+ result = a !== 0 || 1 / a === 1 / b;
+ return result;
+ }
+
+ if (a === null || b === null) {
+ result = a === b;
+ return result;
+ }
+ // 获取a的对象名称
+ const aClassName = Object.prototype.toString.call(a);
+ const bClassName = Object.prototype.toString.call(b);
+ // 不同类型不同对象
+ if (aClassName !== bClassName) {
+ return false;
+ }
+ if (aClassName === '[object String]' || aClassName === '[object Number]' || aClassName === '[object Date]' ||
+ aClassName === '[object Boolean]' || aClassName === '[object ArrayBuffer]' ||
+ aClassName === '[object RegExp]' || aClassName === '[object Error]') {
+ result = isEqualSampleObj(a, b);
+ return result;
+ }
+
+ if (typeof a !== 'object' || typeof b !== 'object') {
+ return false;
+ }
+
+ if (DeepTypeUtils.isDomNode(a) || DeepTypeUtils.isPromise(a) || DeepTypeUtils.isFunction(a)) {
+ result = isEqualNodeOrPromiseOrFunction(a, b);
+ return result;
+ }
+
+ if (aClassName === '[object Array]' || aClassName === '[object Map]' || aClassName === '[object Set]') {
+ result = isEqualCollection(a, b);
+ return result;
+ }
+
+ result = isEqualObj(a, b);
+ return result;
+}
+
+function isEqualNodeOrPromiseOrFunction(a, b) {
+ let equalNodeOrPromiseOrFunction = true;
+ if (DeepTypeUtils.isDomNode(a) && DeepTypeUtils.isDomNode(b)) {
+ const aIsDomNode = DeepTypeUtils.isDomNode(a);
+ const bIsDomNode = DeepTypeUtils.isDomNode(b);
+ if (aIsDomNode && bIsDomNode) {
+ // At first try to use DOM3 method isEqualNode
+ equalNodeOrPromiseOrFunction = a.isEqualNode(b);
+ return equalNodeOrPromiseOrFunction;
+ }
+ if (aIsDomNode || bIsDomNode) {
+ equalNodeOrPromiseOrFunction = false;
+ return false;
+ }
+ }
+
+ if (DeepTypeUtils.isPromise(a) && DeepTypeUtils.isPromise(b)) {
+ const aIsPromise = DeepTypeUtils.isPromise(a);
+ const bIsPromise = DeepTypeUtils.isPromise(b);
+ // 俩个Promise对象
+ if (aIsPromise && bIsPromise) {
+ equalNodeOrPromiseOrFunction = a === b;
+ return a === b;
+ }
+ }
+ if (DeepTypeUtils.isFunction(a) && DeepTypeUtils.isFunction(b)) {
+ // 俩个函数对象
+ const aCtor = a.constructor,
+ bCtor = b.constructor;
+ if (
+ aCtor !== bCtor &&
+ DeepTypeUtils.isFunction(aCtor) &&
+ DeepTypeUtils.isFunction(bCtor) &&
+ a instanceof aCtor &&
+ b instanceof bCtor &&
+ !(aCtor instanceof aCtor && bCtor instanceof bCtor)
+ ) {
+ equalNodeOrPromiseOrFunction = false;
+ return false;
+ }
+ }
+ return equalNodeOrPromiseOrFunction;
+}
+
+function isEqualCollection(a, b) {
+ let equalCollection = true;
+ // 获取a的对象名称
+ const aClassName = Object.prototype.toString.call(a);
+ const bClassName = Object.prototype.toString.call(b);
+ // 都是数组
+ if (aClassName === '[object Array]') {
+ equalCollection = isEqualArray(a, b);
+ return equalCollection;
+ }
+
+ // 都是Map
+ if (DeepTypeUtils.isMap(a) && DeepTypeUtils.isMap(b)) {
+ equalCollection = isEqualMap(a, b);
+ return equalCollection;
+ }
+
+ // 都是Set
+ if (DeepTypeUtils.isSet(a) && DeepTypeUtils.isSet(b)) {
+ equalCollection = isEqualSet(a, b);
+ return equalCollection;
+ }
+
+ return true;
+}
+
+function isEqualSampleObj(a, b) {
+ let equalSampleObj = true;
+ const aClassName = Object.prototype.toString.call(a);
+ const bClassName = Object.prototype.toString.call(b);
+ // 俩个string对象
+ if (aClassName === '[object String]') {
+ equalSampleObj = a === String(b);
+ return equalSampleObj;
+ }
+ // 俩个Number对象
+ if (aClassName === '[object Number]') {
+ equalSampleObj = a !== +a ? b !== +b : a === 0 && b === 0 ? 1 / a === 1 / b : a === +b;
+ return equalSampleObj;
+ }
+
+ // 俩个Date对象/ boolean对象
+ if (aClassName === '[object Date]' || aClassName === '[object Boolean]') {
+ equalSampleObj = +a === +b;
+ return equalSampleObj;
+ }
+
+ // 俩个ArrayBuffer
+ if (aClassName === '[object ArrayBuffer]') {
+ equalSampleObj = eq(new Uint8Array(a), new Uint8Array(b));
+ return equalSampleObj;
+ }
+
+ // 正则表达式
+ if (aClassName === '[object RegExp]') {
+ return (
+ a.source === b.source &&
+ a.global === b.global &&
+ a.multiline === b.multiline &&
+ a.ignoreCase === b.ignoreCase
+ );
+ }
+
+ if (a instanceof Error && b instanceof Error) {
+ equalSampleObj = a.message === b.message;
+ return equalSampleObj;
+ }
+
+ return equalSampleObj;
+}
+
+function isEqualObj(a, b) {
+ let equalObj = true;
+ const aClassName = Object.prototype.toString.call(a);
+ const bClassName = Object.prototype.toString.call(b);
+ const aKeys = DeepTypeUtils.keys(a, aClassName === '[object Array]');
+ let size = aKeys.length;
+
+ // 俩个对象属性长度不一致, 俩对象不相同
+ if (DeepTypeUtils.keys(b, bClassName === '[object Array]').length !== size) {
+ return false;
+ }
+
+ // 俩对象属性数量相同, 递归比较每个属性值得值
+ for (const key of aKeys) {
+ // b 没有 key 属性
+ if (!DeepTypeUtils.has(b, key)) {
+ equalObj = false;
+ continue;
+ }
+ if (!eq(a[key], b[key])) {
+ equalObj = false;
+ }
+ }
+ return equalObj;
+}
+
+function isEqualArray(a, b) {
+ let equalArray = true;
+ const aLength = a.length;
+ const bLength = b.length;
+ if (aLength !== bLength) {
+ // 数组长度不同,不是同一个对象
+ return false;
+ }
+ for (let i = 0; i < aLength || i < bLength; i++) {
+ // 递归每一个元素是否相同
+ equalArray = eq(i < aLength ? a[i] : void 0, i < bLength ? b[i] : void 0) && equalArray;
+ }
+ return equalArray;
+}
+
+function isEqualMap(a, b) {
+ let equalMap = true;
+ if (a.size !== b.size) {
+ return false;
+ }
+ const keysA = [];
+ const keysB = [];
+ a.forEach(function(valueA, keyA) {
+ keysA.push(keyA);
+ });
+ b.forEach(function(valueB, keyB) {
+ keysB.push(keyB);
+ });
+ const mapKeys = [keysA, keysB];
+ const cmpKeys = [keysB, keysA];
+ for (let i = 0; equalMap && i < mapKeys.length; i++) {
+ const mapIter = mapKeys[i];
+ const cmpIter = cmpKeys[i];
+
+ for (let j = 0; equalMap && j < mapIter.length; j++) {
+ const mapKey = mapIter[j];
+ const cmpKey = cmpIter[j];
+ const mapValueA = a.get(mapKey);
+ let mapValueB;
+ if (eq(mapKey, cmpKey)) {
+ mapValueB = b.get(cmpKey);
+ } else {
+ mapValueB = b.get(mapKey);
+ }
+ equalMap = eq(mapValueA, mapValueB);
+ }
+ }
+ return equalMap;
+}
+
+function isEqualSet(a, b) {
+ let equalSet = true;
+ if (a.size !== b.size) {
+ return false;
+ }
+ const valuesA = [];
+ a.forEach(function(valueA) {
+ valuesA.push(valueA);
+ });
+ const valuesB = [];
+ b.forEach(function(valueB) {
+ valuesB.push(valueB);
+ });
+ const setPairs = [[valuesA, valuesB], [valuesB, valuesA]];
+ for (let i = 0; equalSet && i < setPairs.length; i++) {
+ const baseValues = setPairs[i][0];
+ const otherValues = setPairs[i][1];
+ for (const baseValue of baseValues) {
+ let found = false;
+ for (let j = 0; !found && j < otherValues.length; j++) {
+ const otherValue = otherValues[j];
+ // 深度比较对象
+ found = eq(baseValue, otherValue);
+ }
+ equalSet = equalSet && found;
+ }
+ }
+ return equalSet;
+}
+
+export default assertDeepEquals;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/isPromiseLike.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/isPromiseLike.js
new file mode 100644
index 0000000000000000000000000000000000000000..015ab19a2a0c4872d7cb490b61f8e1dd6a8ac90b
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/assert/isPromiseLike.js
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function isPromiseLike(obj) {
+ return !!obj && isFunction_(obj.then);
+}
+
+function isFunction_(value) {
+ return isA_('Function', value);
+}
+
+function isA_(typeName, value) {
+ return getType_(value) === '[object ' + typeName + ']';
+}
+
+function getType_(value) {
+ return Object.prototype.toString.apply(value);
+}
+
+export default isPromiseLike;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/config/DataDriver.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/config/DataDriver.js
new file mode 100644
index 0000000000000000000000000000000000000000..639dffc9cdb912f1f33a6ccb61868c9ed7c695bf
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/config/DataDriver.js
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+const SUITES_KEY = 'suites';
+const SPECS_KEY = 'items';
+const DESCRIBE_KEY = 'describe';
+const IT_KEY = 'it';
+const PARAMS_KEY = 'params';
+const STRESS_KEY = 'stress';
+
+class ObjectUtils {
+ static get(object, name, defaultValue) {
+ let result = defaultValue;
+ for (const key in object) {
+ if (key === name) {
+ return object[key];
+ }
+ }
+ return result;
+ }
+
+ static has(object, key) {
+ return Object.prototype.hasOwnProperty.call(object, key);
+ }
+}
+
+class DataDriver {
+ constructor(attr) {
+ this.id = 'dataDriver';
+ this.data = attr.data || {};
+ }
+
+ init(coreContext) {
+ this.coreContext = coreContext;
+ this.suiteService = this.coreContext.getDefaultService('suite');
+ this.specService = this.coreContext.getDefaultService('spec');
+ }
+
+ getSpecParams() {
+ let specParams = [];
+ let suiteDesc = this.suiteService.getCurrentRunningSuite().description;
+ let specDesc = this.specService.getCurrentRunningSpec().description;
+ let suites = ObjectUtils.get(this.data, SUITES_KEY, []);
+ for (const suiteItem of suites) {
+ let describeValue = ObjectUtils.get(suiteItem, DESCRIBE_KEY, '');
+ if (ObjectUtils.has(suiteItem, DESCRIBE_KEY) && (typeof describeValue === 'object') && describeValue.constructor === Array && describeValue.includes(suiteDesc)) {
+ let specs = ObjectUtils.get(suiteItem, SPECS_KEY, []);
+ for (const specItem of specs) {
+ if (ObjectUtils.has(specItem, IT_KEY) && ObjectUtils.get(specItem, IT_KEY) === specDesc) {
+ return ObjectUtils.get(specItem, PARAMS_KEY, specParams);
+ }
+ }
+ }
+ }
+ return specParams;
+ }
+
+ getSuiteParams() {
+ let suiteParams = {};
+ let suiteDesc = this.suiteService.getCurrentRunningSuite().description;
+ let suites = ObjectUtils.get(this.data, SUITES_KEY, []);
+ for (const suiteItem of suites) {
+ let describeValue = ObjectUtils.get(suiteItem, DESCRIBE_KEY, []);
+ if (ObjectUtils.has(suiteItem, DESCRIBE_KEY) && (typeof describeValue === 'object') && describeValue.constructor === Array && describeValue.includes(suiteDesc)) {
+ suiteParams = Object.assign({}, suiteParams, ObjectUtils.get(suiteItem, PARAMS_KEY, suiteParams));
+ }
+ }
+ return suiteParams;
+ }
+
+ getSpecStress(specDesc) {
+ let stress = 1;
+ let suiteDesc = this.suiteService.getCurrentRunningSuite().description;
+ let suites = ObjectUtils.get(this.data, SUITES_KEY, []);
+ for (const suiteItem of suites) {
+ let describeValue = ObjectUtils.get(suiteItem, DESCRIBE_KEY, '');
+ if (ObjectUtils.has(suiteItem, DESCRIBE_KEY) && (typeof describeValue === 'object') && describeValue.constructor === Array && describeValue.includes(suiteDesc)) {
+ let specs = ObjectUtils.get(suiteItem, SPECS_KEY, []);
+ for (const specItem of specs) {
+ if (ObjectUtils.has(specItem, IT_KEY) && ObjectUtils.get(specItem, IT_KEY) === specDesc) {
+ let tempStress = ObjectUtils.get(specItem, STRESS_KEY, stress);
+ return (Number.isInteger(tempStress) && tempStress >= 1) ? tempStress : stress;
+ }
+ }
+ }
+ }
+ return stress;
+ }
+
+ getSuiteStress(suiteDesc) {
+ let stress = 1;
+ let suites = ObjectUtils.get(this.data, SUITES_KEY, []);
+ for (const suiteItem of suites) {
+ let describeValue = ObjectUtils.get(suiteItem, DESCRIBE_KEY, []);
+ if (ObjectUtils.has(suiteItem, DESCRIBE_KEY) && (typeof describeValue === 'object') && describeValue.constructor === Array && describeValue.includes(suiteDesc)) {
+ let tempStress = ObjectUtils.get(suiteItem, STRESS_KEY, stress);
+ return (Number.isInteger(tempStress) && tempStress >= 1) ? tempStress : stress;
+ }
+ }
+ return stress;
+ }
+}
+
+export default DataDriver;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/config/Filter.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/config/Filter.js
new file mode 100644
index 0000000000000000000000000000000000000000..b07e6c681bfff618cc9f5ca92ec85d1d9880202d
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/config/Filter.js
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { LEVEL, SIZE, TESTTYPE } from '../../Constant';
+
+class ClassFilter {
+ constructor(suiteName, itName, params) {
+ this.suiteName = suiteName;
+ this.itName = itName;
+ this.params = params;
+ }
+
+ filterSuite() {
+ return !this.params.split(',').map(item => item.split('#')[0]).map(item => item == this.suiteName).reduce((pre, cur) => pre || cur, false);
+ }
+
+ filterIt() {
+ let classArray = this.params.split(',') || [];
+ let suiteFilterResult = classArray.filter(item => !item.includes('#')).map(item => item == this.suiteName).reduce((pre, cur) => pre || cur, false);
+ let itFilterResult = classArray.filter(item => item.includes('#')).map(item => item == (this.suiteName + '#' + this.itName)).reduce((pre, cur) => pre || cur, false);
+ return !(suiteFilterResult || itFilterResult);
+ }
+}
+
+class NotClassFilter {
+ constructor(suiteName, itName, params) {
+ this.suiteName = suiteName;
+ this.itName = itName;
+ this.params = params;
+ }
+
+ filterSuite() {
+ return this.params.split(',').map(item => item == this.suiteName).reduce((pre, cur) => pre || cur, false);
+ }
+
+ filterIt() {
+ return this.params.split(',').some(item => item == (this.suiteName + '#' + this.itName));
+ }
+}
+
+class SuiteAndItNameFilter {
+ constructor(suiteName, itName, params) {
+ this.suiteName = suiteName;
+ this.itName = itName;
+ this.params = params;
+ }
+
+ filterSuite() {
+ return !this.params.split(',').map(item => item == this.suiteName).reduce((pre, cur) => pre || cur, false);
+ }
+
+ filterIt() {
+ return !this.params.split(',').map(item => item == this.itName).reduce((pre, cur) => pre || cur, false);
+ }
+}
+
+
+class TestTypesFilter {
+ constructor(suiteName, itName, fi, params) {
+ this.suiteName = suiteName;
+ this.itName = itName;
+ this.params = params;
+ this.fi = fi;
+ }
+
+ filterIt() {
+ return !((this.params === (this.fi & this.params)) || this.fi === 0);
+ }
+}
+
+class NestFilter {
+ filterNestName(targetSuiteArray, targetSpecArray, suiteStack, desc) {
+ let targetSuiteName = '';
+ for (let key in suiteStack) {
+ targetSuiteName = targetSuiteName + '.' + suiteStack[key].description;
+ }
+ targetSuiteName = targetSuiteName.substring(2);
+ const targetSpecName = targetSuiteName + '#' + desc;
+ let isFilter = true;
+ if (targetSpecArray.includes(targetSpecName)) {
+ return false;
+ }
+ for (let index in targetSuiteArray) {
+ if (targetSuiteName.startsWith(targetSuiteArray[index])) {
+ return false;
+ }
+ }
+ return isFilter;
+ }
+
+ filterNotClass(notClass, suiteStack, desc) {
+ let isFilterNotClass = false;
+ if (notClass != null) {
+ let notClassArray = notClass.split(',');
+ let targetSuiteName = '';
+ for (let key in suiteStack) {
+ targetSuiteName = targetSuiteName + '.' + suiteStack[key].description;
+ }
+ targetSuiteName = targetSuiteName.substring(2);
+ const targetSpecName = targetSuiteName + '#' + desc;
+ if (notClassArray.includes(targetSpecName) || notClassArray.some(key => targetSpecName.startsWith(key))) {
+ isFilterNotClass = true;
+ }
+ }
+ return isFilterNotClass;
+ }
+
+ filterLevelOrSizeOrTestType(level, size, testType, filter) {
+ let result = false;
+ if (filter === 0 || filter === '0') {
+ return result;
+ }
+ if (level == null && size == null && testType == null) {
+ return result;
+ }
+ if (level != null) {
+ let levelFilter = LEVEL[`${level}`];
+ result = result || filter === levelFilter;
+ }
+ if (size != null) {
+ let sizeFilter = SIZE[`${size}`];
+ result = result || filter === sizeFilter;
+ }
+ if (testType != null) {
+ let testTypeFilter = TESTTYPE[`${testType}`];
+ result = result || filter === testTypeFilter;
+ }
+ return !result;
+ }
+}
+export { ClassFilter, NotClassFilter, SuiteAndItNameFilter, TestTypesFilter, NestFilter };
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/config/configService.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/config/configService.js
new file mode 100644
index 0000000000000000000000000000000000000000..17674d8cf7e2343bcb4a14ad47eb11cd03c15aac
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/config/configService.js
@@ -0,0 +1,299 @@
+/*
+ * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { ClassFilter, NotClassFilter, SuiteAndItNameFilter, TestTypesFilter, NestFilter } from './Filter';
+import { TAG, TESTTYPE, LEVEL, SIZE, KEYSET } from '../../Constant';
+const STRESS_RULE = /^[1-9]\d*$/;
+
+class ConfigService {
+ constructor(attr) {
+ this.id = attr.id;
+ this.supportAsync = true; // 默认异步处理测试用例
+ this.random = false;
+ this.filterValid = [];
+ this.filter = 0;
+ this.flag = false;
+ this.suite = null;
+ this.itName = null;
+ this.testType = null;
+ this.level = null;
+ this.size = null;
+ this.class = null;
+ this.notClass = null;
+ this.timeout = null;
+ // 遇错即停模式配置
+ this.breakOnError = false;
+ // 压力测试配置
+ this.stress = null;
+ this.skipMessage = false;
+ this.runSkipped = '';
+ this.filterXdescribe = [];
+ }
+
+ init(coreContext) {
+ this.coreContext = coreContext;
+ }
+
+ isNormalInteger(str) {
+ const n = Math.floor(Number(str));
+ return n !== Infinity && String(n) === String(str) && n >= 0;
+ }
+
+
+ getStress() {
+ if (this.stress === undefined || this.stress === '' || this.stress === null) {
+ return 1;
+ }
+ return !this.stress.match(STRESS_RULE) ? 1 : Number.parseInt(this.stress);
+ }
+
+ basicParamValidCheck(params) {
+ let size = params.size;
+ if (size !== undefined && size !== '' && size !== null) {
+ let sizeArray = ['small', 'medium', 'large'];
+ if (sizeArray.indexOf(size) === -1) {
+ this.filterValid.push('size:' + size);
+ }
+ }
+ let level = params.level;
+ if (level !== undefined && level !== '' && level !== null) {
+ let levelArray = ['0', '1', '2', '3', '4'];
+ if (levelArray.indexOf(level) === -1) {
+ this.filterValid.push('level:' + level);
+ }
+ }
+ let testType = params.testType;
+ if (testType !== undefined && testType !== '' && testType !== null) {
+ let testTypeArray = ['function', 'performance', 'power', 'reliability', 'security',
+ 'global', 'compatibility', 'user', 'standard', 'safety', 'resilience'];
+ if (testTypeArray.indexOf(testType) === -1) {
+ this.filterValid.push('testType:' + testType);
+ }
+ }
+ }
+
+ filterParamValidCheck(params) {
+ let timeout = params.timeout;
+ if (timeout !== undefined && timeout !== '' && timeout !== null) {
+ if (!this.isNormalInteger(timeout)) {
+ this.filterValid.push('timeout:' + timeout);
+ }
+ }
+
+ let paramKeys = ['dryRun', 'random', 'breakOnError', 'coverage', 'skipMessage'];
+ for (const key of paramKeys) {
+ if (params[key] !== undefined && params[key] !== 'true' && params[key] !== 'false') {
+ this.filterValid.push(`${key}:${params[key]}`);
+ }
+ }
+
+ // 压力测试参数验证,正整数
+ if (params.stress !== undefined && params.stress !== '' && params.stress !== null) {
+ if (!params.stress.match(STRESS_RULE)) {
+ this.filterValid.push('stress:' + params.stress);
+ }
+ }
+
+ let nameRule = /^[A-Za-z]{1}[\w#,.]*$/;
+ let paramClassKeys = ['class', 'notClass'];
+ for (const key of paramClassKeys) {
+ if (params[key] !== undefined && params[key] !== '' && params[key] !== null) {
+ let classArray = params[key].split(',');
+ classArray.forEach(item => !item.match(nameRule) ? this.filterValid.push(`${key}:${params[key]}`) : null);
+ }
+ }
+ }
+
+ setConfig(params) {
+ this.basicParamValidCheck(params);
+ this.filterParamValidCheck(params);
+ try {
+ this.class = params.class;
+ this.notClass = params.notClass;
+ this.flag = params.flag || { flag: false };
+ this.suite = params.suite;
+ this.itName = params.itName;
+ this.filter = params.filter;
+ this.testType = params.testType;
+ this.level = params.level;
+ this.size = params.size;
+ this.timeout = params.timeout;
+ this.dryRun = params.dryRun;
+ this.breakOnError = params.breakOnError;
+ this.random = params.random === 'true' ? true : false;
+ this.stress = params.stress;
+ this.coverage = params.coverage;
+ this.skipMessage = params.skipMessage;
+ this.runSkipped = params.runSkipped;
+ this.filterParam = {
+ testType: TESTTYPE,
+ level: LEVEL,
+ size: SIZE
+ };
+ this.parseParams();
+ } catch (err) {
+ console.info(`${TAG}setConfig error: ${err.message}`);
+ }
+ }
+
+ parseParams() {
+ if (this.filter != null) {
+ return;
+ }
+ let testTypeFilter = 0;
+ let sizeFilter = 0;
+ let levelFilter = 0;
+ if (this.testType != null) {
+ testTypeFilter = this.testType.split(',')
+ .map(item => this.filterParam.testType[item] || 0)
+ .reduce((pre, cur) => pre | cur, 0);
+ }
+ if (this.level != null) {
+ levelFilter = this.level.split(',')
+ .map(item => this.filterParam.level[item] || 0)
+ .reduce((pre, cur) => pre | cur, 0);
+ }
+ if (this.size != null) {
+ sizeFilter = this.size.split(',')
+ .map(item => this.filterParam.size[item] || 0)
+ .reduce((pre, cur) => pre | cur, 0);
+ }
+ this.filter = testTypeFilter | sizeFilter | levelFilter;
+ console.info(`${TAG}filter params:${this.filter}`);
+ }
+
+ isCurrentSuite(description) {
+ if (this.suite !== undefined && this.suite !== '' && this.suite !== null) {
+ let suiteArray = this.suite.split(',');
+ return suiteArray.indexOf(description) !== -1;
+ }
+ return false;
+ }
+
+ filterSuite(currentSuiteName) {
+ let filterArray = [];
+ if (this.suite !== undefined && this.suite !== '' && this.suite !== null) {
+ filterArray.push(new SuiteAndItNameFilter(currentSuiteName, '', this.suite));
+ }
+ if (this.class !== undefined && this.class !== '' && this.class !== null) {
+ filterArray.push(new ClassFilter(currentSuiteName, '', this.class));
+ }
+ if (this.notClass !== undefined && this.notClass !== '' && this.notClass !== null) {
+ filterArray.push(new NotClassFilter(currentSuiteName, '', this.notClass));
+ }
+
+ let result = filterArray.map(item => item.filterSuite()).reduce((pre, cur) => pre || cur, false);
+ return result;
+ }
+
+ filterDesc(currentSuiteName, desc, fi, coreContext) {
+ let filterArray = [];
+ if (this.itName !== undefined && this.itName !== '' && this.itName !== null) {
+ filterArray.push(new SuiteAndItNameFilter(currentSuiteName, desc, this.itName));
+ }
+ if (this.class !== undefined && this.class !== '' && this.class !== null) {
+ filterArray.push(new ClassFilter(currentSuiteName, desc, this.class));
+ }
+ if (this.notClass !== undefined && this.notClass !== '' && this.notClass !== null) {
+ filterArray.push(new NotClassFilter(currentSuiteName, desc, this.notClass));
+ }
+ if (typeof (this.filter) !== 'undefined' && this.filter !== 0 && fi !== 0) {
+ filterArray.push(new TestTypesFilter('', '', fi, this.filter));
+ }
+ let result = filterArray.map(item => item.filterIt()).reduce((pre, cur) => pre || cur, false);
+ return result;
+ }
+
+ filterWithNest(desc, filter) {
+ let filterArray = [];
+ const nestFilter = new NestFilter();
+ const targetSuiteArray = this.coreContext.getDefaultService('suite').targetSuiteArray;
+ const targetSpecArray = this.coreContext.getDefaultService('suite').targetSpecArray;
+ const suiteStack = this.coreContext.getDefaultService('suite').suitesStack;
+ let isFilter = nestFilter.filterNestName(targetSuiteArray, targetSpecArray, suiteStack, desc);
+ const isFullRun = this.coreContext.getDefaultService('suite').fullRun;
+ if (typeof (this.filter) !== 'undefined' && this.filter !== 0 && filter !== 0) {
+ filterArray.push(new TestTypesFilter('', '', filter, this.filter));
+ return filterArray.map(item => item.filterIt()).reduce((pre, cur) => pre || cur, false);
+ }
+ if (isFilter && !isFullRun) {
+ return true;
+ }
+ return nestFilter.filterNotClass(this.notClass, suiteStack, desc);
+
+ }
+
+ isRandom() {
+ return this.random || false;
+ }
+
+ isBreakOnError() {
+ return this.breakOnError !== 'true' ? false : true;
+ }
+
+ setSupportAsync(value) {
+ this.supportAsync = value;
+ }
+
+ isSupportAsync() {
+ return this.supportAsync;
+ }
+
+ translateParams(parameters) {
+ const keySet = new Set(KEYSET);
+ let targetParams = {};
+ for (const key in parameters) {
+ if (keySet.has(key)) {
+ var newKey = key.replace('-s ', '');
+ targetParams[newKey] = parameters[key];
+ }
+ }
+ return targetParams;
+ }
+ translateParamsToString(parameters) {
+ const keySet = new Set(KEYSET);
+ let targetParams = '';
+ for (const key in parameters) {
+ if (keySet.has(key)) {
+ targetParams += ' ' + key + ' ' + parameters[key];
+ }
+ }
+ return targetParams.trim();
+ }
+
+ execute() {
+ }
+
+ checkIfSuiteInSkipRun(desc) {
+ return this.runSkipped.split(',').some(item => {
+ return item === desc || item.startsWith(desc + '.') || item.startsWith(desc + '#') || desc.startsWith(item + '.') || this.runSkipped === 'skipped';
+ });
+ }
+
+ checkIfSpecInSkipRun(desc) {
+ return this.runSkipped.split(',').some(item => {
+ if (item.includes('#')) {
+ return item === desc;
+ } else {
+ return desc.startsWith(item + '.') || desc.startsWith(item + '#') || this.runSkipped === 'skipped';
+ }
+ }
+ );
+ }
+}
+
+export {
+ ConfigService
+};
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/coverage/coverageCollect.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/coverage/coverageCollect.js
new file mode 100644
index 0000000000000000000000000000000000000000..334a33db9561dd2070c4081457632decf2589b83
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/coverage/coverageCollect.js
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2023 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import SysTestKit from '../kit/SysTestKit';
+import fs from '@ohos.file.fs';
+import {TAG} from '../../Constant';
+
+const jsCoverageFileName = 'js_coverage.json';
+
+export async function collectCoverageData() {
+ if (globalThis.__coverage__ === undefined) {
+ console.info(`${TAG} globalThis not have coverage`);
+ return;
+ }
+ const strJson = JSON.stringify(globalThis.__coverage__);
+ let testMode = globalThis.__testMode__;
+ console.info(`${TAG} coverage data testMode: ${testMode}`);
+ let savePath = globalThis.__savePath__;
+ console.info(`${TAG} write coverage data to: ${savePath}`);
+ let readPath = globalThis.__readPath__;
+ console.info(`${TAG} read coverage data in: ${readPath}`);
+
+ // run callback mode if local test or (save path and read path ) is not defined
+ if (!testMode || !isCoveragePathValid(savePath)) {
+ console.info(`${TAG} run coverage data in call back mode`);
+ const strLen = strJson.length;
+ const maxLen = 500;
+ const maxCount = Math.floor(strLen / maxLen);
+ const OHOS_REPORT_COVERAGE_DATA = 'OHOS_REPORT_COVERAGE_DATA:';
+ for (let count = 0; count <= maxCount; count++) {
+ console.info(`${OHOS_REPORT_COVERAGE_DATA} ${strJson.substring(count * maxLen, (count + 1) * maxLen)}`);
+ await SysTestKit.print(`${OHOS_REPORT_COVERAGE_DATA} ${strJson.substring(count * maxLen, (count + 1) * maxLen)}`);
+ }
+ return;
+ }
+ console.info(`${TAG} run coverage data in save file mode`);
+ if (fs.accessSync(savePath)) {
+ fs.unlinkSync(savePath);
+ }
+
+ let inputPathDir = savePath.substring(0, savePath.length - jsCoverageFileName.length);
+ if (!fs.accessSync(inputPathDir)) {
+ console.info(`${TAG} coverage data create dir: ${inputPathDir}`);
+ fs.mkdirSync(inputPathDir);
+ }
+
+ let file = fs.openSync(savePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
+ let writeLen = fs.writeSync(file.fd, strJson, {encoding:'utf-8'});
+ console.info(`${TAG} write coverage data success: ${writeLen}`);
+ fs.closeSync(file);
+ const OHOS_REPORT_COVERAGE_PATH = 'OHOS_REPORT_COVERAGE_PATH:';
+ await SysTestKit.print(`${OHOS_REPORT_COVERAGE_PATH} ${readPath}`);
+ console.info(`${OHOS_REPORT_COVERAGE_PATH} ${readPath}`);
+}
+
+function isCoveragePathValid(inputPath) {
+ if (!inputPath) {
+ return false;
+ }
+ if (inputPath.indexOf(jsCoverageFileName) === -1) {
+ return false;
+ }
+ return true;
+}
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/kit/SysTestKit.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/kit/SysTestKit.js
new file mode 100644
index 0000000000000000000000000000000000000000..6e2f256514cff87450f910098b1130943a40e39c
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/kit/SysTestKit.js
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {TAG} from '../../Constant';
+import Core from '../../core.js';
+
+export default class SysTestKit {
+
+ static delegator = null;
+ static systemTime = null;
+ static workerPort = null;
+
+ constructor() {
+ this.id = 'sysTestKit';
+ this.index = 0;
+ }
+
+ static getDescribeName() {
+ return Core.getInstance().getDefaultService('suite').getCurrentRunningSuite().description;
+ }
+
+ static getItName() {
+ return Core.getInstance().getDefaultService('spec').getCurrentRunningSpec().description;
+ }
+
+ static getItAttribute() {
+ return Core.getInstance().getDefaultService('spec').getCurrentRunningSpec().fi;
+ }
+
+ static actionStart(tag) {
+ console.info(`${TAG}${JSON.stringify(tag)}`);
+ var message = '\n' + 'OHOS_REPORT_ACTIONSTART: ' + JSON.stringify(tag) + '\n';
+ SysTestKit.print(message);
+ console.info(`${TAG}${JSON.stringify(tag)} actionStart print success`);
+ }
+
+ static actionEnd(tag) {
+ console.info(`${TAG}${JSON.stringify(tag)}`);
+ var message = '\n' + 'OHOS_REPORT_ACTIONEND: ' + JSON.stringify(tag) + '\n';
+ SysTestKit.print(message);
+ console.info(`${TAG}${JSON.stringify(tag)} actionEnd print success`);
+ }
+
+ static async existKeyword(keyword, timeout) {
+ let reg = new RegExp(/^[a-zA-Z0-9]{1,}$/);
+ if (!reg.test(keyword)) {
+ throw new Error('keyword must contain more than one string, and only letters and numbers are supported.');
+ }
+ timeout = timeout || 4;
+
+ let searchResult = false;
+ let cmd = 'hilog -x | grep -i \'' + keyword + '\' | wc -l';
+ await executePromise(cmd, timeout).then((data) => {
+ searchResult = data;
+ });
+ return searchResult;
+ }
+ static async print(message) {
+ if ('printSync' in SysTestKit.delegator) {
+ console.info(`${TAG}printSync called ...`);
+ SysTestKit.delegator.printSync(message);
+ } else {
+ await SysTestKit.delegator.print(message);
+ }
+ }
+
+ static async getRealTime() {
+ let currentTime = new Date().getTime();
+ if (SysTestKit.systemTime !== null && SysTestKit.systemTime !== undefined) {
+ await SysTestKit.systemTime.getRealTime().then((time) => {
+ console.info(`${TAG}systemTime.getRealTime success data: ${JSON.stringify(time)}`);
+ currentTime = time;
+ }).catch((error) => {
+ console.error(`${TAG}failed to systemTime.getRealTime because ${JSON.stringify(error)}`);
+ });
+ }
+ return currentTime;
+ }
+}
+
+function executePromise(cmd, timeout) {
+ return new Promise((resolve, reject) => {
+ SysTestKit.delegator.executeShellCommand(cmd, timeout,
+ (error, data) => {
+ console.info(`${TAG}existKeyword CallBack: err : ${JSON.stringify(error)}`);
+ console.info(`${TAG}existKeyword CallBack: data : ${JSON.stringify(data)}`);
+ resolve(parseInt(data.stdResult) > 3 ? true : false);
+ });
+ });
+}
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/mock/ArgumentMatchers.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/mock/ArgumentMatchers.js
new file mode 100644
index 0000000000000000000000000000000000000000..1e69ac401049589986968a8575ca45a02a299327
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/mock/ArgumentMatchers.js
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class ArgumentMatchers {
+ ANY = '';
+ ANY_STRING = '';
+ ANY_BOOLEAN = '';
+ ANY_NUMBER = '';
+ ANY_OBJECT = '';
+ ANY_FUNCTION = '';
+ MATCH_REGEXS = '';
+
+ static any() {
+ }
+
+ static anyString() {
+ }
+
+ static anyBoolean() {
+ }
+
+ static anyNumber() {
+ }
+
+ static anyObj() {
+ }
+
+ static anyFunction() {
+ }
+
+ static matchRegexs() {
+ let regex = arguments[0];
+ if (ArgumentMatchers.isRegExp(regex)) {
+ return regex;
+ }
+ throw Error('not a regex');
+ }
+
+ static isRegExp(value) {
+ return Object.prototype.toString.call(value) === '[object RegExp]';
+ }
+
+ matcheReturnKey() {
+ let arg = arguments[0];
+ let regex = arguments[1];
+ let stubSetKey = arguments[2];
+
+ if (stubSetKey && stubSetKey == this.ANY) {
+ return this.ANY;
+ }
+
+ if (typeof arg === 'string' && !regex) {
+ return this.ANY_STRING;
+ }
+
+ if (typeof arg === 'boolean' && !regex) {
+ return this.ANY_BOOLEAN;
+ }
+
+ if (typeof arg === 'number' && !regex) {
+ return this.ANY_NUMBER;
+ }
+
+ if (typeof arg === 'object' && !regex) {
+ return this.ANY_OBJECT;
+ }
+
+ if (typeof arg === 'function' && !regex) {
+ return this.ANY_FUNCTION;
+ }
+
+ if (typeof arg === 'string' && regex) {
+ return regex.test(arg);
+ }
+
+ return null;
+ }
+
+ matcheStubKey() {
+ let key = arguments[0];
+
+ if (key === ArgumentMatchers.any) {
+ return this.ANY;
+ }
+
+ if (key === ArgumentMatchers.anyString) {
+ return this.ANY_STRING;
+ }
+ if (key === ArgumentMatchers.anyBoolean) {
+ return this.ANY_BOOLEAN;
+ }
+ if (key === ArgumentMatchers.anyNumber) {
+ return this.ANY_NUMBER;
+ }
+ if (key === ArgumentMatchers.anyObj) {
+ return this.ANY_OBJECT;
+ }
+ if (key === ArgumentMatchers.anyFunction) {
+ return this.ANY_FUNCTION;
+ }
+
+ if (ArgumentMatchers.isRegExp(key)) {
+ return key;
+ }
+
+ return null;
+ }
+}
+
+export default ArgumentMatchers;
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/mock/ExtendInterface.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/mock/ExtendInterface.js
new file mode 100644
index 0000000000000000000000000000000000000000..c6a866a6df662ad10a7f6869dcbc2381fa47bcdc
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/mock/ExtendInterface.js
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class ExtendInterface {
+ constructor(mocker) {
+ this.mocker = mocker;
+ }
+
+ stub() {
+ this.params = arguments;
+ return this;
+ }
+
+ stubMockedCall(returnInfo) {
+ this.mocker.stubApply(this, this.params, returnInfo);
+ }
+
+ afterReturn(value) {
+ this.stubMockedCall(function () {
+ return value;
+ });
+ }
+
+ afterReturnNothing() {
+ this.stubMockedCall(function () {
+ return undefined;
+ });
+ }
+
+ afterAction(action) {
+ this.stubMockedCall(action);
+ }
+
+ afterThrow(msg) {
+ this.stubMockedCall(function () {
+ throw msg;
+ });
+ }
+
+ clear() {
+ this.mocker.clear();
+ }
+}
+
+export default ExtendInterface;
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/mock/MockKit.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/mock/MockKit.js
new file mode 100644
index 0000000000000000000000000000000000000000..5895666bc89ed4270582b436c82045745d5249b4
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/mock/MockKit.js
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import ExtendInterface from './ExtendInterface';
+import VerificationMode from './VerificationMode';
+import ArgumentMatchers from './ArgumentMatchers';
+
+class MockKit {
+
+ constructor() {
+ this.mFunctions = [];
+ this.stubs = new Map();
+ this.recordCalls = new Map();
+ this.currentSetKey = new Map();
+ this.mockObj = null;
+ this.recordMockedMethod = new Map();
+ }
+
+ init() {
+ this.reset();
+ }
+
+ reset() {
+ this.mFunctions = [];
+ this.stubs = {};
+ this.recordCalls = {};
+ this.currentSetKey = new Map();
+ this.mockObj = null;
+ this.recordMockedMethod = new Map();
+ }
+
+ clearAll() {
+ this.reset();
+ var props = Object.keys(this);
+ for (var i = 0; i < props.length; i++) {
+ delete this[props[i]];
+ }
+
+ var props = Object.getOwnPropertyNames(this);
+ for (var i = 0; i < props.length; i++) {
+ delete this[props[i]];
+ }
+ for (var key in this) {
+ delete this[key];
+ }
+ }
+
+ clear(obj) {
+ if (!obj) {
+ throw Error('Please enter an object to be cleaned');
+ }
+ if (typeof (obj) !== 'object' && typeof (obj) !== 'function') {
+ throw new Error('Not a object or static class');
+ }
+ this.recordMockedMethod.forEach(function (value, key, map) {
+ if (key) {
+ obj[key] = value;
+ }
+ });
+ }
+
+ ignoreMock(obj, method) {
+ if (typeof (obj) !== 'object' && typeof (obj) !== 'function') {
+ throw new Error('Not a object or static class');
+ }
+ if (typeof (method) !== 'function') {
+ throw new Error('Not a function');
+ }
+ let og = this.recordMockedMethod.get(method.propName);
+ if (og) {
+ obj[method.propName] = og;
+ this.recordMockedMethod.set(method.propName, undefined);
+ }
+ }
+
+ extend(dest, source) {
+ dest['stub'] = source['stub'];
+ dest['afterReturn'] = source['afterReturn'];
+ dest['afterReturnNothing'] = source['afterReturnNothing'];
+ dest['afterAction'] = source['afterAction'];
+ dest['afterThrow'] = source['afterThrow'];
+ dest['stubMockedCall'] = source['stubMockedCall'];
+ dest['clear'] = source['clear'];
+ return dest;
+ }
+
+ stubApply(f, params, returnInfo) {
+ let values = this.stubs.get(f);
+ if (!values) {
+ values = new Map();
+ }
+ let key = params[0];
+ if (typeof key == 'undefined') {
+ key = 'anonymous-mock-' + f.propName;
+ }
+ let matcher = new ArgumentMatchers();
+ if (matcher.matcheStubKey(key)) {
+ key = matcher.matcheStubKey(key);
+ if (key) {
+ this.currentSetKey.set(f, key);
+ }
+ }
+ values.set(key, returnInfo);
+ this.stubs.set(f, values);
+ }
+
+ getReturnInfo(f, params) {
+ let values = this.stubs.get(f);
+ if (!values) {
+ return undefined;
+ }
+ let retrunKet = params[0];
+ if (typeof retrunKet == 'undefined') {
+ retrunKet = 'anonymous-mock-' + f.propName;
+ }
+ let stubSetKey = this.currentSetKey.get(f);
+
+ if (stubSetKey && (typeof (retrunKet) !== 'undefined')) {
+ retrunKet = stubSetKey;
+ }
+ let matcher = new ArgumentMatchers();
+ if (matcher.matcheReturnKey(params[0], undefined, stubSetKey) && matcher.matcheReturnKey(params[0], undefined, stubSetKey) !== stubSetKey) {
+ retrunKet = params[0];
+ }
+
+ values.forEach(function (value, key, map) {
+ if (ArgumentMatchers.isRegExp(key) && matcher.matcheReturnKey(params[0], key)) {
+ retrunKet = key;
+ }
+ });
+
+ return values.get(retrunKet);
+ }
+
+ findName(obj, value) {
+ let properties = this.findProperties(obj);
+ let name = null;
+ properties.filter(item => (item !== 'caller' && item !== 'arguments')).forEach(
+ function (va1, idx, array) {
+ if (obj[va1] === value) {
+ name = va1;
+ }
+ }
+ );
+ return name;
+ }
+
+ isFunctionFromPrototype(f, container, propName) {
+ if (container.constructor !== Object && container.constructor.prototype !== container) {
+ return container.constructor.prototype[propName] === f;
+ }
+ return false;
+ }
+
+ findProperties(obj, ...arg) {
+ function getProperty(newObj) {
+ if (newObj.__proto__ === null) {
+ return [];
+ }
+ let properties = Object.getOwnPropertyNames(newObj);
+ return [...properties, ...getProperty(newObj.__proto__)];
+ }
+ return getProperty(obj);
+ }
+
+ recordMethodCall(originalMethod, args) {
+ Function.prototype.getName = function () {
+ return this.name || this.toString().match(/function\s*([^(]*)\(/)[1];
+ };
+ let name = originalMethod.getName();
+ let arglistString = name + '(' + Array.from(args).toString() + ')';
+ let records = this.recordCalls.get(arglistString);
+ if (!records) {
+ records = 0;
+ }
+ records++;
+ this.recordCalls.set(arglistString, records);
+ }
+
+ mockFunc(originalObject, originalMethod) {
+ let tmp = this;
+ this.originalMethod = originalMethod;
+ let f = function () {
+ let args = arguments;
+ let action = tmp.getReturnInfo(f, args);
+ if (originalMethod) {
+ tmp.recordMethodCall(originalMethod, args);
+ }
+ if (action) {
+ return action.apply(this, args);
+ }
+ };
+
+ f.container = null || originalObject;
+ f.original = originalMethod || null;
+
+ if (originalObject && originalMethod) {
+ if (typeof (originalMethod) !== 'function') {
+ throw new Error('Not a function');
+ }
+ var name = this.findName(originalObject, originalMethod);
+ originalObject[name] = f;
+ this.recordMockedMethod.set(name, originalMethod);
+ f.propName = name;
+ f.originalFromPrototype = this.isFunctionFromPrototype(f.original, originalObject, f.propName);
+ }
+ f.mocker = this;
+ this.mFunctions.push(f);
+ this.extend(f, new ExtendInterface(this));
+ return f;
+ }
+
+ verify(methodName, argsArray) {
+ if (!methodName) {
+ throw Error('not a function name');
+ }
+ let a = this.recordCalls.get(methodName + '(' + argsArray.toString() + ')');
+ return new VerificationMode(a ? a : 0);
+ }
+
+ mockObject(object) {
+ if (!object || typeof object === 'string') {
+ throw Error(`this ${object} cannot be mocked`);
+ }
+ const _this = this;
+ let mockedObject = {};
+ let keys = Reflect.ownKeys(object);
+ keys.filter(key => (typeof Reflect.get(object, key)) === 'function')
+ .forEach(key => {
+ mockedObject[key] = object[key];
+ mockedObject[key] = _this.mockFunc(mockedObject, mockedObject[key]);
+ });
+ return mockedObject;
+ }
+}
+
+function ifMockedFunction(f) {
+ if (Object.prototype.toString.call(f) !== '[object Function]' &&
+ Object.prototype.toString.call(f) !== '[object AsyncFunction]') {
+ throw Error('not a function');
+ }
+ if (!f.stub) {
+ throw Error('not a mock function');
+ }
+ return true;
+}
+
+function when(f) {
+ if (ifMockedFunction(f)) {
+ return f.stub.bind(f);
+ }
+}
+
+export {MockKit, when};
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/mock/VerificationMode.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/mock/VerificationMode.js
new file mode 100644
index 0000000000000000000000000000000000000000..aaf2fdfae00135d3d2055320fc5ea403b44d0bf3
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/mock/VerificationMode.js
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {expect} from '../../interface';
+
+class VerificationMode {
+ constructor(times) {
+ this.doTimes = times;
+ }
+
+ times(count) {
+ expect(count).assertEqual(this.doTimes);
+ }
+
+ never() {
+ console.info(this.doTimes);
+ expect(0).assertEqual(this.doTimes);
+ }
+
+ once() {
+ expect(1).assertEqual(this.doTimes);
+ }
+
+ atLeast(count) {
+ if (count > this.doTimes) {
+ throw Error('failed ' + count + ' greater than the actual execution times of method');
+ }
+ }
+
+ atMost(count) {
+ if (count < this.doTimes) {
+ throw Error('failed ' + count + ' less than the actual execution times of method');
+ }
+ }
+}
+
+export default VerificationMode;
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/report/LogExpectError.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/report/LogExpectError.js
new file mode 100644
index 0000000000000000000000000000000000000000..5a94cecb4625205797ae886c19ac592f189c2232
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/report/LogExpectError.js
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class LogExpectError {
+ static getErrorMsg(matcherName, actualValue, expect, originMsg) {
+ if (matcherName === 'assertNull') {
+ return 'expect not null, actualValue is ' + (actualValue);
+ }
+ if (matcherName === 'assertTrue') {
+ return 'expect not true, actualValue is ' + (actualValue);
+ }
+ if (matcherName === 'assertFalse') {
+ return 'expect not false, actualValue is ' + (actualValue);
+ }
+ if (matcherName === 'assertEqual') {
+ return 'expect not Equal, actualValue is ' + actualValue + ' equals ' + expect;
+ }
+ if (matcherName === 'assertContain') {
+ return 'expect not have, ' + actualValue + ' have ' + expect;
+ }
+ if (matcherName === 'assertInstanceOf') {
+ return 'expect not InstanceOf, ' + actualValue + ' is ' +
+ Object.prototype.toString.call(actualValue) + expect;
+ }
+ if (matcherName === 'assertLarger') {
+ return 'expect not Larger, ' +
+ (actualValue) + ' is larger than ' + expect;
+ }
+ if (matcherName === 'assertLargerOrEqual') {
+ return 'expect not LargerOrEqual, ' + (actualValue) + ' larger than ' + expect;
+ }
+ if (matcherName === 'assertLess') {
+ return 'expect not Less, ' + (actualValue) + ' less than ' + expect;
+ }
+ if (matcherName === 'assertLessOrEqual') {
+ return 'expect not LessOrEqual, ' + (actualValue) + ' is less than ' + expect;
+ }
+ if (matcherName === 'assertNaN') {
+ return 'expect not NaN, actualValue is ' + (actualValue);
+ }
+ if (matcherName === 'assertNegUnlimited') {
+ return 'expect not NegUnlimited, actualValue is ' + (actualValue);
+ }
+ if (matcherName === 'assertPosUnlimited') {
+ return 'expect not PosUnlimited, actualValue is ' + (actualValue);
+ }
+ if (matcherName === 'assertUndefined') {
+ return 'expect not Undefined, actualValue is ' + (actualValue);
+ }
+ return originMsg;
+ }
+}
+export default LogExpectError;
\ No newline at end of file
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/report/OhReport.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/report/OhReport.js
new file mode 100644
index 0000000000000000000000000000000000000000..653e56be9e88e810f6ab1f3d58049cf08d2ac0b6
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/report/OhReport.js
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import SysTestKit from "../kit/SysTestKit";
+import { collectCoverageData } from '../coverage/coverageCollect';
+import { TAG, PrintTag } from '../../Constant';
+
+class OhReport {
+ constructor(attr) {
+ this.delegator = attr.delegator;
+ this.abilityDelegatorArguments = attr.abilityDelegatorArguments;
+ this.id = 'report';
+ this.index = 0;
+ this.duration = 0;
+ this.currentThreadName = 'mainThread';
+ }
+
+ init(coreContext) {
+ this.coreContext = coreContext;
+ this.suiteService = this.coreContext.getDefaultService('suite');
+ this.specService = this.coreContext.getDefaultService('spec');
+ if (SysTestKit.workerPort !== null) {
+ this.currentThreadName = SysTestKit.workerPort.name;
+ }
+ }
+
+ taskStart() {
+ }
+
+ async taskDone() {
+ let summary = this.suiteService.getSummary();
+ if (this.abilityDelegatorArguments !== null) {
+ this.taskDoneTime = new Date().getTime();
+ const configService = this.coreContext.getDefaultService('config');
+ const suiteService = this.coreContext.getDefaultService('suite');
+ const specService = this.coreContext.getDefaultService('spec');
+ if (configService['coverage'] === 'true') {
+ await collectCoverageData();
+ }
+ let message = '\n' + `${PrintTag.OHOS_REPORT_RESULT}: stream=Tests run: ` + summary.total + ', Failure: ' + summary.failure;
+ message += ', Error: ' + summary.error;
+ message += ', Pass: ' + summary.pass;
+ message += ', Ignore: ' + summary.ignore;
+ if (specService.skipSpecNum > 0) {
+ message += ', SkipSpec: ' + specService.skipSpecNum;
+ }
+ message += '\n' + `${PrintTag.OHOS_REPORT_CODE}: ` + (summary.failure > 0 ? -1 : 0) + '\n';
+ let isHasError = summary.failure > 0 || summary.error > 0;
+ let config = this.coreContext.getDefaultService('config');
+ if (config.isBreakOnError() && isHasError) {
+ // 未执行全部说明
+ message += '\n' + `${PrintTag.OHOS_REPORT_RESULT}: breakOnError model, Stopping whole test suite if one specific test case failed or error` + '\n';
+ }
+ message += `${PrintTag.OHOS_REPORT_STATUS}: taskconsuming=` + summary.duration + '\n';
+ console.info(`${message}`);
+ await SysTestKit.print(message);
+ }
+ if (SysTestKit.workerPort === null || SysTestKit.workerPort === undefined) {
+ // 主线程执行完成 结束任务。
+ console.info(`${TAG}report print success`);
+ this.delegator.finishTest('your test finished!!!', 0, () => { });
+ } else {
+ // worker线程执行完成将数据发送到主线程中。
+ let sendData = {
+ currentThreadName: this.currentThreadName,
+ summary: summary
+ };
+ console.info(`${TAG}, send data to mainThread, ${this.currentThreadName}, ${JSON.stringify(sendData)}`);
+ SysTestKit.workerPort.postMessage(sendData);
+ }
+ }
+
+ incorrectFormat() {
+ if (this.coreContext.getDefaultService('config').filterValid.length !== 0) {
+ var value = this.coreContext.getDefaultService('config').filterValid;
+ var message = 'this param ' + value.join(',') + ' is invalid' + '\n';
+ this.delegator.finishTest(message, 0, () => {
+ });
+ }
+ }
+
+ incorrectTestSuiteFormat() {
+ if (this.coreContext.getDefaultService('config').filterXdescribe.length !== 0) {
+ let value = this.coreContext.getDefaultService('config').filterXdescribe;
+ let message = 'xdescribe ' + value.join(',') + ' should not contain it' + '\n';
+ this.delegator.finishTest(message, 0, () => {
+ });
+ }
+ }
+ async suiteStart() {
+ if (this.abilityDelegatorArguments !== null) {
+ let specArr = [];
+ this.suiteService.getAllChildSuiteNum(this.suiteService.getCurrentRunningSuite(), specArr);
+ let message = '\n' + `${PrintTag.OHOS_REPORT_SUM}: ` + specArr.length;
+ this.suiteService.setCurrentRunningSuiteDesc(this.suiteService.getRootSuite(), this.suiteService.getCurrentRunningSuite(), '');
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: class=` + this.suiteService.getCurrentRunningSuiteDesc() + '\n';
+ if (this.suiteService.currentRunningSuite.isSkip) {
+ message += `${PrintTag.OHOS_REPORT_STATUS}: skipReason=` + this.suiteService.currentRunningSuite.skipReason + '\n';
+ }
+ if (SysTestKit.workerPort !== null) {
+ message += `${PrintTag.OHOS_REPORT_STATUS}: currentWorkerName=` + this.currentThreadName;
+ }
+ console.info(`${message}`);
+ await SysTestKit.print(message);
+ console.info(`${TAG}${this.suiteService.getCurrentRunningSuite().description} suiteStart print success`);
+ }
+ }
+
+ async suiteDone() {
+ if (this.abilityDelegatorArguments !== null) {
+ const currentRunningSuite = this.suiteService.getCurrentRunningSuite();
+ this.suiteService.setCurrentRunningSuiteDesc(this.suiteService.getRootSuite(), this.suiteService.getCurrentRunningSuite(), '');
+ let message = '\n' + `${PrintTag.OHOS_REPORT_STATUS}: class=` + this.suiteService.getCurrentRunningSuiteDesc();
+ if (this.suiteService.currentRunningSuite.isSkip && this.suiteService.currentRunningSuite.skipReason !== '') {
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: skipReason=` + this.suiteService.currentRunningSuite.skipReason;
+ }
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: suiteconsuming=` + this.suiteService.getCurrentRunningSuite().duration;
+ if (currentRunningSuite.hookError) {
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: ${currentRunningSuite.hookError.message}`;
+ }
+ message += '\n';
+ if (SysTestKit.workerPort !== null) {
+ message += `${PrintTag.OHOS_REPORT_STATUS}: currentWorkerName=` + this.currentThreadName;
+ }
+ console.info(`${message}`);
+ await SysTestKit.print(message);
+ console.info(`${TAG}${this.suiteService.getCurrentRunningSuite().description} suiteDone print success`);
+ }
+ }
+
+ async specStart() {
+ if (this.abilityDelegatorArguments !== null) {
+ let message = '\n' + `${PrintTag.OHOS_REPORT_STATUS}: class=` + this.suiteService.getCurrentRunningSuiteDesc();
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: current=` + (++this.index);
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: id=JS`;
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: numtests=` + this.specService.getTestTotal();
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: stream=`;
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: test=` + this.specService.currentRunningSpec.description;
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS_CODE}: 1` + '\n';
+ if (this.specService.currentRunningSpec.isSkip) {
+ message += `${PrintTag.OHOS_REPORT_STATUS}: skipReason=` + this.specService.currentRunningSpec.skipReason + '\n';
+ }
+ if (SysTestKit.workerPort !== null) {
+ message += `${PrintTag.OHOS_REPORT_STATUS}: currentWorkerName=` + this.currentThreadName;
+ }
+ console.info(`${message}`);
+ await SysTestKit.print(message);
+ console.info(`${TAG}${this.specService.currentRunningSpec.description} specStart start print success`);
+ }
+ }
+
+ async specDone() {
+ if (this.abilityDelegatorArguments !== null) {
+ let message = '\n' + `${PrintTag.OHOS_REPORT_STATUS}: class=` + this.suiteService.getCurrentRunningSuiteDesc();
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: current=` + (this.index);
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: id=JS`;
+ message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: numtests=` + this.specService.getTestTotal();
+ let messageStack = '';
+ let messageCode = '';
+ if (this.specService.currentRunningSpec.error) {
+ messageStack = `${PrintTag.OHOS_REPORT_STATUS}: stack=` + this.specService.currentRunningSpec.error?.stack?.slice(0, -1);
+ messageCode += `${PrintTag.OHOS_REPORT_STATUS}: stream=`;
+ messageCode += this.specService.currentRunningSpec.expectMsg !== '' ?
+ `message: ${this.specService.currentRunningSpec.expectMsg}, Error in ${this.specService.currentRunningSpec.description}, ${this.specService.currentRunningSpec.error?.message}` :
+ `Error in ${this.specService.currentRunningSpec.description}, ${this.specService.currentRunningSpec.error?.message}`;
+ messageCode += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: test=` + this.specService.currentRunningSpec.description;
+ messageCode += '\n' + `${PrintTag.OHOS_REPORT_STATUS_CODE}: -1` + '\n';
+ } else if (this.specService.currentRunningSpec) {
+ if (this.specService.currentRunningSpec.fail) {
+ messageStack += `${PrintTag.OHOS_REPORT_STATUS}: stack=` + this.specService.currentRunningSpec.fail?.stack?.slice(0, -1);
+ messageCode += `${PrintTag.OHOS_REPORT_STATUS}: stream=`;
+ messageCode += this.specService.currentRunningSpec.expectMsg !== '' ?
+ `message: ${this.specService.currentRunningSpec.expectMsg}, Error in ${this.specService.currentRunningSpec.description}, ${this.specService.currentRunningSpec.fail?.message}` :
+ `Error in ${this.specService.currentRunningSpec.description}, ${this.specService.currentRunningSpec.fail?.message}`;
+ messageCode += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: test=` + this.specService.currentRunningSpec.description;
+ messageCode += '\n' + `${PrintTag.OHOS_REPORT_STATUS_CODE}: -2` + '\n';
+ } else {
+ messageStack += `${PrintTag.OHOS_REPORT_STATUS}: stream=`;
+ messageCode += `${PrintTag.OHOS_REPORT_STATUS}: test=` + this.specService.currentRunningSpec.description;
+ messageCode += '\n' + `${PrintTag.OHOS_REPORT_STATUS_CODE}: 0` + '\n';
+ messageCode += this.specService.currentRunningSpec.isSkip ? (`${PrintTag.OHOS_REPORT_STATUS}: skipReason=` + this.specService.currentRunningSpec.skipReason + '\n') : '';
+ }
+ } else {
+ messageCode += '\n';
+ }
+ messageCode += `${PrintTag.OHOS_REPORT_STATUS}: consuming=` + this.specService.currentRunningSpec.duration + '\n';
+ if (SysTestKit.workerPort !== null) {
+ messageCode += `${PrintTag.OHOS_REPORT_STATUS}: currentWorkerName=` + this.currentThreadName;
+ }
+ console.info(`${message}`);
+ console.info(`\n${messageStack}`);
+ console.info(`\n${messageCode}`);
+ await SysTestKit.print(message);
+ await SysTestKit.print(messageStack);
+ await SysTestKit.print(messageCode);
+ console.info(`${TAG}${this.specService.currentRunningSpec.description} specDone end print success`);
+ }
+ }
+}
+
+export default OhReport;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/report/ReportExtend.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/report/ReportExtend.js
new file mode 100644
index 0000000000000000000000000000000000000000..852fbcd5cbf97e776ebe5177a029df0f516594a5
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/module/report/ReportExtend.js
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class ReportExtend {
+ constructor(fileModule) {
+ this.id = 'extend';
+ this.fileModule = fileModule;
+ }
+
+ init(coreContext) {
+ this.coreContext = coreContext;
+ this.suiteService = this.coreContext.getDefaultService('suite');
+ }
+
+ taskStart() {
+
+ }
+
+ taskDone() {
+ const report = {
+ tag: 'testsuites',
+ name: 'summary_report',
+ timestamp: new Date().toDateString(),
+ time: '1',
+ errors: 0,
+ failures: 0,
+ tests: 0,
+ children: []
+ };
+ const rootSuite = this.suiteService.rootSuite;
+ if (rootSuite && rootSuite.childSuites) {
+ for (let testsuite of rootSuite.childSuites) {
+ let suiteReport = {
+ tag: 'testsuite',
+ name: testsuite['description'],
+ errors: 0,
+ tests: 0,
+ failures: 0,
+ time: '0.1',
+ children: []
+ };
+ let specs = testsuite['specs'];
+ for (let testcase of specs) {
+ report.tests++;
+ suiteReport.tests++;
+ let caseReport = {
+ tag: 'testcase',
+ name: testcase['description'],
+ status: 'run',
+ time: '0.0',
+ classname: testsuite['description']
+ };
+ if (testcase.error) {
+ caseReport['result'] = false;
+ caseReport['children'] = [{
+ tag: 'error',
+ type: '',
+ message: testcase.error.message
+ }];
+ report.errors++;
+ suiteReport.errors++;
+ } else if (testcase.result.failExpects.length > 0) {
+ caseReport['result'] = false;
+ let message = '';
+ testcase.result.failExpects.forEach(failExpect => {
+ message += failExpect.message || ('expect ' + failExpect.actualValue + ' ' + failExpect.checkFunc + ' ' + (failExpect.expectValue || '')) + ';';
+ });
+ caseReport['children'] = [{
+ tag: 'failure',
+ type: '',
+ message: message
+ }];
+ report.failures++;
+ suiteReport.failures++;
+ } else {
+ caseReport['result'] = true;
+ }
+ suiteReport.children.push(caseReport);
+ }
+ report.children.push(suiteReport);
+ }
+ }
+
+ let reportXml = '\n' + json2xml(report);
+ this.fileModule.writeText({
+ uri: 'internal://app/report.xml',
+ text: reportXml,
+ success: function () {
+ console.info('call success callback success');
+ },
+ fail: function (data, code) {
+ console.info('call fail callback success:');
+ },
+ complete: function () {
+ console.info('call complete callback success');
+ }
+ });
+ }
+}
+
+function json2xml(json) {
+ let tagName;
+ let hasChildren = false;
+ let childrenStr = '';
+ let attrStr = '';
+ for (let key in json) {
+ if (key === 'tag') {
+ tagName = json[key];
+ } else if (key === 'children') {
+ if (json[key].length > 0) {
+ hasChildren = true;
+ for (let child of json[key]) {
+ childrenStr += json2xml(child);
+ }
+ }
+ } else {
+ attrStr += ` ${key}="${json[key]}"`;
+ }
+ }
+ let xml = `<${tagName}${attrStr}`;
+ xml += hasChildren ? `>${childrenStr}${tagName}>` : '/>';
+ return xml;
+}
+
+export default ReportExtend;
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/service.js b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/service.js
new file mode 100644
index 0000000000000000000000000000000000000000..92d46b77959af314f40bd601ede62b9b6d8b9ba2
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/service.js
@@ -0,0 +1,1230 @@
+/*
+ * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import SysTestKit from './module/kit/SysTestKit';
+import { TAG } from './Constant';
+import LogExpectError from './module/report/LogExpectError';
+import { NestFilter } from './module/config/Filter';
+
+class AssertException extends Error {
+ constructor(message) {
+ super();
+ this.name = 'AssertException';
+ this.message = message;
+ }
+}
+
+function getFuncWithArgsZero(func, timeout, isStressTest) {
+ return new Promise(async (resolve, reject) => {
+ let timer = null;
+ if (!isStressTest) {
+ timer = setTimeout(() => {
+ reject(new Error('execute timeout ' + timeout + 'ms'));
+ }, timeout);
+ }
+ try {
+ await func();
+ } catch (err) {
+ reject(err);
+ }
+ timer !== null ? clearTimeout(timer) : null;
+ resolve();
+ });
+}
+
+function getFuncWithArgsOne(func, timeout, isStressTest) {
+ return new Promise(async (resolve, reject) => {
+ let timer = null;
+ if (!isStressTest) {
+ timer = setTimeout(() => {
+ reject(new Error('execute timeout ' + timeout + 'ms'));
+ }, timeout);
+ }
+
+ function done() {
+ timer !== null ? clearTimeout(timer) : null;
+ resolve();
+ }
+
+ try {
+ await func(done);
+ } catch (err) {
+ timer !== null ? clearTimeout(timer) : null;
+ reject(err);
+ }
+ });
+}
+
+function getFuncWithArgsTwo(func, timeout, paramItem, isStressTest) {
+ return new Promise(async (resolve, reject) => {
+ let timer = null;
+ if (!isStressTest) {
+ timer = setTimeout(() => {
+ reject(new Error('execute timeout ' + timeout + 'ms'));
+ }, timeout);
+ }
+
+ function done() {
+ timer !== null ? clearTimeout(timer) : null;
+ resolve();
+ }
+
+ try {
+ await func(done, paramItem);
+ } catch (err) {
+ timer !== null ? clearTimeout(timer) : null;
+ reject(err);
+ }
+ });
+}
+
+function processFunc(coreContext, func) {
+ let argNames = ((func || '').toString()
+ .replace(/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg, '')
+ .match(/^(function)?\s*[^\(]*\(\s*([^\)]*)\)/m) || ['', '', ''])[2]
+ .split(',') // split parameters
+ .map(item => item.replace(/^\s*(_?)(.+?)\1\s*$/, name => name.split('=')[0].trim()))
+ .filter(String);
+ let funcLen = func.length;
+ let processedFunc;
+ const config = coreContext.getDefaultService('config');
+ config.setSupportAsync(true);
+ const timeout = + (config.timeout === undefined ? 5000 : config.timeout);
+ const isStressTest = (coreContext.getServices('dataDriver') !== undefined || config.getStress() > 1);
+ switch (funcLen) {
+ case 0: {
+ processedFunc = function () {
+ return getFuncWithArgsZero(func, timeout, isStressTest);
+ };
+ break;
+ }
+ case 1: {
+ if (argNames[0] === 'data') {
+ processedFunc = function (paramItem) {
+ func(paramItem);
+ };
+ } else {
+ processedFunc = function () {
+ return getFuncWithArgsOne(func, timeout, isStressTest);
+ };
+ }
+ break;
+ }
+ default: {
+ processedFunc = function (paramItem) {
+ return getFuncWithArgsTwo(func, timeout, paramItem, isStressTest);
+ };
+ break;
+ }
+ }
+ return processedFunc;
+}
+
+function secureRandomNumber() {
+ return crypto.randomBytes(8).readUInt32LE() / 0xffffffff;
+}
+
+class SuiteService {
+ constructor(attr) {
+ this.id = attr.id;
+ this.rootSuite = new SuiteService.Suite({});
+ this.currentRunningSuite = this.rootSuite;
+ this.suitesStack = [this.rootSuite];
+ this.targetSuiteArray = [];
+ this.targetSpecArray = [];
+ this.currentRunningSuiteDesc = null;
+ this.fullRun = false;
+ this.isSkipSuite = false;
+ this.suiteSkipReason = null;
+ }
+
+ describe(desc, func) {
+ const configService = this.coreContext.getDefaultService('config');
+ if (this.suitesStack.some(suite => { return suite.description === desc })) {
+ console.error(`${TAG} Loop nesting occurs : ${desc}`);
+ this.suiteSkipReason = '';
+ this.isSkipSuite = false;
+ return;
+ }
+ let isFilter = this.analyzeConfigServiceClass(configService.class, desc);
+ if (configService.filterSuite(desc) && isFilter) {
+ if (this.currentRunningSuite.description === '' || this.currentRunningSuite.description == null) {
+ console.info(`${TAG}filter suite : ${desc}`);
+ this.suiteSkipReason = '';
+ this.isSkipSuite = false;
+ return;
+ }
+ }
+ const suite = new SuiteService.Suite({ description: desc });
+ if (this.isSkipSuite) {
+ suite.isSkip = true;
+ suite.skipReason = this.suiteSkipReason;
+ }
+ this.suiteSkipReason = '';
+ this.isSkipSuite = false;
+ if (typeof this.coreContext.getServices('dataDriver') !== 'undefined' && configService['dryRun'] !== 'true') {
+ let suiteStress = this.coreContext.getServices('dataDriver').dataDriver.getSuiteStress(desc);
+ for (let i = 1; i < suiteStress; i++) {
+ this.currentRunningSuite.childSuites.push(suite);
+ }
+ }
+ this.currentRunningSuite.childSuites.push(suite);
+ this.currentRunningSuite = suite;
+ this.suitesStack.push(suite);
+ func.call();
+ this.suitesStack.pop();
+ this.currentRunningSuite = this.suitesStack.pop();
+ this.suitesStack.push(this.currentRunningSuite);
+ }
+ xdescribe(desc, func, reason) {
+ const configService = this.coreContext.getDefaultService('config');
+ if (!configService.skipMessage && configService.runSkipped !== 'all') {
+ if (configService.runSkipped != null && configService.runSkipped !== '') {
+ let finalDesc = '';
+ this.suitesStack.map(suite => {
+ finalDesc = finalDesc + '.' + suite.description;
+ });
+ finalDesc = (finalDesc + '.' + desc).substring(2);
+ console.info(`${TAG} finalDesc ${finalDesc}`);
+ if (configService.checkIfSuiteInSkipRun(finalDesc)) {
+ console.info(`${TAG} runSkipped suite: ${desc}`);
+ } else {
+ console.info(reason == null ? `${TAG} skip suite: ${desc}` : `${TAG} skip suite: ${desc}, and the reason is ${reason}`);
+ return;
+ }
+ } else {
+ console.info(reason == null ? `${TAG} skip suite: ${desc}` : `${TAG} skip suite: ${desc}, and the reason is ${reason}`);
+ return;
+ }
+ }
+ this.isSkipSuite = true;
+ this.suiteSkipReason = reason;
+ this.describe(desc, func);
+ }
+
+ beforeAll(func) {
+ this.currentRunningSuite.beforeAll.push(processFunc(this.coreContext, func));
+ }
+
+ beforeEach(func) {
+ this.currentRunningSuite.beforeEach.push(processFunc(this.coreContext, func));
+ }
+
+ beforeItSpecified(itDescs, func) {
+ this.currentRunningSuite.beforeItSpecified.set(itDescs, processFunc(this.coreContext, func));
+ }
+
+ afterItSpecified(itDescs, func) {
+ this.currentRunningSuite.afterItSpecified.set(itDescs, processFunc(this.coreContext, func));
+ }
+
+ afterAll(func) {
+ this.currentRunningSuite.afterAll.push(processFunc(this.coreContext, func));
+ }
+
+ afterEach(func) {
+ this.currentRunningSuite.afterEach.push(processFunc(this.coreContext, func));
+ }
+
+ getCurrentRunningSuite() {
+ return this.currentRunningSuite;
+ }
+
+ setCurrentRunningSuite(suite) {
+ this.currentRunningSuite = suite;
+ }
+
+ getRootSuite() {
+ return this.rootSuite;
+ }
+
+ getCurrentRunningSuiteDesc() {
+ return this.currentRunningSuiteDesc;
+ }
+
+
+ setCurrentRunningSuiteDesc(suite, currentSuite, prefix) {
+ if (suite != null && suite === currentSuite) {
+ this.currentRunningSuiteDesc = prefix;
+ } else if (suite != null && suite !== currentSuite) {
+ suite.childSuites.forEach(it => {
+ let temp = prefix;
+ if (it.description != null || it.description !== '') {
+ temp = prefix === '' ? it.description : prefix + '.' + it.description;
+ }
+ this.setCurrentRunningSuiteDesc(it, currentSuite, temp);
+ }
+ );
+ }
+ }
+ analyzeConfigServiceClass(configServiceClass, desc) {
+ if (configServiceClass == null || configServiceClass === '') {
+ this.fullRun = true
+ return false;
+ }
+ if (this.targetSuiteArray.length === 0) {
+ const targetArray = configServiceClass.split(',');
+ for (let index in targetArray) {
+ if (targetArray[index].includes('#')) {
+ this.targetSpecArray.push(targetArray[index]);
+ } else {
+ this.targetSuiteArray.push(targetArray[index]);
+ }
+ }
+
+ }
+ return !configServiceClass.includes(desc);
+
+ }
+ traversalResults(suite, obj, breakOnError) {
+ if (suite.childSuites.length === 0 && suite.specs.length === 0) {
+ return obj;
+ }
+ if (suite.specs.length > 0) {
+ for (const itItem of suite.specs) {
+ obj.total++;
+ let itInfo = {
+ currentThreadName: 'mainThread',
+ description: suite.description + '#' + itItem.description,
+ result: -3
+ };
+ if (SysTestKit.workerPort !== null) {
+ itInfo.currentThreadName = SysTestKit.workerPort.name;
+ }
+ obj.itItemList.push(itInfo);
+ if (breakOnError && (obj.error > 0 || obj.failure > 0)) { // breakOnError模式
+ continue;
+ }
+ if (itItem.error) {
+ obj.error++;
+ itInfo.result = -1;
+ } else if (itItem.fail) {
+ obj.failure++;
+ itInfo.result = -2;
+ } else if (itItem.pass === true) {
+ obj.pass++;
+ itInfo.result = 0;
+ }
+ }
+ }
+
+ obj.duration += suite.duration;
+
+ if (suite.childSuites.length > 0) {
+ for (const suiteItem of suite.childSuites) {
+ this.traversalResults(suiteItem, obj, breakOnError);
+ }
+ }
+ }
+
+ async setSuiteResults(suite, error, coreContext) {
+ if (suite.childSuites.length === 0 && suite.specs.length === 0) {
+ return obj;
+ }
+ if (suite.specs.length > 0) {
+ const specService = coreContext.getDefaultService('spec');
+ for (const specItem of suite.specs) {
+ specService.setCurrentRunningSpec(specItem);
+ if (error instanceof AssertException) {
+ specItem.fail = error;
+ } else {
+ specItem.error = error;
+ }
+ await coreContext.fireEvents('spec', 'specStart', specItem);
+ await coreContext.fireEvents('spec', 'specDone', specItem);
+ }
+ }
+ if (suite.childSuites.length > 0) {
+ for (const suiteItem of suite.childSuites) {
+ await this.setSuiteResults(suiteItem, error, coreContext);
+ }
+ }
+ }
+
+ getSummary() {
+ let suiteService = this.coreContext.getDefaultService('suite');
+ let rootSuite = suiteService.rootSuite;
+ const specService = this.coreContext.getDefaultService('spec');
+ const configService = this.coreContext.getDefaultService('config');
+ let breakOnError = configService.isBreakOnError();
+ let isError = specService.getStatus();
+ let isBreaKOnError = breakOnError && isError;
+ // itItemList 保存当前用例执行情况, 发送到主线程用例计算最终结果
+ let obj = { total: 0, failure: 0, error: 0, pass: 0, ignore: 0, duration: 0, itItemList: []};
+ for (const suiteItem of rootSuite.childSuites) {
+ this.traversalResults(suiteItem, obj, isBreaKOnError);
+ }
+ obj.ignore = obj.total - obj.pass - obj.failure - obj.error;
+ return obj;
+ }
+
+ init(coreContext) {
+ this.coreContext = coreContext;
+ }
+
+ traversalSuites(suite, obj, configService) {
+ if (suite.childSuites.length === 0 && suite.specs.length === 0) {
+ return [];
+ }
+ if (suite.specs.length > 0) {
+ let itArray = [];
+ for (const itItem of suite['specs']) {
+ if (!configService.filterDesc(suite.description, itItem.description, itItem.fi, null)) {
+ itArray.push({ 'itName': itItem.description });
+ }
+ }
+ obj[suite.description] = itArray;
+ }
+ if (suite.childSuites.length > 0) {
+ let suiteArray = [];
+ for (const suiteItem of suite.childSuites) {
+ let suiteObj = {};
+ this.traversalSuites(suiteItem, suiteObj, configService);
+ if (!configService.filterSuite(suiteItem.description)) {
+ suiteArray.push(suiteObj);
+ }
+ }
+ obj.suites = suiteArray;
+ }
+ }
+
+ async dryRun(abilityDelegator) {
+ console.info(`${TAG} rootSuite : ` + JSON.stringify(this.rootSuite));
+ let obj = this.rootSuite;
+ let prefixStack = [];
+ let suiteArray = [];
+ let skipSuiteArray = [];
+ this.analyzeSuitesArray(prefixStack, suiteArray, skipSuiteArray, obj);
+ const configService = this.coreContext.getDefaultService('config');
+ let result;
+ if (configService.skipMessage) {
+ result = { 'suites': suiteArray, 'skipSuites': skipSuiteArray };
+ } else {
+ result = { 'suites': suiteArray };
+ }
+ let strJson = JSON.stringify(result);
+ let strLen = strJson.length;
+ let maxLen = 500;
+ let maxCount = Math.floor(strLen / maxLen);
+ for (let count = 0; count <= maxCount; count++) {
+ await SysTestKit.print(strJson.substring(count * maxLen, (count + 1) * maxLen));
+ }
+ console.info(`${TAG}dryRun print success`);
+ abilityDelegator.finishTest('dry run finished!!!', 0, () => { });
+ }
+
+ //将suitesArray的嵌套结构展开成三层结构
+ analyzeSuitesArray(prefixStack, suiteArray, skipSuiteArray, obj) {
+ obj.childSuites.map(suite => {
+ if (suite.description != null && suite.description !== '') {
+ let prefix = '';
+ if (prefixStack.length > 0) {
+ prefix = prefixStack.join('.') + '.' + suite.description;
+ } else {
+ prefix = suite.description;
+ }
+ prefixStack.push(suite.description);
+ let temp = {};
+ temp[prefix] = [];
+ let skipTemp = {};
+ skipTemp[prefix] = [];
+ suite.specs.map(spec => {
+ let it = { 'itName': spec.description };
+ spec.isSkip ? skipTemp[prefix].push(it) : temp[prefix].push(it);
+ });
+ suiteArray.push(temp);
+ skipSuiteArray.push(skipTemp);
+ }
+ this.analyzeSuitesArray(prefixStack, suiteArray, skipSuiteArray, suite);
+ prefixStack.pop();
+ });
+ }
+ //获取当前测试套下的所有测试用例数量
+ getAllChildSuiteNum(suite, specArray) {
+ if (suite.specs != null) {
+ suite.specs.forEach(spec => specArray.push(spec));
+ }
+ if (suite.childSuites != null) {
+ suite.childSuites.forEach(it => this.getAllChildSuiteNum(it, specArray));
+ }
+ }
+
+ execute() {
+ const configService = this.coreContext.getDefaultService('config');
+ if (configService.filterValid.length !== 0) {
+ this.coreContext.fireEvents('task', 'incorrectFormat');
+ return;
+ }
+ if (configService.filterXdescribe.length !== 0) {
+ this.coreContext.fireEvents('task', 'incorrectTestSuiteFormat');
+ return;
+ }
+ if (configService.isRandom() && this.rootSuite.childSuites.length > 0) {
+ this.rootSuite.childSuites.sort(function () {
+ return Math.random().toFixed(1) > 0.5 ? -1 : 1;
+ });
+ this.currentRunningSuite = this.rootSuite.childSuites[0];
+ }
+ if (configService.isSupportAsync()) {
+ console.info(`${TAG} rootSuite:` + JSON.stringify(this.rootSuite));
+ let asyncExecute = async () => {
+ await this.coreContext.fireEvents('task', 'taskStart');
+ await this.rootSuite.asyncRun(this.coreContext);
+ };
+ asyncExecute().then(async () => {
+ await this.coreContext.fireEvents('task', 'taskDone');
+ });
+ } else {
+ console.info('${TAG} rootSuite:' + JSON.stringify(this.rootSuite));
+ this.coreContext.fireEvents('task', 'taskStart');
+ this.rootSuite.run(this.coreContext);
+ this.coreContext.fireEvents('task', 'taskDone');
+ }
+ }
+
+ apis() {
+ const _this = this;
+ return {
+ describe: function (desc, func) {
+ return _this.describe(desc, func);
+ },
+ xdescribe: function (desc, func, reason) {
+ return _this.xdescribe(desc, func, reason);
+ },
+ beforeItSpecified: function (itDescs, func) {
+ return _this.beforeItSpecified(itDescs, func);
+ },
+ afterItSpecified: function (itDescs, func) {
+ return _this.afterItSpecified(itDescs, func);
+ },
+ beforeAll: function (func) {
+ return _this.beforeAll(func);
+ },
+ beforeEach: function (func) {
+ return _this.beforeEach(func);
+ },
+ afterAll: function (func) {
+ return _this.afterAll(func);
+ },
+ afterEach: function (func) {
+ return _this.afterEach(func);
+ }
+ };
+ }
+}
+
+SuiteService.Suite = class {
+ constructor(attrs) {
+ this.description = attrs.description || '';
+ this.childSuites = [];
+ this.specs = [];
+ this.beforeAll = [];
+ this.afterAll = [];
+ this.beforeItSpecified = new Map();
+ this.afterItSpecified = new Map();
+ this.beforeEach = [];
+ this.afterEach = [];
+ this.duration = 0;
+ this.hookError = null;
+ this.isSkip = false;
+ this.skipReason = '';
+ }
+
+ pushSpec(spec) {
+ this.specs.push(spec);
+ }
+
+ removeSpec(desc) {
+ this.specs = this.specs.filter((item, index) => {
+ return item.description !== desc;
+ });
+ }
+
+ getSpecsNum() {
+ return this.specs.length;
+ }
+
+ isRun(coreContext) {
+ const configService = coreContext.getDefaultService('config');
+ const suiteService = coreContext.getDefaultService('suite');
+ const specService = coreContext.getDefaultService('spec');
+ let breakOnError = configService.isBreakOnError();
+ let isError = specService.getStatus();
+ return breakOnError && isError;
+ }
+
+ run(coreContext) {
+ const suiteService = coreContext.getDefaultService('suite');
+ suiteService.setCurrentRunningSuite(this);
+ if (this.description !== '') {
+ coreContext.fireEvents('suite', 'suiteStart', this);
+ }
+ this.runHookFunc('beforeAll');
+ if (this.specs.length > 0) {
+ const configService = coreContext.getDefaultService('config');
+ if (configService.isRandom()) {
+ this.specs.sort(function () {
+ return Math.random().toFixed(1) > 0.5 ? -1 : 1;
+ });
+ }
+ for (let spec in this.specs) {
+ let isBreakOnError = this.isRun(coreContext);
+ if (isBreakOnError) {
+ break;
+ }
+ this.runHookFunc('beforeEach');
+ spec.run(coreContext);
+ this.runHookFunc('afterEach');
+ }
+ }
+ if (this.childSuites.length > 0) {
+ for (let suite in this.childSuites) {
+ let isBreakOnError = this.isRun(coreContext);
+ if (isBreakOnError) {
+ break;
+ }
+ suite.run(coreContext);
+ suiteService.setCurrentRunningSuite(suite);
+ }
+ }
+ this.runHookFunc('afterAll');
+ if (this.description !== '') {
+ coreContext.fireEvents('suite', 'suiteDone');
+ }
+ }
+
+ async asyncRunSpecs(coreContext) {
+ const configService = coreContext.getDefaultService('config');
+ if (configService.isRandom()) {
+ this.specs.sort(function () {
+ return Math.random().toFixed(1) > 0.5 ? -1 : 1;
+ });
+ }
+ const specService = coreContext.getDefaultService('spec');
+ for (let specItem of this.specs) {
+ specService.setCurrentRunningSpec(specItem);
+ // 遇错即停模式,发现用例有问题,直接返回,不在执行后面的it
+ let isBreakOnError = this.isRun(coreContext);
+ if (isBreakOnError) {
+ console.info('break description :' + this.description);
+ break;
+ }
+ await coreContext.fireEvents('spec', 'specStart', specItem);
+ try {
+ for (const [itNames, hookFunc] of this.beforeItSpecified) {
+ if ((Object.prototype.toString.call(itNames) === '[object Array]' && itNames.includes(specItem.description)) ||
+ (Object.prototype.toString.call(itNames) === '[object String]' && itNames === specItem.description)) {
+ await Reflect.apply(hookFunc, null, []);
+ }
+ break;
+ }
+ await this.runAsyncHookFunc('beforeEach');
+ await specItem.asyncRun(coreContext);
+ for (const [itNames, hookFunc] of this.afterItSpecified) {
+ if ((Object.prototype.toString.call(itNames) === '[object Array]' && itNames.includes(specItem.description)) ||
+ (Object.prototype.toString.call(itNames) === '[object String]' && itNames === specItem.description)) {
+ await Reflect.apply(hookFunc, null, []);
+ }
+ break;
+ }
+ await this.runAsyncHookFunc('afterEach');
+ } catch (e) {
+ console.error(`${TAG}stack:${e?.stack}`);
+ console.error(`${TAG}stack end`);
+ if (e instanceof AssertException) {
+ specItem.fail = e;
+ } else {
+ specItem.error = e;
+ }
+ specService.setStatus(true);
+ }
+ specItem.setResult();
+ await coreContext.fireEvents('spec', 'specDone', specItem);
+ specService.setCurrentRunningSpec(null);
+ }
+ }
+
+ async asyncRunChildSuites(coreContext) {
+ for (let i = 0; i < this.childSuites.length; i++) {
+ // 遇错即停模式, 发现用例有问题,直接返回,不在执行后面的description
+ let isBreakOnError = this.isRun(coreContext);
+ if (isBreakOnError) {
+ console.info(`${TAG}break description : ${this.description}`);
+ break;
+ }
+ await this.childSuites[i].asyncRun(coreContext);
+ }
+ }
+
+ async asyncRun(coreContext) {
+ const suiteService = coreContext.getDefaultService('suite');
+ const specService = coreContext.getDefaultService('spec');
+
+ suiteService.setCurrentRunningSuite(this);
+ suiteService.suitesStack.push(this);
+ if (this.description !== '') {
+ await coreContext.fireEvents('suite', 'suiteStart', this);
+ }
+
+ try {
+ await this.runAsyncHookFunc('beforeAll');
+ } catch (error) {
+ console.error(`${TAG}${error?.stack}`);
+ this.hookError = error;
+ }
+
+ if (this.hookError !== null) {
+ specService.setStatus(true);
+ await suiteService.setSuiteResults(this, this.hookError, coreContext);
+ }
+
+ if (this.specs.length > 0 && this.hookError === null) {
+ await this.asyncRunSpecs(coreContext);
+ }
+
+ if (this.childSuites.length > 0 && this.hookError === null) {
+ await this.asyncRunChildSuites(coreContext);
+ }
+
+ try {
+ await this.runAsyncHookFunc('afterAll');
+ } catch (error) {
+ console.error(`${TAG}${error?.stack}`);
+ this.hookError = error;
+ specService.setStatus(true);
+ }
+
+ if (this.description !== '') {
+ await coreContext.fireEvents('suite', 'suiteDone');
+ let childSuite = suiteService.suitesStack.pop();
+ let currentRunningSuite = suiteService.suitesStack.pop();
+ suiteService.setCurrentRunningSuite(currentRunningSuite);
+ suiteService.suitesStack.push(currentRunningSuite);
+ }
+ }
+
+ runHookFunc(hookName) {
+ if (this[hookName] && this[hookName].length > 0) {
+ this[hookName].forEach(func => {
+ try {
+ func();
+ } catch (e) {
+ console.error(`${TAG}${e.stack}`);
+ }
+ });
+ }
+ }
+
+ async runAsyncHookFunc(hookName) {
+ for (const hookItem of this[hookName]) {
+ try {
+ await hookItem();
+ } catch (error) {
+ error['message'] += `, error in ${hookName} function`;
+ throw error;
+ }
+
+ }
+ }
+};
+
+class SpecService {
+ constructor(attr) {
+ this.id = attr.id;
+ this.totalTest = 0;
+ this.hasError = false;
+ this.skipSpecNum = 0;
+ this.isSkipSpec = false;
+ this.specSkipReason = '';
+ }
+
+ init(coreContext) {
+ this.coreContext = coreContext;
+ }
+
+ setCurrentRunningSpec(spec) {
+ this.currentRunningSpec = spec;
+ }
+
+ setStatus(obj) {
+ this.hasError = obj;
+ }
+
+ getStatus() {
+ return this.hasError;
+ }
+
+ getTestTotal() {
+ return this.totalTest;
+ }
+
+ getCurrentRunningSpec() {
+ return this.currentRunningSpec;
+ }
+
+
+ getSkipSpecNum() {
+ return this.skipSpecNum;
+ }
+
+ initSpecService() {
+ this.isSkipSpec = false;
+ this.specSkipReason = '';
+ }
+
+ it(desc, filter, func) {
+ const suiteService = this.coreContext.getDefaultService('suite');
+ const configService = this.coreContext.getDefaultService('config');
+ let isFilter = new NestFilter().filterNestName(suiteService.targetSuiteArray, suiteService.targetSpecArray, suiteService.suitesStack, desc);
+ if (configService.filterWithNest(desc, filter)) {
+ console.info(`${TAG}filter it :${desc}`);
+ this.initSpecService();
+ return;
+ }
+ if (configService.filterDesc(suiteService.currentRunningSuite.description, desc, filter, this.coreContext) && isFilter && !suiteService.fullRun) {
+ console.info(`${TAG}filter it :${desc}`);
+ this.initSpecService();
+ } else {
+ let processedFunc = processFunc(this.coreContext, func);
+ const spec = new SpecService.Spec({ description: desc, fi: filter, fn: processedFunc });
+ if (this.isSkipSpec) {
+ spec.isSkip = true;
+ spec.skipReason = this.specSkipReason;
+ }
+ this.initSpecService();
+ if (configService.runSkipped === 'skipped' && !spec.isSkip) {
+ console.info(`${TAG} runSkipped is skipped , just run xit, don't run it: ${spec.description}`);
+ return;
+ }
+ if (suiteService.getCurrentRunningSuite().isSkip && !spec.isSkip) {
+ configService.filterXdescribe.push(suiteService.getCurrentRunningSuite().description);
+ }
+ if (typeof this.coreContext.getServices('dataDriver') !== 'undefined' && configService['dryRun'] !== 'true') {
+ let specStress = this.coreContext.getServices('dataDriver').dataDriver.getSpecStress(desc);
+ for (let i = 1; i < specStress; i++) {
+ this.totalTest++;
+ suiteService.getCurrentRunningSuite().pushSpec(spec);
+ }
+ }
+ // dryRun 状态下不统计压力测试重复数据
+ if (configService['dryRun'] !== 'true') {
+ let stress = configService.getStress(); // 命令配置压力测试
+ console.info(`${TAG}stress length : ${stress}`);
+ for (let i = 1; i < stress; i++) {
+ this.totalTest++;
+ suiteService.getCurrentRunningSuite().pushSpec(spec);
+ }
+ }
+ this.totalTest++;
+ suiteService.getCurrentRunningSuite().pushSpec(spec);
+ }
+ }
+
+ xit(desc, filter, func, reason) {
+ const configService = this.coreContext.getDefaultService('config');
+ const suiteService = this.coreContext.getDefaultService('suite');
+ if (!configService.skipMessage && configService.runSkipped !== 'all') {
+ if (configService.runSkipped != null && configService.runSkipped !== '') {
+ let finalDesc = '';
+ suiteService.suitesStack.map(suite => {
+ finalDesc = finalDesc + '.' + suite.description;
+ });
+ finalDesc = (finalDesc + '#' + desc).substring(2);
+ if (configService.checkIfSpecInSkipRun(finalDesc)) {
+ console.info(`${TAG} runSkipped spec: ${desc}`);
+ } else {
+ console.info(reason == null ? `${TAG} skip spec: ${desc}` : `${TAG} skip spec: ${desc}, and the reason is ${reason}`);
+ return;
+ }
+ } else {
+ console.info(reason == null ? `${TAG} skip spec: ${desc}` : `${TAG} skip spec: ${desc}, and the reason is ${reason}`);
+ return;
+ }
+ }
+ this.skipSpecNum++;
+ this.isSkipSpec = true;
+ this.specSkipReason = reason;
+ this.it(desc, filter, func);
+ }
+
+ apis() {
+ const _this = this;
+ return {
+ it: function (desc, filter, func) {
+ return _this.it(desc, filter, func);
+ },
+ xit: function (desc, filter, func, reason) {
+ return _this.xit(desc, filter, func, reason);
+ }
+ };
+ }
+}
+
+SpecService.Spec = class {
+ constructor(attrs) {
+ this.description = attrs.description || '';
+ this.fi = attrs.fi;
+ this.fn = attrs.fn || function () {
+ };
+ this.fail = undefined;
+ this.error = undefined;
+ this.duration = 0;
+ this.startTime = 0;
+ this.isExecuted = false; // 当前用例是否执行
+ this.isSkip = false;
+ this.skipReason = '';
+ this.expectMsg = '';
+ }
+
+ setResult() {
+ if (this.fail) {
+ this.pass = false;
+ } else {
+ this.pass = true;
+ }
+ }
+
+ run(coreContext) {
+ const specService = coreContext.getDefaultService('spec');
+ specService.setCurrentRunningSpec(this);
+ coreContext.fireEvents('spec', 'specStart', this);
+ this.isExecuted = true;
+ try {
+ let dataDriver = coreContext.getServices('dataDriver');
+ if (typeof dataDriver === 'undefined') {
+ this.fn();
+ } else {
+ let suiteParams = dataDriver.dataDriver.getSuiteParams();
+ let specParams = dataDriver.dataDriver.getSpecParams();
+ console.info(`${TAG}[suite params] ${JSON.stringify(suiteParams)}`);
+ console.info(`${TAG}[spec params] ${JSON.stringify(specParams)}`);
+ if (this.fn.length === 0) {
+ this.fn();
+ } else if (specParams.length === 0) {
+ this.fn(suiteParams);
+ } else {
+ specParams.forEach(paramItem => this.fn(Object.assign({}, paramItem, suiteParams)));
+ }
+ }
+ this.setResult();
+ } catch (e) {
+ this.error = e;
+ specService.setStatus(true);
+ }
+ coreContext.fireEvents('spec', 'specDone', this);
+ }
+
+ async asyncRun(coreContext) {
+ const dataDriver = coreContext.getServices('dataDriver');
+ if (typeof dataDriver === 'undefined') {
+ await this.fn();
+ } else {
+ const suiteParams = dataDriver.dataDriver.getSuiteParams();
+ const specParams = dataDriver.dataDriver.getSpecParams();
+ console.info(`[suite params] ${JSON.stringify(suiteParams)}`);
+ console.info(`[spec params] ${JSON.stringify(specParams)}`);
+ if (this.fn.length === 0) {
+ await this.fn();
+ } else if (specParams.length === 0) {
+ await this.fn(suiteParams);
+ } else {
+ for (const paramItem of specParams) {
+ await this.fn(Object.assign({}, paramItem, suiteParams));
+ }
+ }
+ }
+
+ this.isExecuted = true;
+ }
+
+ filterCheck(coreContext) {
+ const specService = coreContext.getDefaultService('spec');
+ specService.setCurrentRunningSpec(this);
+ return true;
+ }
+};
+
+class ExpectService {
+ constructor(attr) {
+ this.id = attr.id;
+ this.matchers = {};
+ this.customMatchers = [];
+ }
+
+ expect(actualValue) {
+ return this.wrapMatchers(actualValue);
+ }
+
+ init(coreContext) {
+ this.coreContext = coreContext;
+ this.addMatchers(this.basicMatchers());
+ }
+
+ addMatchers(matchers) {
+ for (const matcherName in matchers) {
+ if (Object.prototype.hasOwnProperty.call(matchers, matcherName)) {
+ this.matchers[matcherName] = matchers[matcherName];
+ }
+ }
+ }
+
+ removeMatchers(customAssertionName) {
+ if (customAssertionName === 'all') {
+ for (const matcherName in this.matchers) {
+ this.matchers[matcherName] = this.customMatchers.includes(matcherName) ? (() => {throw new Error(`${matcherName} is unregistered`)}) : undefined;
+ }
+ }else {
+ this.matchers[customAssertionName] = () => {
+ throw new Error(`${customAssertionName} is unregistered`)
+ };
+ }
+ }
+
+ basicMatchers() {
+ return {
+ assertTrue: function (actualValue) {
+ return {
+ pass: (actualValue) === true,
+ message: 'expect true, actualValue is ' + actualValue
+ };
+ },
+ assertEqual: function (actualValue, args) {
+ let msg = 'expect ' + actualValue + ' equals ' + args[0];
+ if (actualValue == args[0]) { // 数值相同,提示数据类型
+ const aClassName = Object.prototype.toString.call(actualValue);
+ const bClassName = Object.prototype.toString.call(args[0]);
+ msg = 'expect ' + actualValue + aClassName + ' equals ' + args[0] + bClassName + 'strict mode inspect type';
+ }
+ return {
+ pass: (actualValue) === args[0],
+ expectValue: args[0],
+ message: msg
+ };
+ },
+ assertThrow: function (actual, args) {
+ const result = {
+ pass: false
+ };
+ if (typeof actual !== 'function') {
+ result.message = 'toThrow\'s Actual should be a Function';
+ } else {
+ let hasThrow = false;
+ let throwError;
+ try {
+ actual();
+ } catch (e) {
+ hasThrow = true;
+ throwError = e;
+ }
+ if (!hasThrow) {
+ result.message = 'function did not throw an exception';
+ } else if (throwError && throwError.message === args[0]) {
+ result.pass = true;
+ } else {
+ result.message = `expect to throw ${args[0]} , actual throw ${throwError.message}`;
+ }
+ }
+ return result;
+ }
+ };
+ }
+
+ initWrapMatchers(currentRunningSpec) {
+ return {
+ // 翻转标识
+ isNot: false,
+ // 翻转方法
+ not: function () {
+ this.isNot = true;
+ return this;
+ },
+ message: function (msg) {
+ currentRunningSpec.expectMsg = msg;
+ console.info(`${TAG} msg: ${msg}`);
+ return this;
+ }
+ };
+
+ }
+ wrapMatchers(actualValue) {
+ const _this = this;
+ const specService = _this.coreContext.getDefaultService('spec');
+ const currentRunningSpec = specService.getCurrentRunningSpec();
+ const wrappedMatchers = this.initWrapMatchers(currentRunningSpec);
+ const currentRunningSuite = _this.coreContext.getDefaultService('suite').getCurrentRunningSuite();
+ for (const matcherName in this.matchers) {
+ let result = Object.prototype.hasOwnProperty.call(this.matchers, matcherName);
+ if (!result) {
+ continue;
+ }
+ if (matcherName.search('assertPromise') == 0) {
+ wrappedMatchers[matcherName] = async function () {
+ await _this.matchers[matcherName](actualValue, arguments).then(function (result) {
+ if (wrappedMatchers.isNot) {
+ result.pass = !result.pass;
+ }
+ result.actualValue = actualValue;
+ result.checkFunc = matcherName;
+ if (!result.pass) {
+ const assertError = new AssertException(result.message);
+ currentRunningSpec ? currentRunningSpec.fail = assertError : currentRunningSuite.hookError = assertError;
+ throw assertError;
+ }
+ });
+ };
+ } else {
+ wrappedMatchers[matcherName] = function () {
+ const result = _this.customMatchers.includes(matcherName) ? _this.matchers[matcherName](actualValue, arguments[0]) : _this.matchers[matcherName](actualValue, arguments);
+ if (wrappedMatchers.isNot) {
+ result.pass = !result.pass;
+ result.message = LogExpectError.getErrorMsg(matcherName, actualValue, arguments[0], result.message);
+ }
+ result.actualValue = actualValue;
+ result.checkFunc = matcherName;
+ if (!result.pass) {
+ const assertError = new AssertException(result.message);
+ currentRunningSpec ? currentRunningSpec.fail = assertError : currentRunningSuite.hookError = assertError;
+ throw assertError;
+ }
+ };
+ }
+ }
+ return wrappedMatchers;
+ }
+
+ apis() {
+ const _this = this;
+ return {
+ expect: function (actualValue) {
+ return _this.expect(actualValue);
+ }
+ };
+ }
+}
+
+class ReportService {
+ constructor(attr) {
+ this.id = attr.id;
+ }
+
+ init(coreContext) {
+ this.coreContext = coreContext;
+ this.specService = this.coreContext.getDefaultService('spec');
+ this.suiteService = this.coreContext.getDefaultService('suite');
+ this.duration = 0;
+ }
+
+ taskStart() {
+ console.info(`${TAG}[start] start run suites`);
+ }
+
+ async suiteStart() {
+ console.info(`${TAG}[suite start]${this.suiteService.getCurrentRunningSuite().description}`);
+ }
+
+ async specStart() {
+ console.info(`${TAG}start running case '${this.specService.currentRunningSpec.description}'`);
+ this.index = this.index + 1;
+ let spec = this.specService.currentRunningSpec;
+ spec.startTime = await SysTestKit.getRealTime();
+ }
+
+ async specDone() {
+ let msg = '';
+ let spec = this.specService.currentRunningSpec;
+ let suite = this.suiteService.currentRunningSuite;
+ spec.duration = await SysTestKit.getRealTime() - spec.startTime;
+ suite.duration += spec.duration;
+ if (spec.error) {
+ this.formatPrint('error', spec.description + ' ; consuming ' + spec.duration + 'ms');
+ this.formatPrint('errorDetail', spec.error);
+ } else if (spec.fail) {
+ this.formatPrint('fail', spec.description + ' ; consuming ' + spec.duration + 'ms');
+ this.formatPrint('failDetail', spec.fail?.message);
+ } else {
+ this.formatPrint('pass', spec.description + ' ; consuming ' + spec.duration + 'ms');
+ }
+ this.formatPrint(this.specService.currentRunningSpec.error, msg);
+ }
+
+ suiteDone() {
+ let suite = this.suiteService.currentRunningSuite;
+ let message = suite.hookError ? `, ${suite.hookError?.message}` : '';
+ console.info(`[suite end] ${suite.description} consuming ${suite.duration} ms${message}`);
+ }
+
+ taskDone() {
+ let msg = '';
+ let summary = this.suiteService.getSummary();
+ msg = 'total cases:' + summary.total + ';failure ' + summary.failure + ',' + 'error ' + summary.error;
+ msg += ',pass ' + summary.pass + '; consuming ' + summary.duration + 'ms';
+ console.info(`${TAG}${msg}`);
+ console.info(`${TAG}[end] run suites end`);
+ }
+
+ incorrectFormat() {
+ if (this.coreContext.getDefaultService('config').filterValid.length !== 0) {
+ this.coreContext.getDefaultService('config').filterValid.forEach(function (item) {
+ console.info(`${TAG}this param ${item} is invalid`);
+ });
+ }
+ }
+
+ incorrectTestSuiteFormat() {
+ if (this.coreContext.getDefaultService('config').filterXdescribe.length !== 0) {
+ this.coreContext.getDefaultService('config').filterXdescribe.forEach(function (item) {
+ console.info(`${TAG}xdescribe: ${item} should not contain it`);
+ })
+ }
+ }
+
+ formatPrint(type, msg) {
+ switch (type) {
+ case 'pass':
+ console.info(`${TAG}[pass]${msg}`);
+ break;
+ case 'fail':
+ console.info(`${TAG}[fail]${msg}`);
+ break;
+ case 'failDetail':
+ console.info(`${TAG}[failDetail]${msg}`);
+ break;
+ case 'error':
+ console.info(`${TAG}[error]${msg}`);
+ break;
+ case 'errorDetail':
+ console.info(`${TAG}[errorDetail]${msg}`);
+ break;
+ }
+ }
+
+ sleep(numberMillis) {
+ var now = new Date();
+ var exitTime = now.getTime() + numberMillis;
+ while (true) {
+ now = new Date();
+ if (now.getTime() > exitTime) {
+ return;
+ }
+ }
+ }
+}
+
+export {
+ SuiteService,
+ SpecService,
+ ExpectService,
+ ReportService
+};
diff --git a/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/testrunner/OpenHarmonyTestRunner.ts b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/testrunner/OpenHarmonyTestRunner.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e6f4c1b12dd69714ed5a4524671abca1fbcaa58c
--- /dev/null
+++ b/code/UI/CalendarViewSwitch/oh_modules/@ohos/hypium/src/main/testrunner/OpenHarmonyTestRunner.ts
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2023-2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { abilityDelegatorRegistry, TestRunner } from '@kit.TestKit';
+import { BusinessError } from '@kit.BasicServicesKit';
+import { hilog } from '@kit.PerformanceAnalysisKit';
+import { resourceManager } from '@kit.LocalizationKit';
+import { util } from '@kit.ArkTS';
+import { Hypium } from '@ohos/hypium';
+import testsuite from '../test/List.test';
+
+let abilityDelegator: abilityDelegatorRegistry.AbilityDelegator;
+let abilityDelegatorArguments: abilityDelegatorRegistry.AbilityDelegatorArgs;
+let jsonPath: string = 'mock/mock-config.json';
+let domain: number = 0x0000; //日志标识,0x0000作为测试框架的业务标识
+let tag: string = 'testTag'; //日志标识字符串,作为tag标识当前runner类下的测试行为
+
+export default class OpenHarmonyTestRunner implements TestRunner {
+ constructor() {
+ }
+
+ onPrepare() {
+ hilog.info(domain, tag, '%{public}s', 'OpenHarmonyTestRunner OnPrepare');
+ }
+
+ async onRun() {
+ hilog.info(domain, tag, '%{public}s', 'OpenHarmonyTestRunner onRun run');
+ abilityDelegatorArguments = abilityDelegatorRegistry.getArguments();
+ abilityDelegator = abilityDelegatorRegistry.getAbilityDelegator();
+ let moduleName = abilityDelegatorArguments.parameters['-m'];
+ let context = abilityDelegator.getAppContext().getApplicationContext().createModuleContext(moduleName);
+ let mResourceManager = context.resourceManager;
+ await checkMock(abilityDelegator, mResourceManager);
+ hilog.info(domain, tag, '%{public}s', 'start run testcase!!!');
+ Hypium.hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite);
+ hilog.info(domain, tag, '%{public}s', 'OpenHarmonyTestRunner onRun end');
+ }
+}
+
+async function checkMock(abilityDelegator: abilityDelegatorRegistry.AbilityDelegator, resourceManager: resourceManager.ResourceManager) {
+ let rawFile: Uint8Array;
+ try {
+ rawFile = resourceManager.getRawFileContentSync(jsonPath);
+ hilog.info(domain, tag, 'MockList file exists');
+ let mockStr: string = util.TextDecoder.create("utf-8", { ignoreBOM: true }).decodeWithStream(rawFile);
+ let mockMap: Record = getMockList(mockStr);
+ try {
+ abilityDelegator.setMockList(mockMap);
+ } catch (error) {
+ let code = (error as BusinessError).code;
+ let message = (error as BusinessError).message;
+ hilog.error(domain, tag, `abilityDelegator.setMockList failed, error code: ${code}, message: ${message}.`);
+ }
+ } catch (error) {
+ let code = (error as BusinessError).code;
+ let message = (error as BusinessError).message;
+ hilog.error(domain, tag, `ResourceManager:callback getRawFileContent failed, error code: ${code}, message: ${message}.`);
+ }
+}
+
+function getMockList(jsonStr: string) {
+ let jsonObj: Record = JSON.parse(jsonStr);
+ let map: Map = new Map(Object.entries(jsonObj));
+ let mockList: Record = {};
+ map.forEach((value: object, key: string) => {
+ let realValue: string = value['source'].toString();
+ mockList[key] = realValue;
+ });
+ hilog.info(domain, tag, '%{public}s', 'mock-json value:' + JSON.stringify(mockList) ?? '');
+ return mockList;
+}
\ No newline at end of file
diff --git a/code/UI/CitySearch/casesfeature/citysearch/BuildProfile.ets b/code/UI/CitySearch/casesfeature/citysearch/BuildProfile.ets
new file mode 100644
index 0000000000000000000000000000000000000000..3a501e5ddee8ea6d28961648fc7dd314a5304bd4
--- /dev/null
+++ b/code/UI/CitySearch/casesfeature/citysearch/BuildProfile.ets
@@ -0,0 +1,17 @@
+/**
+ * Use these variables when you tailor your ArkTS code. They must be of the const type.
+ */
+export const HAR_VERSION = '1.0.0';
+export const BUILD_MODE_NAME = 'debug';
+export const DEBUG = true;
+export const TARGET_NAME = 'default';
+
+/**
+ * BuildProfile Class is used only for compatibility purposes.
+ */
+export default class BuildProfile {
+ static readonly HAR_VERSION = HAR_VERSION;
+ static readonly BUILD_MODE_NAME = BUILD_MODE_NAME;
+ static readonly DEBUG = DEBUG;
+ static readonly TARGET_NAME = TARGET_NAME;
+}
\ No newline at end of file
diff --git a/code/UI/CitySearch/entry/oh-package-lock.json5 b/code/UI/CitySearch/entry/oh-package-lock.json5
new file mode 100644
index 0000000000000000000000000000000000000000..3c0e72c1774e58f616d9bd9244fddf7e5a836f01
--- /dev/null
+++ b/code/UI/CitySearch/entry/oh-package-lock.json5
@@ -0,0 +1,18 @@
+{
+ "meta": {
+ "stableOrder": true
+ },
+ "lockfileVersion": 3,
+ "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.",
+ "specifiers": {
+ "citysearch@../casesfeature/citysearch": "citysearch@../casesfeature/citysearch"
+ },
+ "packages": {
+ "citysearch@../casesfeature/citysearch": {
+ "name": "citysearch",
+ "version": "1.0.0",
+ "resolved": "../casesfeature/citysearch",
+ "registryType": "local"
+ }
+ }
+}
\ No newline at end of file
diff --git a/code/UI/CitySearch/oh-package-lock.json5 b/code/UI/CitySearch/oh-package-lock.json5
new file mode 100644
index 0000000000000000000000000000000000000000..f538ae290f499a46efa12e593420d47f6e9024ff
--- /dev/null
+++ b/code/UI/CitySearch/oh-package-lock.json5
@@ -0,0 +1,19 @@
+{
+ "meta": {
+ "stableOrder": true
+ },
+ "lockfileVersion": 3,
+ "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.",
+ "specifiers": {
+ "@ohos/hypium@1.0.19": "@ohos/hypium@1.0.19"
+ },
+ "packages": {
+ "@ohos/hypium@1.0.19": {
+ "name": "@ohos/hypium",
+ "version": "1.0.19",
+ "integrity": "sha512-cEjDgLFCm3cWZDeRXk7agBUkPqjWxUo6AQeiu0gEkb3J8ESqlduQLSIXeo3cCsm8U/asL7iKjF85ZyOuufAGSQ==",
+ "resolved": "https://ohpm.openharmony.cn/ohpm/@ohos/hypium/-/hypium-1.0.19.har",
+ "registryType": "ohpm"
+ }
+ }
+}
\ No newline at end of file
diff --git a/code/UI/DragAndExchange/.gitignore b/code/UI/DragAndExchange/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..d2ff20141ceed86d87c0ea5d99481973005bab2b
--- /dev/null
+++ b/code/UI/DragAndExchange/.gitignore
@@ -0,0 +1,12 @@
+/node_modules
+/oh_modules
+/local.properties
+/.idea
+**/build
+/.hvigor
+.cxx
+/.clangd
+/.clang-format
+/.clang-tidy
+**/.test
+/.appanalyzer
\ No newline at end of file
diff --git a/code/UI/DragAndExchange/AppScope/app.json5 b/code/UI/DragAndExchange/AppScope/app.json5
new file mode 100644
index 0000000000000000000000000000000000000000..df435a8e5bb8278b5b8e85eb482838c885b68919
--- /dev/null
+++ b/code/UI/DragAndExchange/AppScope/app.json5
@@ -0,0 +1,10 @@
+{
+ "app": {
+ "bundleName": "com.samples.dragandexchange",
+ "vendor": "example",
+ "versionCode": 1000000,
+ "versionName": "1.0.0",
+ "icon": "$media:app_icon",
+ "label": "$string:app_name"
+ }
+}
diff --git a/code/UI/DragAndExchange/AppScope/resources/base/element/string.json b/code/UI/DragAndExchange/AppScope/resources/base/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..6f3663eee48f0f1aca46df80e530e951cbd7dcf3
--- /dev/null
+++ b/code/UI/DragAndExchange/AppScope/resources/base/element/string.json
@@ -0,0 +1,8 @@
+{
+ "string": [
+ {
+ "name": "app_name",
+ "value": "DragAndExchange"
+ }
+ ]
+}
diff --git a/code/UI/DragAndExchange/AppScope/resources/base/media/app_icon.png b/code/UI/DragAndExchange/AppScope/resources/base/media/app_icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..a39445dc87828b76fed6d2ec470dd455c45319e3
Binary files /dev/null and b/code/UI/DragAndExchange/AppScope/resources/base/media/app_icon.png differ
diff --git a/code/UI/DragAndExchange/README.md b/code/UI/DragAndExchange/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..1179d97c76456ad18c4861e70ee64e053c785bb8
--- /dev/null
+++ b/code/UI/DragAndExchange/README.md
@@ -0,0 +1,107 @@
+# Grid和List内拖拽交换子组件位置
+
+### 介绍
+
+本示例分别通过onItemDrop()和onDrop()回调,实现子组件在Grid和List中的子组件位置交换。
+
+
+### 效果图预览
+
+
+
+**使用说明:**
+
+1. 拖拽Grid中子组件,到目标Grid子组件位置,进行两者位置互换。
+2. 拖拽List中子组件,到目标List子组件位置,进行两者位置互换。
+
+### 实现思路
+
+1. 在Grid组件中,通过editMode()打开编辑模式、通过onItemDragStart()指定拖拽时样式、通过onItemDrop()指定拖拽释放时的行为。源码参考[GridSceneView.ets](casesfeature/dragandexchange/src/main/ets/view/GridSceneView.ets)。
+
+ ```ts
+ Grid() { ... }
+ .editMode(true) // 设置Grid进入编辑模式
+ .onItemDragStart((event: ItemDragInfo, itemIndex: number) => { // 设置拖拽过程中显示的图形
+ this.movedItem = this.appInfoList[itemIndex]; // 记录原位置子组件信息
+ return this.itemWhileDrag();
+ })
+ .onItemDrop((event: ItemDragInfo, itemIndex: number, insertIndex: number, isSuccess: boolean) => { // 拖拽释放时,触发回调
+ // isSuccess=false时,说明drop的位置在grid外部;insertIndex > length时,说明有新增元素的事件发生
+ if (isSuccess && insertIndex < this.appInfoList.length) {
+ this.changeIndex(itemIndex, insertIndex); // 互换子组件index值
+ }
+ })
+ ```
+
+
+
+2. 在List组件中,通过ListItem的onDragStart()方法指定拖拽开始时的行为,通过List的onTouch()指定拖拽释放时的行为。源码参考[ListSceneView.ets](casesfeature/dragandexchange/src/main/ets/view/ListSceneView.ets)。
+
+ ```ts
+ List({ space: LIST_SPACE }) {
+ ForEach(this.appInfoList, (item: AppInfo, index) => {
+ ListItem() { ... }
+ .onDragStart(() => {
+ item.visible = false; // 拖拽时,设置子组件原位置图标不可见
+ })
+ .onTouch((event: TouchEvent) => { // 拖拽释放时,记录目标位置子组件index值
+ if (event.type === TouchType.Down) {
+ this.dragIndex = index;
+ }
+ })
+ })
+ }
+ .onDrop((event: DragEvent, extraParams: string) => {
+ let jsonString: JsonObjType = JSON.parse(extraParams) as JsonObjType; // 通过参数extraParams获取原位置子组件index值
+ this.changeIndex(this.dragIndex, jsonString.insertIndex); // 互换子组件index值
+ this.appInfoList[jsonString.insertIndex].visible = true; // 完成互换后,设置子组件原位置图标不可见
+ })
+ ```
+
+### 高性能知识点
+
+**不涉及**
+
+### 工程结构&模块类型
+
+```
+dragandexchange // har类型
+|---pages
+|---|---Launcher.ets // 页面层-方案主页面
+|---view
+|---|---GridSceneView.ets // 视图层-Grid拖拽页面
+|---|---ListSceneView.ets // 视图层-List拖拽页面
+|---model
+|---|---AppInfo.ets // 模型层-App信息模型
+```
+
+
+### 模块依赖
+
+不涉及
+
+### 参考资料
+
+1. [创建网格(Grid/GridItem)](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-layout-development-create-grid-0000001820999753)
+2. [List](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-list-0000001774121286)
+
+### 相关权限
+不涉及
+
+### 约束与限制
+1.本示例仅支持在标准系统上运行,支持设备:RK3568。
+
+2.本示例为Stage模型,支持API12版本SDK,SDK版本号(API Version 12 Release)。
+
+3.本示例需要使用DevEco Studio 5.0.0 Release 才可编译运行。
+
+### 下载
+如需单独下载本工程,执行如下命令:
+
+```javascript
+git init
+git config core.sparsecheckout true
+echo code/UI/DragAndExchange/ > .git/info/sparse-checkout
+git remote add origin https://gitee.com/openharmony/applications_app_samples.git
+git pull origin master
+```
\ No newline at end of file
diff --git a/code/UI/DragAndExchange/build-profile.json5 b/code/UI/DragAndExchange/build-profile.json5
new file mode 100644
index 0000000000000000000000000000000000000000..705361c66d8750670fe9d54c43ec5bb2c617e4d7
--- /dev/null
+++ b/code/UI/DragAndExchange/build-profile.json5
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+{
+ "app": {
+ "signingConfigs": [],
+ "products": [
+ {
+ "name": "default",
+ "signingConfig": "default",
+ "compileSdkVersion": 12,
+ "compatibleSdkVersion": 12,
+ "runtimeOS": "OpenHarmony",
+ "buildOption": {
+ "strictMode": {
+ "caseSensitiveCheck": true,
+ "useNormalizedOHMUrl": true
+ }
+ }
+ }
+ ],
+ "buildModeSet": [
+ {
+ "name": "debug",
+ },
+ {
+ "name": "release"
+ }
+ ]
+ },
+ "modules": [
+ {
+ "name": "entry",
+ "srcPath": "./entry",
+ "targets": [
+ {
+ "name": "default",
+ "applyToProducts": [
+ "default"
+ ]
+ }
+ ]
+ },
+ {
+ "name": "dragandexchange",
+ "srcPath": "./casesfeature/dragandexchange"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/.gitignore b/code/UI/DragAndExchange/casesfeature/dragandexchange/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..e2713a2779c5a3e0eb879efe6115455592caeea5
--- /dev/null
+++ b/code/UI/DragAndExchange/casesfeature/dragandexchange/.gitignore
@@ -0,0 +1,6 @@
+/node_modules
+/oh_modules
+/.preview
+/build
+/.cxx
+/.test
\ No newline at end of file
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/Index.ets b/code/UI/DragAndExchange/casesfeature/dragandexchange/Index.ets
new file mode 100644
index 0000000000000000000000000000000000000000..c6be91e07125237d2e442fc921719b4503056aa5
--- /dev/null
+++ b/code/UI/DragAndExchange/casesfeature/dragandexchange/Index.ets
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export { Launcher } from './src/main/ets/pages/Launcher'
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/build-profile.json5 b/code/UI/DragAndExchange/casesfeature/dragandexchange/build-profile.json5
new file mode 100644
index 0000000000000000000000000000000000000000..aefa5f6959f0e65b9347a5182401ee9f4873007a
--- /dev/null
+++ b/code/UI/DragAndExchange/casesfeature/dragandexchange/build-profile.json5
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+{
+ "apiType": "stageMode",
+ "buildOption": {
+ },
+ "buildOptionSet": [
+ {
+ "name": "release",
+ "arkOptions": {
+ "obfuscation": {
+ "ruleOptions": {
+ "enable": false,
+ "files": [
+ "./obfuscation-rules.txt"
+ ]
+ },
+ "consumerFiles": [
+ "./consumer-rules.txt"
+ ]
+ }
+ },
+ },
+ ],
+ "targets": [
+ {
+ "name": "default"
+ },
+ {
+ "name": "ohosTest"
+ }
+ ]
+}
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/drag_and_exchange.gif b/code/UI/DragAndExchange/casesfeature/dragandexchange/drag_and_exchange.gif
new file mode 100644
index 0000000000000000000000000000000000000000..f90c29959aea4b6bd6a7a3840c426920f03aecde
Binary files /dev/null and b/code/UI/DragAndExchange/casesfeature/dragandexchange/drag_and_exchange.gif differ
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/hvigorfile.ts b/code/UI/DragAndExchange/casesfeature/dragandexchange/hvigorfile.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0785a511e1f806573e5208d382645d48719a0f06
--- /dev/null
+++ b/code/UI/DragAndExchange/casesfeature/dragandexchange/hvigorfile.ts
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { harTasks } from '@ohos/hvigor-ohos-plugin';
+
+export default {
+ system: harTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
+ plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
+}
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/obfuscation-rules.txt b/code/UI/DragAndExchange/casesfeature/dragandexchange/obfuscation-rules.txt
new file mode 100644
index 0000000000000000000000000000000000000000..272efb6ca3f240859091bbbfc7c5802d52793b0b
--- /dev/null
+++ b/code/UI/DragAndExchange/casesfeature/dragandexchange/obfuscation-rules.txt
@@ -0,0 +1,23 @@
+# Define project specific obfuscation rules here.
+# You can include the obfuscation configuration files in the current module's build-profile.json5.
+#
+# For more details, see
+# https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5
+
+# Obfuscation options:
+# -disable-obfuscation: disable all obfuscations
+# -enable-property-obfuscation: obfuscate the property names
+# -enable-toplevel-obfuscation: obfuscate the names in the global scope
+# -compact: remove unnecessary blank spaces and all line feeds
+# -remove-log: remove all console.* statements
+# -print-namecache: print the name cache that contains the mapping from the old names to new names
+# -apply-namecache: reuse the given cache file
+
+# Keep options:
+# -keep-property-name: specifies property names that you want to keep
+# -keep-global-name: specifies names that you want to keep in the global scope
+
+-enable-property-obfuscation
+-enable-toplevel-obfuscation
+-enable-filename-obfuscation
+-enable-export-obfuscation
\ No newline at end of file
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/oh-package.json5 b/code/UI/DragAndExchange/casesfeature/dragandexchange/oh-package.json5
new file mode 100644
index 0000000000000000000000000000000000000000..9450129d2361f4c6c667d630e5b8619ee394ebf0
--- /dev/null
+++ b/code/UI/DragAndExchange/casesfeature/dragandexchange/oh-package.json5
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+{
+ "name": "dragandexchange",
+ "version": "1.0.0",
+ "description": "Please describe the basic information.",
+ "main": "Index.ets",
+ "author": "",
+ "license": "Apache-2.0",
+ "dependencies": {}
+}
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/ets/components/MainPage.ets b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/ets/components/MainPage.ets
new file mode 100644
index 0000000000000000000000000000000000000000..7dc1a0d257a948cd6882b47f74253fdf1acaefcb
--- /dev/null
+++ b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/ets/components/MainPage.ets
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@Component
+export struct MainPage {
+ @State message: string = 'Hello World';
+
+ build() {
+ Row() {
+ Column() {
+ Text(this.message)
+ .fontSize(50)
+ .fontWeight(FontWeight.Bold)
+ }
+ .width('100%')
+ }
+ .height('100%')
+ }
+}
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/ets/model/AppInfo.ets b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/ets/model/AppInfo.ets
new file mode 100644
index 0000000000000000000000000000000000000000..00741b11504c3f647eb28092b87667f0c3a5d3cf
--- /dev/null
+++ b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/ets/model/AppInfo.ets
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * App信息,包括图标、名字、是否可见
+ */
+@Observed
+export class AppInfo {
+ icon: ResourceStr = ''; // 应用图标
+ name: ResourceStr = ''; // 应用名称
+ visible: boolean = true; // 是否可见
+
+ constructor(icon: ResourceStr = '', name: ResourceStr = '', visible: boolean = true) {
+ this.icon = icon;
+ this.name = name;
+ this.visible = visible;
+ }
+}
\ No newline at end of file
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/ets/model/DateSource.ets b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/ets/model/DateSource.ets
new file mode 100644
index 0000000000000000000000000000000000000000..01d5b941bc55992baedddbaad151bf9651a54029
--- /dev/null
+++ b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/ets/model/DateSource.ets
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { AppInfo } from './AppInfo';
+
+export class DataSource implements IDataSource {
+ // 数据变化监听器
+ private listeners: DataChangeListener[] = [];
+ private appInfoList: AppInfo[] = [];
+
+ totalCount(): number {
+ return this.appInfoList.length;
+ }
+
+ setData(index: number, data: AppInfo) {
+ this.appInfoList[index] = data;
+ }
+
+ getData(index: number): AppInfo {
+ return this.appInfoList[index];
+ }
+
+ // 该方法为框架侧调用,为LazyForEach组件向其数据源处添加listener监听
+ registerDataChangeListener(listener: DataChangeListener): void {
+ if (this.listeners.indexOf(listener) < 0) {
+ console.info('add listener');
+ this.listeners.push(listener);
+ }
+ }
+
+ // 该方法为框架侧调用,为对应的LazyForEach组件在数据源处去除listener监听
+ unregisterDataChangeListener(listener: DataChangeListener): void {
+ const pos = this.listeners.indexOf(listener);
+ if (pos >= 0) {
+ console.info('remove listener');
+ this.listeners.splice(pos, 1);
+ }
+ }
+
+ /**
+ * 添加数据
+ * @param data 虚拟数据
+ */
+ pushData(data: AppInfo): void {
+ this.appInfoList.push(data);
+ this.notifyDataAdd(this.appInfoList.length - 1);
+ }
+
+ // 通知LazyForEach组件需要重载所有子组件
+ notifyDataReload(): void {
+ this.listeners.forEach(listener => {
+ listener.onDataReloaded();
+ })
+ }
+
+ // 通知LazyForEach组件需要在index对应索引处添加子组件
+ notifyDataAdd(index: number): void {
+ this.listeners.forEach(listener => {
+ listener.onDataAdd(index);
+ })
+ }
+
+ // 通知LazyForEach组件在index对应索引处数据有变化,需要重建该子组件
+ notifyDataChange(index: number): void {
+ this.listeners.forEach(listener => {
+ listener.onDataChange(index);
+ })
+ }
+ // 通知LazyForEach组件将from索引和to索引处的子组件进行交换
+ notifyDataMove(from: number, to: number): void {
+ this.listeners.forEach(listener => {
+ listener.onDataMove(from, to);
+ })
+ }
+}
\ No newline at end of file
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/ets/pages/Launcher.ets b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/ets/pages/Launcher.ets
new file mode 100644
index 0000000000000000000000000000000000000000..d79c16cbc6e2fabbfc77f585ec1a188b2b94bd2b
--- /dev/null
+++ b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/ets/pages/Launcher.ets
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { GridSceneView } from '../view/GridSceneView';
+import { ListSceneView } from '../view/ListSceneView';
+
+/**
+ * 功能描述: 本示例使用position绝对定位实现应用内悬浮窗,并且通过animateTo结合curves动画曲线实现悬浮窗拖拽跟手和松手吸附边缘的弹性动画效果
+ *
+ * 推荐场景: 悬浮窗显示场景
+ *
+ * 核心组件:
+ * 1. FloatWindowView
+ *
+ * 实现步骤:
+ * 1. 悬浮窗组件使用Stack嵌套video布局,使用属性position绝对定位使组件悬浮,position使用Edges类型控制悬浮窗到父组件四条边的距离
+ * 2. 初始化时悬浮窗的position属性设置top和right,让悬浮窗靠右
+ * 3. 父组件添加onAreaChange回调,获取父组件的宽高
+ * 4. 悬浮窗组件添加onTouchEvent回调,在手指按下时保存触摸点在窗口中的坐标,用于移动时悬浮窗位置的计算
+ * 5. 手指移动时,获取触摸点相对于应用窗口左上角的X和Y坐标,通过计算设置悬浮窗的position坐标实现拖拽,使用默认参数的弹性跟手动画曲线curves.responsiveSpringMotion结合animateTo实现跟手动画效果
+ * 6. 手指抬起时,通过判断悬浮窗中心在水平方向位于父组件中心的左侧或右侧设置悬浮窗靠左或靠右,如果悬浮窗超出内容区上下边界,则将悬浮窗设置在边界位置,使用curves.springMotion弹性动画曲线实现吸附边界时的弹性动画效果
+ */
+@Component
+export struct Launcher {
+ build() {
+ Column() {
+ GridSceneView() // 实现Grid拖拽场景
+ ListSceneView() // 实现List拖拽场景
+ }
+ .width($r("app.string.drag_and_exchange_layout_100_percent"))
+ .height($r("app.string.drag_and_exchange_layout_100_percent"))
+ .justifyContent(FlexAlign.Center)
+ .backgroundImage($r('app.media.drag_and_exchange_wallpaper_default'))
+ .backgroundImageSize(ImageSize.Cover)
+ }
+}
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/ets/view/GridSceneView.ets b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/ets/view/GridSceneView.ets
new file mode 100644
index 0000000000000000000000000000000000000000..3aef13f8f064650bd19764dc7a5d50f723c48f5f
--- /dev/null
+++ b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/ets/view/GridSceneView.ets
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { AppInfo } from '../model/AppInfo';
+import { DataSource } from '../model/DateSource';
+
+const ICON_NUM_IN_GRID: number = 15; // 示例Grid中子组件数目
+
+/**
+ * 实现Grid场景,拖拽交换子组件位置: 通过editMode()打开编辑模式、通过onItemDragStart()
+ * 指定拖拽时样式、通过onItemDrop()指定拖拽释放时的行为
+ */
+@Component
+export struct GridSceneView {
+ @State movedItem: AppInfo = new AppInfo();
+ @State dataSource: DataSource = new DataSource();
+
+ aboutToAppear() {
+ for (let index = 1; index <= ICON_NUM_IN_GRID; index++) {
+ this.dataSource.pushData(new AppInfo($r(`app.media.drag_and_exchange_ic_public_app${index}`), `App${index}`));
+ }
+ }
+
+ build() {
+ Column() {
+ Text($r("app.string.drag_and_exchange_grid_drag_title"))
+ .fontColor(Color.White)
+ .textAlign(TextAlign.Center)
+ .fontSize($r("app.string.drag_and_exchange_opt_title_font_size"))
+ Row() {
+ Grid() {
+ // TODO: 性能知识点:图标一次性完全显示,且禁用滑动,无需懒加载。LazyForEach可以适用在动态添加数据的场景中,参考资料:
+ // https://docs.openharmony.cn/pages/v4.0/zh-cn/application-dev/performance/lazyforeach_optimization.md/
+ LazyForEach(this.dataSource, (item: AppInfo) => {
+ GridItem() {
+ IconWithNameView({ app: item });
+ }
+ .width($r("app.string.drag_and_exchange_icon_square_size"))
+ .height($r("app.string.drag_and_exchange_layout_70"))
+ }, (item: AppInfo) => item.name.toString())
+ }
+ .columnsTemplate('1fr 1fr 1fr 1fr 1fr')
+ .rowsTemplate('1fr 1fr 1fr')
+ .columnsGap($r("app.string.drag_and_exchange_layout_10"))
+ .rowsGap($r("app.string.drag_and_exchange_layout_10"))
+ .editMode(true) // TODO:知识点:设置Grid进入编辑模式,方可拖拽Grid组件内部GridItem
+ .onItemDragStart((event: ItemDragInfo, itemIndex: number) => { // TODO:知识点:在Grid层,通过onItemDragStart实现拖拽开始时的回调行为
+ this.movedItem = this.dataSource.getData(itemIndex);
+ return this.itemWhileDrag(); //设置拖拽过程中显示的图形
+ })
+ .onItemDrop((event: ItemDragInfo, itemIndex: number, insertIndex: number,
+ isSuccess: boolean) => { // TODO:知识点:在Grid层,通过onItemDrop实现拖拽结束后的回调行为
+ // isSuccess=false时,说明drop的位置在grid外部;insertIndex > length时,说明有新增元素的事件发生
+ if (isSuccess && insertIndex < this.dataSource.totalCount()) {
+ let temp: AppInfo = this.dataSource.getData(itemIndex);
+ this.dataSource.setData(itemIndex, this.dataSource.getData(insertIndex));
+ this.dataSource.setData(insertIndex, temp);
+ this.dataSource.notifyDataReload();
+ }
+ })
+ .padding({
+ top: $r("app.string.drag_and_exchange_layout_10"),
+ bottom: $r("app.string.drag_and_exchange_layout_10"),
+ left: $r("app.string.drag_and_exchange_layout_5"),
+ right: $r("app.string.drag_and_exchange_layout_5")
+ })
+ }
+ .width($r("app.string.drag_and_exchange_layout_90_percent"))
+ .height($r("app.string.drag_and_exchange_layout_250"))
+ .borderRadius($r("app.string.drag_and_exchange_layout_20"))
+ .opacity($r("app.string.drag_and_exchange_background_opacity"))
+ .backgroundColor($r('app.color.drag_and_exchange_background_color'))
+ }
+ }
+
+ /**
+ * 设置GridItem拖拽过程中显示的图形
+ */
+ @Builder
+ itemWhileDrag() {
+ IconWithNameView({ app: this.movedItem })
+ .width($r("app.string.drag_and_exchange_icon_square_size"))
+ .height($r("app.string.drag_and_exchange_icon_square_size"))
+ }
+}
+
+/**
+ * App自定义组件
+ */
+@Component
+struct IconWithNameView {
+ @ObjectLink app: AppInfo
+
+ build() {
+ Column() {
+ Image(this.app.icon)
+ .id(`${this.app.name}`)
+ .width($r("app.string.drag_and_exchange_icon_square_size"))
+ .height($r("app.string.drag_and_exchange_icon_square_size"))
+ .objectFit(ImageFit.Cover)
+ .borderRadius($r("app.string.drag_and_exchange_layout_10"))
+ .draggable(false) // TODO:知识点:保持默认值true时,图片有默认拖拽效果,会影响Grid子组件拖拽判断,所以修改为false
+ Text(this.app.name)
+ .width($r("app.string.drag_and_exchange_icon_square_size"))
+ .fontColor(Color.White)
+ .textAlign(TextAlign.Center)
+ .margin({ top: $r("app.string.drag_and_exchange_layout_1") })
+ .fontSize($r("app.string.drag_and_exchange_app_name_font_size"))
+ }
+ }
+}
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/ets/view/ListSceneView.ets b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/ets/view/ListSceneView.ets
new file mode 100644
index 0000000000000000000000000000000000000000..19d0477781f6996a0e3444fc9d96949273dd1848
--- /dev/null
+++ b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/ets/view/ListSceneView.ets
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { AppInfo } from '../model/AppInfo';
+import { DataSource } from '../model/DateSource';
+
+const ICON_NUM_IN_LIST: number = 4; // 示例List中子组件数目
+const LIST_SPACE: number = 30; // 列表默认间隔
+
+/**
+ * 实现List场景,拖拽交换子组件位置: 通过ListItem的onDragStart()方法指定拖拽开始时的行为,通过List的onTouch()指定拖拽释放时的行为。
+ */
+@Component
+export struct ListSceneView {
+ @State dataSource: DataSource = new DataSource();
+ @State dragIndex: number = 0;
+
+ aboutToAppear() {
+ for (let index = 0; index < ICON_NUM_IN_LIST; index++) {
+ this.dataSource.pushData(new AppInfo($r(`app.media.drag_and_exchange_ic_public_game${index + 1}`),
+ `Item${index + 1}`, true));
+ }
+ }
+
+ changeIndex(index1: number, index2: number) {
+ let temp: AppInfo = this.dataSource.getData(index1);
+ this.dataSource.setData(index1, this.dataSource.getData(index2));
+ this.dataSource.setData(index2, temp);
+ }
+
+ build() {
+ Column() {
+ Text($r("app.string.drag_and_exchange_list_drag_title"))
+ .fontColor(Color.White)
+ .textAlign(TextAlign.Center)
+ .fontSize($r("app.string.drag_and_exchange_opt_title_font_size"))
+ Row() { // 仅靠List实现背景框,padding调整样式后,互换时可能错位
+ List({ space: LIST_SPACE }) {
+ // TODO: 性能知识点:图标一次性完全显示,且禁用滑动,无需懒加载。LazyForEach可以适用在动态添加数据的场景中,参考资料:
+ // https://docs.openharmony.cn/pages/v4.0/zh-cn/application-dev/performance/lazyforeach_optimization.md/
+ LazyForEach(this.dataSource, (item: AppInfo, index) => {
+ ListItem() {
+ Column() {
+ IconNoNameView({ app: item })
+ }
+ }
+ .onDragStart((event: DragEvent, extraParams: string) => { // TODO:知识点:在ListItem层,通过onDragStart实现拖拽开始时的回调行为
+ item.visible = false; // 拖拽时,设置子组件原位置图标不可见
+ // 记录目标位置子组件index值
+ this.dragIndex = (JSON.parse(extraParams) as JsonObjType).selectedIndex;
+ })
+ .onDragEnd(() => {
+ item.visible = true;
+ })
+ }, (item: AppInfo) => item.name.toString())
+ }
+ .scrollBar(BarState.Off)
+ .height($r("app.string.drag_and_exchange_layout_90"))
+ .listDirection(Axis.Horizontal)
+ .alignListItem(ListItemAlign.Center)
+ .onDrop((event: DragEvent, extraParams: string) => { // TODO:知识点:在List层,通过onDrop实现拖拽结束后的回调行为
+ let insertIndex: number = (JSON.parse(extraParams) as JsonObjType).insertIndex; // 通过参数extraParams获取原位置子组件index值
+ if (insertIndex >= this.dataSource.totalCount()) {
+ return;
+ }
+ this.changeIndex(this.dragIndex, insertIndex); // 互换子组件index值
+ this.dataSource.notifyDataReload();
+ })
+ .enableScrollInteraction(false) // 禁用滑动
+ .alignListItem(ListItemAlign.Center)
+ .padding({
+ top: $r("app.string.drag_and_exchange_layout_10"),
+ bottom: $r("app.string.drag_and_exchange_layout_10"),
+ left: $r("app.string.drag_and_exchange_layout_15"),
+ right: $r("app.string.drag_and_exchange_layout_15")
+ })
+ }
+ .justifyContent(FlexAlign.Center)
+ .height($r("app.string.drag_and_exchange_layout_90"))
+ .width($r("app.string.drag_and_exchange_layout_90_percent"))
+ .borderRadius($r("app.string.drag_and_exchange_layout_20"))
+ .opacity($r("app.string.drag_and_exchange_background_opacity"))
+ .backgroundColor($r('app.color.drag_and_exchange_background_color'))
+ }
+ .margin({ top: $r("app.string.drag_and_exchange_layout_20") })
+ }
+}
+
+/**
+ * 无名字App自定义组件
+ */
+@Component
+struct IconNoNameView {
+ @ObjectLink app: AppInfo;
+
+ build() {
+ Column() {
+ Image(this.app.icon)
+ .id(`${this.app.name}`)
+ .width($r("app.string.drag_and_exchange_icon_square_size"))
+ .height($r("app.string.drag_and_exchange_icon_square_size"))
+ .objectFit(ImageFit.Cover)
+ .borderRadius($r("app.string.drag_and_exchange_layout_10"))
+ .draggable(false) // TODO:知识点:保持默认值true时,图片有默认拖拽效果,会影响List子组件拖拽动效,所以修改为false
+ Text(this.app.name)
+ .width($r("app.string.drag_and_exchange_icon_square_size"))
+ .fontColor(Color.White)
+ .textAlign(TextAlign.Center)
+ .margin({ top: $r("app.string.drag_and_exchange_layout_1") })
+ .fontSize($r("app.string.drag_and_exchange_app_name_font_size"))
+ }
+ .visibility(this.app.visible ? Visibility.Visible :
+ Visibility.Hidden) // 消失时需要占位,所以使用显隐控制而非条件渲染。(条件渲染与显隐控制区别,参考资料:https://docs.openharmony.cn/pages/v4.0/zh-cn/application-dev/performance/proper-choice-between-if-and-visibility.md/)
+ }
+}
+
+/**
+ * 封装处理处理JSON对象的类
+ */
+class JsonObjType {
+ public insertIndex: number;
+ public selectedIndex: number;
+
+ constructor(insertIndex: number, selectedIndex: number) {
+ this.insertIndex = insertIndex;
+ this.selectedIndex = selectedIndex;
+ }
+}
\ No newline at end of file
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/module.json5 b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/module.json5
new file mode 100644
index 0000000000000000000000000000000000000000..82488d1e7a2cf601b805d944bd4dc4ade39679ae
--- /dev/null
+++ b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/module.json5
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+{
+ "module": {
+ "name": "dragandexchange",
+ "type": "har",
+ "deviceTypes": [
+ "default",
+ "tablet"
+ ]
+ }
+}
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/element/color.json b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/element/color.json
new file mode 100644
index 0000000000000000000000000000000000000000..a63243bbdb8bc9206c9f733a42b8b8328695faae
--- /dev/null
+++ b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/element/color.json
@@ -0,0 +1,8 @@
+{
+ "color": [
+ {
+ "name": "drag_and_exchange_background_color",
+ "value": "#a9c2cc"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/element/string.json b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..57c97f100fb07ffa4bb8fd2625cfe907e7bf3877
--- /dev/null
+++ b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/element/string.json
@@ -0,0 +1,72 @@
+{
+ "string": [
+ {
+ "name": "page_show",
+ "value": "page from package"
+ },
+ {
+ "name": "drag_and_exchange_grid_drag_title",
+ "value": "Grid拖动互换子组件"
+ },
+ {
+ "name": "drag_and_exchange_list_drag_title",
+ "value": "List拖动互换子组件"
+ },
+ {
+ "name": "drag_and_exchange_layout_100_percent",
+ "value": "100%"
+ },
+ {
+ "name": "drag_and_exchange_layout_90_percent",
+ "value": "90%"
+ },
+ {
+ "name": "drag_and_exchange_layout_250",
+ "value": "250"
+ },
+ {
+ "name": "drag_and_exchange_layout_70",
+ "value": "70"
+ },
+ {
+ "name": "drag_and_exchange_layout_90",
+ "value": "90"
+ },
+ {
+ "name": "drag_and_exchange_icon_square_size",
+ "value": "50"
+ },
+ {
+ "name": "drag_and_exchange_layout_20",
+ "value": "20"
+ },
+ {
+ "name": "drag_and_exchange_layout_15",
+ "value": "15"
+ },
+ {
+ "name": "drag_and_exchange_layout_10",
+ "value": "10"
+ },
+ {
+ "name": "drag_and_exchange_layout_5",
+ "value": "5"
+ },
+ {
+ "name": "drag_and_exchange_layout_1",
+ "value": "1"
+ },
+ {
+ "name": "drag_and_exchange_opt_title_font_size",
+ "value": "25"
+ },
+ {
+ "name": "drag_and_exchange_app_name_font_size",
+ "value": "16"
+ },
+ {
+ "name": "drag_and_exchange_background_opacity",
+ "value": "0.8"
+ }
+ ]
+}
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app1.png b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app1.png
new file mode 100644
index 0000000000000000000000000000000000000000..af06b54d499b84d062e3324d1aac11d1f07253d0
Binary files /dev/null and b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app1.png differ
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app10.png b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app10.png
new file mode 100644
index 0000000000000000000000000000000000000000..be5fbb520460f0d7a84e2504a20618f9a9f7ca3b
Binary files /dev/null and b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app10.png differ
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app11.png b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app11.png
new file mode 100644
index 0000000000000000000000000000000000000000..1b653fff3b41b9e47dd37a6409836fe3c43714b5
Binary files /dev/null and b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app11.png differ
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app12.png b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app12.png
new file mode 100644
index 0000000000000000000000000000000000000000..071ce9bb09eb0c0c50a58233ec471bcb4a16c150
Binary files /dev/null and b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app12.png differ
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app13.png b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app13.png
new file mode 100644
index 0000000000000000000000000000000000000000..4b34a1c988d0fdd4eb190c07c87d37dd351d7c05
Binary files /dev/null and b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app13.png differ
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app14.png b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app14.png
new file mode 100644
index 0000000000000000000000000000000000000000..4e2e6caaec42d2eadb165336741be66a212cf553
Binary files /dev/null and b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app14.png differ
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app15.png b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app15.png
new file mode 100644
index 0000000000000000000000000000000000000000..9c346dc57e3db10cd826a12fe21f1bf9d793cb8d
Binary files /dev/null and b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app15.png differ
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app2.png b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app2.png
new file mode 100644
index 0000000000000000000000000000000000000000..ed714aa652869dd11dfc88c121b682571b29c8bd
Binary files /dev/null and b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app2.png differ
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app3.png b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app3.png
new file mode 100644
index 0000000000000000000000000000000000000000..ddbea05998261e0913a99715f1d40223e2fb4fae
Binary files /dev/null and b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app3.png differ
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app4.png b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app4.png
new file mode 100644
index 0000000000000000000000000000000000000000..753e8b834c01afbf81811b94d5f3b9aa62f48698
Binary files /dev/null and b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app4.png differ
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app5.png b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app5.png
new file mode 100644
index 0000000000000000000000000000000000000000..80c6fc06ee1d7f73ace0d65e7145d8cee61886f8
Binary files /dev/null and b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app5.png differ
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app6.png b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app6.png
new file mode 100644
index 0000000000000000000000000000000000000000..7d1d7edd6bb40d01be4d5de5b6fe83a553b1e54d
Binary files /dev/null and b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app6.png differ
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app7.png b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app7.png
new file mode 100644
index 0000000000000000000000000000000000000000..2b73f2db2199d39017a953bac19f2a62a682d988
Binary files /dev/null and b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app7.png differ
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app8.png b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app8.png
new file mode 100644
index 0000000000000000000000000000000000000000..f01981332e7d08dfcec5a4dbd70f3a1599e8c2db
Binary files /dev/null and b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app8.png differ
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app9.png b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app9.png
new file mode 100644
index 0000000000000000000000000000000000000000..251fe00b3c6fb4a356ba23d071d7c9d627d5d1d2
Binary files /dev/null and b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_app9.png differ
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_game1.png b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_game1.png
new file mode 100644
index 0000000000000000000000000000000000000000..97d743fb0ed625811021d3dc2b11cd9c551ef55c
Binary files /dev/null and b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_game1.png differ
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_game2.png b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_game2.png
new file mode 100644
index 0000000000000000000000000000000000000000..9284d4ea522b82304306b58caa0fc8a3b390e128
Binary files /dev/null and b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_game2.png differ
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_game3.png b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_game3.png
new file mode 100644
index 0000000000000000000000000000000000000000..0405eaa7f7177515eead0de38ac0d4dcfe34e2f7
Binary files /dev/null and b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_game3.png differ
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_game4.png b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_game4.png
new file mode 100644
index 0000000000000000000000000000000000000000..23a5cfbd6b53fd96197be042dfd92e1c86104914
Binary files /dev/null and b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_ic_public_game4.png differ
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_wallpaper_default.jpg b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_wallpaper_default.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..54b99a3a86507a98b248d417f4222c61f0a12971
Binary files /dev/null and b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/base/media/drag_and_exchange_wallpaper_default.jpg differ
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/rawfile/routerMap/dragandexchange.json b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/rawfile/routerMap/dragandexchange.json
new file mode 100644
index 0000000000000000000000000000000000000000..6148ae29ddd40bb058162651a429e25e9429bb31
--- /dev/null
+++ b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/main/resources/rawfile/routerMap/dragandexchange.json
@@ -0,0 +1,10 @@
+{
+ "routerMap": [
+ {
+ "name": "dragandexchange/LauncherComponent",
+ "pageModule": "dragandexchange",
+ "pageSourceFile": "src/main/ets/generated/RouterBuilder.ets",
+ "registerFunction": "launcherComponentRegister"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/src/ohosTest/ets/test/Ability.test.ets b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/ohosTest/ets/test/Ability.test.ets
new file mode 100644
index 0000000000000000000000000000000000000000..0f8ce9a2c012f8fe36114cef65216ef0b6254f41
--- /dev/null
+++ b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/ohosTest/ets/test/Ability.test.ets
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { hilog } from '@kit.PerformanceAnalysisKit';
+import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium';
+
+export default function abilityTest() {
+ describe('ActsAbilityTest', () => {
+ // Defines a test suite. Two parameters are supported: test suite name and test suite function.
+ beforeAll(() => {
+ // Presets an action, which is performed only once before all test cases of the test suite start.
+ // This API supports only one parameter: preset action function.
+ })
+ beforeEach(() => {
+ // Presets an action, which is performed before each unit test case starts.
+ // The number of execution times is the same as the number of test cases defined by **it**.
+ // This API supports only one parameter: preset action function.
+ })
+ afterEach(() => {
+ // Presets a clear action, which is performed after each unit test case ends.
+ // The number of execution times is the same as the number of test cases defined by **it**.
+ // This API supports only one parameter: clear action function.
+ })
+ afterAll(() => {
+ // Presets a clear action, which is performed after all test cases of the test suite end.
+ // This API supports only one parameter: clear action function.
+ })
+ it('assertContain', 0, () => {
+ // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
+ hilog.info(0x0000, 'testTag', '%{public}s', 'it begin');
+ let a = 'abc';
+ let b = 'b';
+ // Defines a variety of assertion methods, which are used to declare expected boolean conditions.
+ expect(a).assertContain(b);
+ expect(a).assertEqual(a);
+ })
+ })
+}
\ No newline at end of file
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/src/ohosTest/ets/test/List.test.ets b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/ohosTest/ets/test/List.test.ets
new file mode 100644
index 0000000000000000000000000000000000000000..1eac52fcebe8958e19a7b8fed2e8f39c520a3e42
--- /dev/null
+++ b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/ohosTest/ets/test/List.test.ets
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import abilityTest from './Ability.test';
+
+export default function testsuite() {
+ abilityTest();
+}
\ No newline at end of file
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/src/ohosTest/module.json5 b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/ohosTest/module.json5
new file mode 100644
index 0000000000000000000000000000000000000000..0d2052f0ef91a710622e32d9e4d3b635764866ca
--- /dev/null
+++ b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/ohosTest/module.json5
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+{
+ "module": {
+ "name": "dragandexchange_test",
+ "type": "feature",
+ "deviceTypes": [
+ "default",
+ "tablet"
+ ],
+ "deliveryWithInstall": true,
+ "installationFree": false
+ }
+}
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/src/test/List.test.ets b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/test/List.test.ets
new file mode 100644
index 0000000000000000000000000000000000000000..f1186b1f53c3a70930921c5dbd1417332bec56c9
--- /dev/null
+++ b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/test/List.test.ets
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import localUnitTest from './LocalUnit.test';
+
+export default function testsuite() {
+ localUnitTest();
+}
\ No newline at end of file
diff --git a/code/UI/DragAndExchange/casesfeature/dragandexchange/src/test/LocalUnit.test.ets b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/test/LocalUnit.test.ets
new file mode 100644
index 0000000000000000000000000000000000000000..7fc57c77dbf76d8df08a2b802a55b948e3fcf968
--- /dev/null
+++ b/code/UI/DragAndExchange/casesfeature/dragandexchange/src/test/LocalUnit.test.ets
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium';
+
+export default function localUnitTest() {
+ describe('localUnitTest', () => {
+ // Defines a test suite. Two parameters are supported: test suite name and test suite function.
+ beforeAll(() => {
+ // Presets an action, which is performed only once before all test cases of the test suite start.
+ // This API supports only one parameter: preset action function.
+ });
+ beforeEach(() => {
+ // Presets an action, which is performed before each unit test case starts.
+ // The number of execution times is the same as the number of test cases defined by **it**.
+ // This API supports only one parameter: preset action function.
+ });
+ afterEach(() => {
+ // Presets a clear action, which is performed after each unit test case ends.
+ // The number of execution times is the same as the number of test cases defined by **it**.
+ // This API supports only one parameter: clear action function.
+ });
+ afterAll(() => {
+ // Presets a clear action, which is performed after all test cases of the test suite end.
+ // This API supports only one parameter: clear action function.
+ });
+ it('assertContain', 0, () => {
+ // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
+ let a = 'abc';
+ let b = 'b';
+ // Defines a variety of assertion methods, which are used to declare expected boolean conditions.
+ expect(a).assertContain(b);
+ expect(a).assertEqual(a);
+ });
+ });
+}
\ No newline at end of file
diff --git a/code/UI/DragAndExchange/code-linter.json5 b/code/UI/DragAndExchange/code-linter.json5
new file mode 100644
index 0000000000000000000000000000000000000000..28586467ee7a761c737d8654a73aed6fddbc3c71
--- /dev/null
+++ b/code/UI/DragAndExchange/code-linter.json5
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+{
+ "files": [
+ "**/*.ets"
+ ],
+ "ignore": [
+ "**/src/ohosTest/**/*",
+ "**/src/test/**/*",
+ "**/src/mock/**/*",
+ "**/node_modules/**/*",
+ "**/oh_modules/**/*",
+ "**/build/**/*",
+ "**/.preview/**/*"
+ ],
+ "ruleSet": [
+ "plugin:@performance/recommended",
+ "plugin:@typescript-eslint/recommended"
+ ],
+ "rules": {
+ }
+}
\ No newline at end of file
diff --git a/code/UI/DragAndExchange/entry/.gitignore b/code/UI/DragAndExchange/entry/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..e2713a2779c5a3e0eb879efe6115455592caeea5
--- /dev/null
+++ b/code/UI/DragAndExchange/entry/.gitignore
@@ -0,0 +1,6 @@
+/node_modules
+/oh_modules
+/.preview
+/build
+/.cxx
+/.test
\ No newline at end of file
diff --git a/code/UI/DragAndExchange/entry/build-profile.json5 b/code/UI/DragAndExchange/entry/build-profile.json5
new file mode 100644
index 0000000000000000000000000000000000000000..e7569e3056e27af38e9991b7ea73ec10f3ba8a05
--- /dev/null
+++ b/code/UI/DragAndExchange/entry/build-profile.json5
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+{
+ "apiType": "stageMode",
+ "buildOption": {
+ },
+ "buildOptionSet": [
+ {
+ "name": "release",
+ "arkOptions": {
+ "obfuscation": {
+ "ruleOptions": {
+ "enable": false,
+ "files": [
+ "./obfuscation-rules.txt"
+ ]
+ }
+ }
+ }
+ },
+ ],
+ "targets": [
+ {
+ "name": "default"
+ },
+ {
+ "name": "ohosTest",
+ }
+ ]
+}
\ No newline at end of file
diff --git a/code/UI/DragAndExchange/entry/hvigorfile.ts b/code/UI/DragAndExchange/entry/hvigorfile.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e4f43d54667f8327c367c8096bd08bb8c75aff54
--- /dev/null
+++ b/code/UI/DragAndExchange/entry/hvigorfile.ts
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { hapTasks } from '@ohos/hvigor-ohos-plugin';
+
+export default {
+ system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
+ plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
+}
diff --git a/code/UI/DragAndExchange/entry/obfuscation-rules.txt b/code/UI/DragAndExchange/entry/obfuscation-rules.txt
new file mode 100644
index 0000000000000000000000000000000000000000..272efb6ca3f240859091bbbfc7c5802d52793b0b
--- /dev/null
+++ b/code/UI/DragAndExchange/entry/obfuscation-rules.txt
@@ -0,0 +1,23 @@
+# Define project specific obfuscation rules here.
+# You can include the obfuscation configuration files in the current module's build-profile.json5.
+#
+# For more details, see
+# https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5
+
+# Obfuscation options:
+# -disable-obfuscation: disable all obfuscations
+# -enable-property-obfuscation: obfuscate the property names
+# -enable-toplevel-obfuscation: obfuscate the names in the global scope
+# -compact: remove unnecessary blank spaces and all line feeds
+# -remove-log: remove all console.* statements
+# -print-namecache: print the name cache that contains the mapping from the old names to new names
+# -apply-namecache: reuse the given cache file
+
+# Keep options:
+# -keep-property-name: specifies property names that you want to keep
+# -keep-global-name: specifies names that you want to keep in the global scope
+
+-enable-property-obfuscation
+-enable-toplevel-obfuscation
+-enable-filename-obfuscation
+-enable-export-obfuscation
\ No newline at end of file
diff --git a/code/UI/DragAndExchange/entry/oh-package-lock.json5 b/code/UI/DragAndExchange/entry/oh-package-lock.json5
new file mode 100644
index 0000000000000000000000000000000000000000..325ba95f285e4132a2f48f1cdfc1f7faf3332f07
--- /dev/null
+++ b/code/UI/DragAndExchange/entry/oh-package-lock.json5
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+{
+ "meta": {
+ "stableOrder": true
+ },
+ "lockfileVersion": 3,
+ "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.",
+ "specifiers": {
+ "dragandexchange@../casesfeature/dragandexchange": "dragandexchange@../casesfeature/dragandexchange"
+ },
+ "packages": {
+ "dragandexchange@../casesfeature/dragandexchange": {
+ "name": "dragandexchange",
+ "version": "1.0.0",
+ "resolved": "../casesfeature/dragandexchange",
+ "registryType": "local"
+ }
+ }
+}
\ No newline at end of file
diff --git a/code/UI/DragAndExchange/entry/oh-package.json5 b/code/UI/DragAndExchange/entry/oh-package.json5
new file mode 100644
index 0000000000000000000000000000000000000000..d3c9181b773041b3e04c4167b1b3ab605d5300f4
--- /dev/null
+++ b/code/UI/DragAndExchange/entry/oh-package.json5
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+{
+ "name": "entry",
+ "version": "1.0.0",
+ "description": "Please describe the basic information.",
+ "main": "",
+ "author": "",
+ "license": "",
+ "dependencies": {
+ "dragandexchange": "file:../casesfeature/dragandexchange"
+ }
+}
+
diff --git a/code/UI/DragAndExchange/entry/src/main/ets/entryability/EntryAbility.ets b/code/UI/DragAndExchange/entry/src/main/ets/entryability/EntryAbility.ets
new file mode 100644
index 0000000000000000000000000000000000000000..edc2839f203ba057c186e19b0cbbbf80c8faa8b3
--- /dev/null
+++ b/code/UI/DragAndExchange/entry/src/main/ets/entryability/EntryAbility.ets
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit';
+import { hilog } from '@kit.PerformanceAnalysisKit';
+import { window } from '@kit.ArkUI';
+
+export default class EntryAbility extends UIAbility {
+ onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
+ this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);
+ hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
+ }
+
+ onDestroy(): void {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
+ }
+
+ onWindowStageCreate(windowStage: window.WindowStage): void {
+ // Main window is created, set main page for this ability
+ hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
+
+ windowStage.loadContent('pages/Index', (err) => {
+ if (err.code) {
+ hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
+ return;
+ }
+ hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.');
+ });
+ }
+
+ onWindowStageDestroy(): void {
+ // Main window is destroyed, release UI related resources
+ hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
+ }
+
+ onForeground(): void {
+ // Ability has brought to foreground
+ hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
+ }
+
+ onBackground(): void {
+ // Ability has back to background
+ hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
+ }
+}
\ No newline at end of file
diff --git a/code/UI/DragAndExchange/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets b/code/UI/DragAndExchange/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets
new file mode 100644
index 0000000000000000000000000000000000000000..b1e212947256c5533c7b06285a597c94f840a6e3
--- /dev/null
+++ b/code/UI/DragAndExchange/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { hilog } from '@kit.PerformanceAnalysisKit';
+import { BackupExtensionAbility, BundleVersion } from '@kit.CoreFileKit';
+
+export default class EntryBackupAbility extends BackupExtensionAbility {
+ async onBackup() {
+ hilog.info(0x0000, 'testTag', 'onBackup ok');
+ }
+
+ async onRestore(bundleVersion: BundleVersion) {
+ hilog.info(0x0000, 'testTag', 'onRestore ok %{public}s', JSON.stringify(bundleVersion));
+ }
+}
\ No newline at end of file
diff --git a/code/UI/DragAndExchange/entry/src/main/ets/pages/Index.ets b/code/UI/DragAndExchange/entry/src/main/ets/pages/Index.ets
new file mode 100644
index 0000000000000000000000000000000000000000..209336138b94635b2aa6963ab4fdd1a44eb6969a
--- /dev/null
+++ b/code/UI/DragAndExchange/entry/src/main/ets/pages/Index.ets
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { Launcher } from 'dragandexchange';
+
+@Entry
+@Component
+struct Index {
+ @State message: string = 'Hello World';
+
+ build() {
+ Column() {
+ /**
+ * 功能描述:本示例介绍Grid和List内拖拽交换子组件位置的使用:通过onItemDrop()和onDrop()回调,实现子组件在Grid和List中的子组件位置交换。
+ * 参数介绍:无
+ */
+ Launcher()
+ }
+ .height('100%')
+ .width('100%')
+ }
+}
\ No newline at end of file
diff --git a/code/UI/DragAndExchange/entry/src/main/module.json5 b/code/UI/DragAndExchange/entry/src/main/module.json5
new file mode 100644
index 0000000000000000000000000000000000000000..4144486d1af4c03b0d767cce1cda86fc0d697f91
--- /dev/null
+++ b/code/UI/DragAndExchange/entry/src/main/module.json5
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+{
+ "module": {
+ "name": "entry",
+ "type": "entry",
+ "description": "$string:module_desc",
+ "mainElement": "EntryAbility",
+ "deviceTypes": [
+ "default",
+ "tablet"
+ ],
+ "deliveryWithInstall": true,
+ "installationFree": false,
+ "pages": "$profile:main_pages",
+ "abilities": [
+ {
+ "name": "EntryAbility",
+ "srcEntry": "./ets/entryability/EntryAbility.ets",
+ "description": "$string:EntryAbility_desc",
+ "icon": "$media:layered_image",
+ "label": "$string:EntryAbility_label",
+ "startWindowIcon": "$media:startIcon",
+ "startWindowBackground": "$color:start_window_background",
+ "exported": true,
+ "skills": [
+ {
+ "entities": [
+ "entity.system.home"
+ ],
+ "actions": [
+ "action.system.home"
+ ]
+ }
+ ]
+ }
+ ],
+ "extensionAbilities": [
+ {
+ "name": "EntryBackupAbility",
+ "srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets",
+ "type": "backup",
+ "exported": false,
+ "metadata": [
+ {
+ "name": "ohos.extension.backup",
+ "resource": "$profile:backup_config"
+ }
+ ]
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/code/UI/DragAndExchange/entry/src/main/resources/base/element/color.json b/code/UI/DragAndExchange/entry/src/main/resources/base/element/color.json
new file mode 100644
index 0000000000000000000000000000000000000000..3c712962da3c2751c2b9ddb53559afcbd2b54a02
--- /dev/null
+++ b/code/UI/DragAndExchange/entry/src/main/resources/base/element/color.json
@@ -0,0 +1,8 @@
+{
+ "color": [
+ {
+ "name": "start_window_background",
+ "value": "#FFFFFF"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/code/UI/DragAndExchange/entry/src/main/resources/base/element/string.json b/code/UI/DragAndExchange/entry/src/main/resources/base/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..f94595515a99e0c828807e243494f57f09251930
--- /dev/null
+++ b/code/UI/DragAndExchange/entry/src/main/resources/base/element/string.json
@@ -0,0 +1,16 @@
+{
+ "string": [
+ {
+ "name": "module_desc",
+ "value": "module description"
+ },
+ {
+ "name": "EntryAbility_desc",
+ "value": "description"
+ },
+ {
+ "name": "EntryAbility_label",
+ "value": "label"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/code/UI/DragAndExchange/entry/src/main/resources/base/media/background.png b/code/UI/DragAndExchange/entry/src/main/resources/base/media/background.png
new file mode 100644
index 0000000000000000000000000000000000000000..f939c9fa8cc8914832e602198745f592a0dfa34d
Binary files /dev/null and b/code/UI/DragAndExchange/entry/src/main/resources/base/media/background.png differ
diff --git a/code/UI/DragAndExchange/entry/src/main/resources/base/media/foreground.png b/code/UI/DragAndExchange/entry/src/main/resources/base/media/foreground.png
new file mode 100644
index 0000000000000000000000000000000000000000..4483ddad1f079e1089d685bd204ee1cfe1d01902
Binary files /dev/null and b/code/UI/DragAndExchange/entry/src/main/resources/base/media/foreground.png differ
diff --git a/code/UI/DragAndExchange/entry/src/main/resources/base/media/layered_image.json b/code/UI/DragAndExchange/entry/src/main/resources/base/media/layered_image.json
new file mode 100644
index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a
--- /dev/null
+++ b/code/UI/DragAndExchange/entry/src/main/resources/base/media/layered_image.json
@@ -0,0 +1,7 @@
+{
+ "layered-image":
+ {
+ "background" : "$media:background",
+ "foreground" : "$media:foreground"
+ }
+}
\ No newline at end of file
diff --git a/code/UI/DragAndExchange/entry/src/main/resources/base/media/startIcon.png b/code/UI/DragAndExchange/entry/src/main/resources/base/media/startIcon.png
new file mode 100644
index 0000000000000000000000000000000000000000..205ad8b5a8a42e8762fbe4899b8e5e31ce822b8b
Binary files /dev/null and b/code/UI/DragAndExchange/entry/src/main/resources/base/media/startIcon.png differ
diff --git a/code/UI/DragAndExchange/entry/src/main/resources/base/profile/backup_config.json b/code/UI/DragAndExchange/entry/src/main/resources/base/profile/backup_config.json
new file mode 100644
index 0000000000000000000000000000000000000000..78f40ae7c494d71e2482278f359ec790ca73471a
--- /dev/null
+++ b/code/UI/DragAndExchange/entry/src/main/resources/base/profile/backup_config.json
@@ -0,0 +1,3 @@
+{
+ "allowToBackupRestore": true
+}
\ No newline at end of file
diff --git a/code/UI/DragAndExchange/entry/src/main/resources/base/profile/main_pages.json b/code/UI/DragAndExchange/entry/src/main/resources/base/profile/main_pages.json
new file mode 100644
index 0000000000000000000000000000000000000000..1898d94f58d6128ab712be2c68acc7c98e9ab9ce
--- /dev/null
+++ b/code/UI/DragAndExchange/entry/src/main/resources/base/profile/main_pages.json
@@ -0,0 +1,5 @@
+{
+ "src": [
+ "pages/Index"
+ ]
+}
diff --git a/code/UI/DragAndExchange/entry/src/main/resources/dark/element/color.json b/code/UI/DragAndExchange/entry/src/main/resources/dark/element/color.json
new file mode 100644
index 0000000000000000000000000000000000000000..79b11c2747aec33e710fd3a7b2b3c94dd9965499
--- /dev/null
+++ b/code/UI/DragAndExchange/entry/src/main/resources/dark/element/color.json
@@ -0,0 +1,8 @@
+{
+ "color": [
+ {
+ "name": "start_window_background",
+ "value": "#000000"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/code/UI/DragAndExchange/entry/src/mock/mock-config.json5 b/code/UI/DragAndExchange/entry/src/mock/mock-config.json5
new file mode 100644
index 0000000000000000000000000000000000000000..7a73a41bfdf76d6f793007240d80983a52f15f97
--- /dev/null
+++ b/code/UI/DragAndExchange/entry/src/mock/mock-config.json5
@@ -0,0 +1,2 @@
+{
+}
\ No newline at end of file
diff --git a/code/UI/DragAndExchange/entry/src/ohosTest/ets/test/Ability.test.ets b/code/UI/DragAndExchange/entry/src/ohosTest/ets/test/Ability.test.ets
new file mode 100644
index 0000000000000000000000000000000000000000..bc1553f7ff3a895d7e37631b98dea51acf98ae27
--- /dev/null
+++ b/code/UI/DragAndExchange/entry/src/ohosTest/ets/test/Ability.test.ets
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { describe, it, expect } from '@ohos/hypium';
+import { Driver, ON } from '@ohos.UiTest';
+import { logger } from '../utils/logger';
+import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry';
+
+const BUNDLE: string = 'DragAndExchange';
+const TAG: string = '[DragAndExchange_Test]';
+const DELAY_MS: number = 1000; // 指定1000ms的延迟
+
+export default function abilityTest() {
+ describe('ActsAbilityTest', () => {
+ /**
+ * 打开应用
+ */
+ it(BUNDLE + '_StartAbility', 0, async (done: Function) => {
+ logger.info(TAG, BUNDLE + '_StartAbility start');
+ let abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator();
+ try {
+ await abilityDelegator.startAbility({
+ bundleName: 'com.samples.dragandexchange',
+ abilityName: 'EntryAbility'
+ });
+ } catch (exception) {
+ logger.error(TAG, BUNDLE + '_StartAbility error');
+ expect().assertFail();
+ }
+ logger.info(TAG, BUNDLE + '_StartAbility end');
+ done();
+ })
+
+ /**
+ * 拖拽Grid中子组件,到目标Grid子组件位置,进行两者位置互换。
+ */
+ it(BUNDLE + '拖拽Grid中子组件,到目标Grid子组件位置,进行两者位置互换。', 0, async (done: Function) => {
+ let driver = Driver.create();
+ await driver.assertComponentExist(ON.id('App1'));
+ let App1 = await driver.findComponent(ON.id('App1'));
+ let point1 = await App1.getBoundsCenter();
+ await driver.assertComponentExist(ON.id('App3'));
+ let App3 = await driver.findComponent(ON.id('App3'));
+ let point3 = await App3.getBoundsCenter();
+ await App1.dragTo(App3);
+ await driver.delayMs(DELAY_MS);
+ let App12 = await driver.findComponent(ON.id('App1'));
+ let point12 = await App12.getBoundsCenter();
+ expect(point1.x !== point12.x).assertTrue();
+ expect(point12.x === point3.x).assertTrue();
+ done();
+ })
+
+ /**
+ * 拖拽List中子组件,到目标List子组件位置,进行两者位置互换。
+ */
+ it(BUNDLE + '拖拽List中子组件,到目标List子组件位置,进行两者位置互换。', 0, async (done: Function) => {
+ let driver = Driver.create();
+ await driver.assertComponentExist(ON.id('Item1'));
+ let Item1 = await driver.findComponent(ON.id('Item1'));
+ let point1 = await Item1.getBoundsCenter();
+ await driver.assertComponentExist(ON.id('Item3'));
+ let Item3 = await driver.findComponent(ON.id('Item3'));
+ let point3 = await Item3.getBoundsCenter();
+ await Item1.dragTo(Item3);
+ await driver.delayMs(DELAY_MS);
+ let Item12 = await driver.findComponent(ON.id('Item1'));
+ let point12 = await Item12.getBoundsCenter();
+ expect(point1.x !== point12.x).assertTrue();
+ expect(point12.x === point3.x).assertTrue();
+ done();
+ })
+ })
+}
\ No newline at end of file
diff --git a/code/UI/DragAndExchange/entry/src/ohosTest/ets/test/List.test.ets b/code/UI/DragAndExchange/entry/src/ohosTest/ets/test/List.test.ets
new file mode 100644
index 0000000000000000000000000000000000000000..1eac52fcebe8958e19a7b8fed2e8f39c520a3e42
--- /dev/null
+++ b/code/UI/DragAndExchange/entry/src/ohosTest/ets/test/List.test.ets
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import abilityTest from './Ability.test';
+
+export default function testsuite() {
+ abilityTest();
+}
\ No newline at end of file
diff --git a/code/UI/DragAndExchange/entry/src/ohosTest/ets/utils/logger.ets b/code/UI/DragAndExchange/entry/src/ohosTest/ets/utils/logger.ets
new file mode 100644
index 0000000000000000000000000000000000000000..3aba453bab30b2f120f10d0c0c91e7e666ac5dfd
--- /dev/null
+++ b/code/UI/DragAndExchange/entry/src/ohosTest/ets/utils/logger.ets
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import hilog from '@ohos.hilog';
+
+/**
+ * 日志打印类
+ */
+class Logger {
+ private domain: number;
+ private prefix: string;
+ private format: string = '%{public}s, %{public}s';
+
+ constructor(prefix: string) {
+ this.prefix = prefix;
+ this.domain = 0xFF00;
+ this.format.toUpperCase();
+ }
+
+ debug(...args: string[]) {
+ hilog.debug(this.domain, this.prefix, this.format, args);
+ }
+
+ info(...args: string[]) {
+ hilog.info(this.domain, this.prefix, this.format, args);
+ }
+
+ warn(...args: string[]) {
+ hilog.warn(this.domain, this.prefix, this.format, args);
+ }
+
+ error(...args: string[]) {
+ hilog.error(this.domain, this.prefix, this.format, args);
+ }
+}
+
+export let logger = new Logger('[Samples_dragandexchange]');
\ No newline at end of file
diff --git a/code/UI/DragAndExchange/entry/src/ohosTest/module.json5 b/code/UI/DragAndExchange/entry/src/ohosTest/module.json5
new file mode 100644
index 0000000000000000000000000000000000000000..69026872775eebd0844900b225c411959ae5608b
--- /dev/null
+++ b/code/UI/DragAndExchange/entry/src/ohosTest/module.json5
@@ -0,0 +1,12 @@
+{
+ "module": {
+ "name": "entry_test",
+ "type": "feature",
+ "deviceTypes": [
+ "default",
+ "tablet"
+ ],
+ "deliveryWithInstall": true,
+ "installationFree": false
+ }
+}
diff --git a/code/UI/DragAndExchange/entry/src/test/List.test.ets b/code/UI/DragAndExchange/entry/src/test/List.test.ets
new file mode 100644
index 0000000000000000000000000000000000000000..f1186b1f53c3a70930921c5dbd1417332bec56c9
--- /dev/null
+++ b/code/UI/DragAndExchange/entry/src/test/List.test.ets
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import localUnitTest from './LocalUnit.test';
+
+export default function testsuite() {
+ localUnitTest();
+}
\ No newline at end of file
diff --git a/code/UI/DragAndExchange/entry/src/test/LocalUnit.test.ets b/code/UI/DragAndExchange/entry/src/test/LocalUnit.test.ets
new file mode 100644
index 0000000000000000000000000000000000000000..7fc57c77dbf76d8df08a2b802a55b948e3fcf968
--- /dev/null
+++ b/code/UI/DragAndExchange/entry/src/test/LocalUnit.test.ets
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium';
+
+export default function localUnitTest() {
+ describe('localUnitTest', () => {
+ // Defines a test suite. Two parameters are supported: test suite name and test suite function.
+ beforeAll(() => {
+ // Presets an action, which is performed only once before all test cases of the test suite start.
+ // This API supports only one parameter: preset action function.
+ });
+ beforeEach(() => {
+ // Presets an action, which is performed before each unit test case starts.
+ // The number of execution times is the same as the number of test cases defined by **it**.
+ // This API supports only one parameter: preset action function.
+ });
+ afterEach(() => {
+ // Presets a clear action, which is performed after each unit test case ends.
+ // The number of execution times is the same as the number of test cases defined by **it**.
+ // This API supports only one parameter: clear action function.
+ });
+ afterAll(() => {
+ // Presets a clear action, which is performed after all test cases of the test suite end.
+ // This API supports only one parameter: clear action function.
+ });
+ it('assertContain', 0, () => {
+ // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
+ let a = 'abc';
+ let b = 'b';
+ // Defines a variety of assertion methods, which are used to declare expected boolean conditions.
+ expect(a).assertContain(b);
+ expect(a).assertEqual(a);
+ });
+ });
+}
\ No newline at end of file
diff --git a/code/UI/DragAndExchange/hvigor/hvigor-config.json5 b/code/UI/DragAndExchange/hvigor/hvigor-config.json5
new file mode 100644
index 0000000000000000000000000000000000000000..d584c19c247db9a7caee4b606bb931aa9279c637
--- /dev/null
+++ b/code/UI/DragAndExchange/hvigor/hvigor-config.json5
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+{
+ "modelVersion": "5.0.1",
+ "dependencies": {
+ },
+ "execution": {
+ // "analyze": "normal", /* Define the build analyze mode. Value: [ "normal" | "advanced" | false ]. Default: "normal" */
+ // "daemon": true, /* Enable daemon compilation. Value: [ true | false ]. Default: true */
+ // "incremental": true, /* Enable incremental compilation. Value: [ true | false ]. Default: true */
+ // "parallel": true, /* Enable parallel compilation. Value: [ true | false ]. Default: true */
+ // "typeCheck": false, /* Enable typeCheck. Value: [ true | false ]. Default: false */
+ },
+ "logging": {
+ // "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */
+ },
+ "debugging": {
+ // "stacktrace": false /* Disable stacktrace compilation. Value: [ true | false ]. Default: false */
+ },
+ "nodeOptions": {
+ // "maxOldSpaceSize": 8192 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process. Default: 8192*/
+ // "exposeGC": true /* Enable to trigger garbage collection explicitly. Default: true*/
+ }
+}
diff --git a/code/UI/DragAndExchange/hvigorfile.ts b/code/UI/DragAndExchange/hvigorfile.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2a5e543f190732c159beb574dfc9fa37bc94e156
--- /dev/null
+++ b/code/UI/DragAndExchange/hvigorfile.ts
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { appTasks } from '@ohos/hvigor-ohos-plugin';
+
+export default {
+ system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
+ plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
+}
diff --git a/code/UI/DragAndExchange/oh-package.json5 b/code/UI/DragAndExchange/oh-package.json5
new file mode 100644
index 0000000000000000000000000000000000000000..e41bae026aab3b50d0abb42fece08ba43b4a772b
--- /dev/null
+++ b/code/UI/DragAndExchange/oh-package.json5
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+{
+ "modelVersion": "5.0.1",
+ "description": "Please describe the basic information.",
+ "dependencies": {
+ },
+ "devDependencies": {
+ "@ohos/hypium": "1.0.19",
+ "@ohos/hamock": "1.0.0"
+ }
+}
diff --git a/code/UI/DragAndExchange/ohosTest.md b/code/UI/DragAndExchange/ohosTest.md
new file mode 100644
index 0000000000000000000000000000000000000000..192034cbaafaea1d3212ed41fba9f2b93d906805
--- /dev/null
+++ b/code/UI/DragAndExchange/ohosTest.md
@@ -0,0 +1,8 @@
+## Grid和List内拖拽交换子组件位置案例测试用例
+
+### 用例表
+
+| 测试功能 | 预置条件 | 输入 | 预期输出 | 是否自动 | 测试结果 |
+|:---------------------------------:|:---------------------:|:-----------------------:|:------:|:----:|:----:|
+| 拖拽Grid中子组件,到目标Grid子组件位置,进行两者位置互换。 | 启动Grid和List内拖拽交换子组件位置 | 拖拽Grid中子组件,到目标Grid子组件位置 | 两者位置互换 | 否 | Pass |
+| 拖拽List中子组件,到目标List子组件位置,进行两者位置互换。 | 启动Grid和List内拖拽交换子组件位置 | 拖拽List中子组件,到目标List子组件位置 | 两者位置互换 | 否 | Pass |