@@ -38,6 +38,10 @@ private void TestChart(TestInput c)
3838 var expectedTimeline = SimaiCommaTimeline . Flatten ( inote ) ;
3939 var actualTimeline = SimaiCommaTimeline . Flatten ( simai ) ;
4040 SimaiCommaTimeline . AssertTimelineEqual ( expectedTimeline , actualTimeline , chart , _output ) ;
41+
42+ // 转出来的simai,重新parse一次、确保没有任何错误
43+ var ( _, alertsReparsed ) = new SimaiParser ( strictLevel : SimaiParser . StrictLevelEnum . Strict ) . Parse ( simai ) ;
44+ Assert . Empty ( alertsReparsed ) ;
4145 }
4246}
4347
@@ -110,8 +114,8 @@ static IEnumerable<Entry> Canon(IReadOnlyList<Entry> e) =>
110114
111115 private static void AssertNoteEqual ( string expected , string actual , int noteIdx , Rational time , MaiChart chart )
112116 {
113- var expArr = RearrangeNote ( expected ) . Split ( '/' , '`' ) ;
114- var actArr = RearrangeNote ( actual ) . Split ( '/' , '`' ) ;
117+ var expArr = RearrangeNote ( expected ) . Split ( '/' , '`' , '*' ) ;
118+ var actArr = RearrangeNote ( actual ) . Split ( '/' , '`' , '*' ) ;
115119 var max = Math . Max ( expArr . Length , actArr . Length ) ;
116120
117121 for ( var i = 0 ; i < max ; i ++ )
@@ -126,36 +130,7 @@ private static void AssertNoteEqual(string expected, string actual, int noteIdx,
126130 result = exp == act ;
127131 }
128132
129- if ( ! result )
130- {
131- // 尝试是否是只有时间不匹配,如果是的话,允许一定的阈值
132- var expTime = DurationStrRegex ( ) . Match ( exp ) ;
133- var actTime = DurationStrRegex ( ) . Match ( act ) ;
134- var bpm = chart . BpmList . Find ( time ) . Bpm ;
135- if ( expTime . Groups [ 2 ] . Success && actTime . Groups [ 4 ] . Success )
136- { // exp中是分数时间、act中是小数时间的情况
137- // 小数时间化为分数时间,看看是否对的上
138- var numer = decimal . Parse ( actTime . Groups [ 4 ] . Value ) / ( 240 / bpm ) * int . Parse ( expTime . Groups [ 2 ] . Value ) ;
139- if ( Math . Round ( numer ) == int . Parse ( expTime . Groups [ 3 ] . Value ) ) result = true ; // 如果对的上,则不判定为比较失败
140- }
141- else if ( actTime . Groups [ 2 ] . Success && expTime . Groups [ 4 ] . Success )
142- { // exp中是小数时间、act中是分数时间的情况
143- // 分数时间化为小数时间,看是否对的上(差距<1ms)
144- var sec = new Rational ( int . Parse ( actTime . Groups [ 3 ] . Value ) , int . Parse ( actTime . Groups [ 2 ] . Value ) ) * ( 240 / ( Rational ) bpm ) ;
145- if ( Near ( ( double ) sec , double . Parse ( expTime . Groups [ 4 ] . Value ) ) ) result = true ; // 如果对的上,则不判定为比较失败
146- }
147- else if ( actTime . Groups [ 4 ] . Success && expTime . Groups [ 4 ] . Success )
148- { // exp中是小数时间、act中是小数时间的情况
149- var expSec = double . Parse ( expTime . Groups [ 4 ] . Value ) ;
150- var actSec = double . Parse ( actTime . Groups [ 4 ] . Value ) ;
151- if ( Near ( expSec , actSec ) ) result = true ; // 如果对的上,则不判定为比较失败
152- }
153-
154- // 比较等待时间是否相等(没显式写出的就是1拍)
155- var expWait = expTime . Groups [ 1 ] . Success ? double . Parse ( expTime . Groups [ 1 ] . Value ) : 60 / ( double ) bpm ;
156- var actWait = actTime . Groups [ 1 ] . Success ? double . Parse ( actTime . Groups [ 1 ] . Value ) : 60 / ( double ) bpm ;
157- if ( ! Near ( expWait , actWait ) ) result = false ; // 如果等待时间对不上,则仍判定为比较失败
158- }
133+ if ( ! result ) result = CompareDurationStr ( exp , act , time , chart ) ;
159134
160135 if ( ! result ) Assert . Fail (
161136 $ "First difference at Notation { noteIdx + 1 } (time { time } ):{ Environment . NewLine } " +
@@ -165,6 +140,61 @@ private static void AssertNoteEqual(string expected, string actual, int noteIdx,
165140 }
166141 }
167142
143+ private static bool CompareDurationStr ( string exp , string act , Rational time , MaiChart chart )
144+ {
145+ bool result = false ;
146+ // 尝试是否是只有时间不匹配,如果是的话,允许一定的阈值
147+ var expTime = DurationStrRegex ( ) . Match ( exp ) ;
148+ var actTime = DurationStrRegex ( ) . Match ( act ) ;
149+ if ( ! expTime . Success || ! actTime . Success ) return result ;
150+ var expRemain = exp [ ..expTime . Index ] + exp [ ( expTime . Index + expTime . Length ) ..] ;
151+ var actRemain = act [ ..expTime . Index ] + act [ ( actTime . Index + actTime . Length ) ..] ;
152+ if ( actRemain != expRemain ) return result ; // 如果除了时间以外还有其他不一样的,那么直接返回false
153+
154+ // 对act产生的时间标记,做规范性检查。对齐到标准中的每一条
155+ if ( actRemain . Contains ( 'h' ) )
156+ { // Hold / TouchHold
157+ Assert . False ( actTime . Groups [ 1 ] . Success , $ "Hold/TouchHold不应该有等待时间!{ act } ") ;
158+ if ( actTime . Groups [ 4 ] . Success )
159+ { // 绝对时长的情况
160+ Assert . True ( act [ actTime . Groups [ 4 ] . Index - 1 ] == '#' , $ "Hold/TouchHold格式不正确,绝对时长的前面必须带一个井号!{ act } ") ;
161+ }
162+ }
163+ else
164+ {
165+ if ( actTime . Groups [ 4 ] . Success )
166+ { // 绝对时长的情况,前面必须是'bpm#'或'等待时间##'。我们不考虑前面一种情况,则应该断言一定是第二种情况出现了
167+ Assert . True ( actTime . Groups [ 1 ] . Success && actTime . Groups [ 1 ] . Index + actTime . Groups [ 1 ] . Length == actTime . Groups [ 4 ] . Index , $ "星星持续时长使用了非标准语法!{ act } ") ;
168+ }
169+ }
170+
171+ var bpm = chart . BpmList . Find ( time ) . Bpm ;
172+ if ( expTime . Groups [ 2 ] . Success && actTime . Groups [ 4 ] . Success )
173+ { // exp中是分数时间、act中是小数时间的情况
174+ // 小数时间化为分数时间,看看是否对的上
175+ var numer = decimal . Parse ( actTime . Groups [ 4 ] . Value ) / ( 240 / bpm ) * int . Parse ( expTime . Groups [ 2 ] . Value ) ;
176+ if ( Math . Round ( numer ) == int . Parse ( expTime . Groups [ 3 ] . Value ) ) result = true ; // 如果对的上,则不判定为比较失败
177+ }
178+ else if ( actTime . Groups [ 2 ] . Success && expTime . Groups [ 4 ] . Success )
179+ { // exp中是小数时间、act中是分数时间的情况
180+ // 分数时间化为小数时间,看是否对的上(差距<1ms)
181+ var sec = new Rational ( int . Parse ( actTime . Groups [ 3 ] . Value ) , int . Parse ( actTime . Groups [ 2 ] . Value ) ) * ( 240 / ( Rational ) bpm ) ;
182+ if ( Near ( ( double ) sec , double . Parse ( expTime . Groups [ 4 ] . Value ) ) ) result = true ; // 如果对的上,则不判定为比较失败
183+ }
184+ else if ( actTime . Groups [ 4 ] . Success && expTime . Groups [ 4 ] . Success )
185+ { // exp中是小数时间、act中是小数时间的情况
186+ var expSec = double . Parse ( expTime . Groups [ 4 ] . Value ) ;
187+ var actSec = double . Parse ( actTime . Groups [ 4 ] . Value ) ;
188+ if ( Near ( expSec , actSec ) ) result = true ; // 如果对的上,则不判定为比较失败
189+ }
190+
191+ // 比较等待时间是否相等(没显式写出的就是1拍)
192+ var expWait = expTime . Groups [ 1 ] . Success ? double . Parse ( expTime . Groups [ 1 ] . Value ) : 60 / ( double ) bpm ;
193+ var actWait = actTime . Groups [ 1 ] . Success ? double . Parse ( actTime . Groups [ 1 ] . Value ) : 60 / ( double ) bpm ;
194+ if ( ! Near ( expWait , actWait ) ) result = false ; // 如果等待时间对不上,则仍判定为比较失败
195+ return result ;
196+ }
197+
168198 private static string RearrangeNote ( string s )
169199 {
170200 return string . Join ( '`' , s . Split ( '`' ) . Select ( x =>
0 commit comments