MAXScript コードにアサーションを配置するために、Assert 関数を使用できます。また、assert 関数の拡張セットおよび AssertReporter メッセージログ システムが公開されていて、オートデスクは 3ds Max の開発時にテスト スイート用に使用しています。
概要:
アサーションは、開発者がその場所では常に評価が true になると想定してコード内に配置する述語(true|false ステートメント)です。
アサーションは、プログラミングの正しさを検証するために使用されます。
構文
assert <expression> [message:<string>] [options:#( #dialog | #listener | #debug_output_window | #debugBreak | #c_break | #all)] [showstack:<boolean>]
1 番目の引数として関数に渡された式の結果が、コード内の特定の箇所で必ず true であることをアサートします。
式は、ブール値に解決される必要があります。そうでない場合は、MAXScript 例外が発生します。
式が true
を返した場合には、コードは通常どおりに続行されます。
式が false
を返した場合、次のオプションに応じて実行が中断されます。
message:
- このオプション キーワードを指定すると、文字列はアサートのメッセージとして表示されます。
options:
- 次の MAXScript 名前オプションの配列です。配列が空の場合、既定値は #listener
となります。
#dialog
- アプリケーションの実行を中断するモーダル ダイアログ ボックスを表示します。
#listener
- 障害情報を MAXScript リスナーに出力します。
#debug_output_window
- Visual Studio の出力デバッガ ウィンドウに出力します(存在する場合)。
#debugBreak
- MAXScript デバッガでの実行を中断します。このオプションを指定すると、#dialog オプションは無視されます。このオプションは、抑制モードが false の場合にのみ有効です。そうでない場合は何も起こりません。
#c_break
-デバッガで Visual Studio での実行をブレークします。これは、3ds Max のデバッグ ビルドをデバッガで実行している場合にのみ動作します。指定すると、最初に #debug_output_window
フラグが内部でオンになってデバッグが支援されます。 #debugBreak
オプションと #dialog
オプションは無視され、他のオプションがそれぞれのデータを出力できるよう、この動作は必ず最後に行われます。
#all
- #dialog
と #c_break
を除く、上記のすべてが含まれます。
showstack:
- 出力に MAXScript スタック トレースバックを含めるかどうかを定義します。 このオプションは、#listener
オプションと #debug_output_window
オプションにのみ適用されます。他のすべてのオプションについては、スタック情報は無視されます。既定値は false です。
例:
以下の例では、関数がシーン内のすべてのオブジェクトをループしてこれらの位置を累算します。最後に、結果の値をオブジェクトの数で割って、全オブジェクトの平均位置を算出しています。
スクリプト開発者は、シーンが空ではないことを前提としています。 このため、最終結果は有効な位置となります。オブジェクトの数がゼロである場合、ゼロによる除算でプログラムがクラッシュすることはありませんが、Point3 値[-1.#IND,-1.#IND,-1.#IND] が生成されます。
fn averageObjectPosition =
(
theSum = [0,0,0]
theCount = objects.count
for i = 1 to theCount do
(
theSum += objects[i].pos
)
assert (theCount > 0) message: "theCount expected to be positive, but was found not to be!" options:#(#all) showstack:true
theSum /= theCount
)
averageObjectPosition()
開発者は theCount
が常にゼロよりも大きいことを条件とする assert()
呼び出しを使用し、この条件に当てはまらない場合はデバッガでコードの実行をブレークして、リスナーのスタックを表示することにしました。
この例では、デモンストレーションのためにこれを行い、assert()
関数がどのように機能するかを示します。
実際には、どのようなケースをテストすればよいか予想できないために、IF テストで不正な値を補足するのが困難であるような複雑な計算では、一般に assert()
を使用して値を検証します。加えて、assert()
にはいくつかの便利なレポート モードがあります(たとえば、3ds Max のデバッグ ビルドの実行時に C++ デバッガでブレークするなど)。
上の関数を空のシーンで実行すると、結果は以下のようになります。
メッセージを管理するための多くの assert 関数および 1 つの AssertReporter
構造体が実装され、オートデスクでの内部テストに使用できるようになりました。
これらの関数はすべての MAXScript ユーザが利用でき、カスタムのテスト フレームワークで使用してプログラム フローが正確かどうか確認することができます。
これらのテスト フレームワーク関数には、次のような利点があります。
すべての assert は自動的にレポートされます。
この新しいシステムでは、開発者は assert のメッセージで大量のエラー文字列が生成されないようにすることができるため、assert の表示を非常に見やすくすることができます(必要に応じてカスタム メッセージを提供することもできます)。また、これらの assert は静的に実行され、メッセージは専用の AssertReporter
に収集されてコードの実行後に照会および分析されるため、実際のテストの実行を妨げることはありません。
assert 関数は次のとおりです。
<boolean>assert_true <expression>expectedToBeTrue [message:<string>]
式の戻り値が true でない場合は false を返し、AssertReporter
に assert エラー メッセージを記録します。
*"Assert - Expected true, got false - (No File) in framemessage:
キーワード引数が指定されていない場合)。
<boolean>assert_false <expression>expectedToBeFalse [message:<string>]
式の戻り値が false でない場合は false を返し、AssertReporter
に assert エラー メッセージを記録します。
*"Assert - Expected false, got true - (No File) in frame message:
キーワード引数が指定されていない場合)。
<boolean>assert_equal <value>expected <expression>actual [message:<string>]
2 つ目の引数として渡された式の戻り値が最初の引数として渡された必要な値と異なる場合は false を返し、AssertReporter
に assert エラー メッセージを記録します。
*"Assert - Expected 1, got 2 - (No File) in frame message:
キーワード引数が指定されていない場合)。
<boolean>assert_not_equal <value>expected <expression>actual [message:<string>]
2 つ目の引数として渡された式の戻り値が最初の引数として渡された実際の値と等しい場合は false を返し、AssertReporter
に assert エラー メッセージを記録します。
*"Assert - Expected value not equal tomessage:
キーワード引数が指定されていない場合)。
<boolean>assert_defined <expression>expectedToBeDefined [message:<string>]
式の戻り値が undefined の場合は false を返し、AssertReporter
に assert エラー メッセージを記録します。
*"Assert - Expected "defined", got undefined - (No File) in framemessage:
キーワード引数が指定されていない場合)。
<boolean>assert_undefined <expression>expectedToBeUndefined [message:<string>]
式の戻り値が undefined でない場合は false を返し、AssertReporter
に assert エラー メッセージを記録します。
*"Assert - Expected undefined, got 1 - (No File) in frame message:
キーワード引数が指定されていない場合)。
<boolean>assert_float <float>expected <expression>actual [tolerance:<float>delta] [message:<string>]
<boolean>assert_float_equal <float>expected <expression>actual [tolerance:<float>delta] [message:<string>]
2 つ目の引数として渡された式の戻り値が必要な float 値でない場合は false を返し AssertReporter
に assert エラー メッセージを記録します。
tolerance:
オプション キーワード引数が指定され、実際の戻り値が必要な値と異なり、許容差値を超えている場合は false を返します。
*"Assert - Expected 1.0, got 2 - (No File) in frame message:
キーワード引数が指定されていない場合)。
assert_float_equal()
のバージョンは assert_float()
と同じですが、他の assert 関数に対応する、わかりやすい名前が付いているため、記載しています。3ds Max 2021.1 Update 以降で使用可能です。
<boolean>assert_string_equal <string>expected <exression>actual [ignorecase:<boolean>val]
[message:]
2 つ目の引数として渡された式の戻り値が、必要な文字列と異なる場合は false を返します。
オプションの ignorecase:
キーワード引数の既定値は true です。大文字小文字を区別して比較を実行する場合は false として指定する必要があります。
*"Assert - Expected "A", got "b" - (No File) in frame message:
キーワード引数が指定されていない場合)。
<boolean>assert_point3_equal <point3>expected <expression>actual [tolerance:<float>delta]
[message:]
2 つ目の引数として渡された式の戻り値が必要な Point3 値と異なる場合は false を返します。
tolerance:
オプション キーワード引数が指定され、実際の戻り値の構成要素のいずれかが必要な値と異なり、対応する構成要素が許容差値を超えている場合は false を返します。
*"Assert - Expected [1,2,3], got [1.1,2.1,3.1] - (No File) in frame message:
キーワード引数が指定されていない場合)。
<boolean>assert_matrix_equal <matrix>expected <matrix>actual [tolerance:<float>delta]
[message:]
2 つ目の引数として渡されたこの式の戻り値が期待した行列値と異なる場合は false を返します
tolerance:
オプション キーワード引数が指定され、実際の戻り値の構成要素のいずれかが必要な値と異なり、対応する構成要素が許容差値を超えている場合は false を返します。
*"Assert - Expected (matrix3 [1,0,0] [0,1,0] [0,0,1] [0,0,0]), got (matrix3 [1,0,0] [0,1,0] [0,0,1] [42.1234,43.8329,0]) - (No File) in frame message:
キーワード引数が指定されていない場合)。
コンピュータの数値表現の精度が制限されているため、assert_float()
メソッドや assert_point3_equal()
メソッドを使用しているときに、許容差ぎりぎりの値では assert が記録される場合と記録されない場合があります。
例:
floatVariable = 1.0
assert_float 1.1 floatVariable tolerance:0.1
-->"Assert - Expected 1.1, got 1.0 ..."
ただし、次のコードを使用すると、assert はありません。
point3Variable = [1,2,3]
assert_point3_equal [1.0,2.0,3.1] point3Variable tolerance:0.1
上記の結果では、最初のメソッドで必要な値と実際の値の差が許容値未満であるかどうかを確認しています。この例では、許容値未満ではありません。この 2 つの値は内部で double に変換されて、先頭の 7 桁の小数位が同一(すべてゼロ)であるため、この差は許容差未満ではありません。
一方、2 つ目の例では、Point3 値[1.0,2.0,3.1]は実際に内部では[1.0,2.0,3.0999999]として表されます。したがって、3.0 と 3.0999999 の差は許容値を若干下回り、精度エラーにより、asset は true として渡します。
<boolean>assert_array_equal expected actual [message:<string>] [tolerance:<boolean>] [ignoreCase:<boolean>]
2 つ目の引数として渡された式の戻り値が、予想された配列と異なる場合は false を返します。3ds Max 2021.1 Update 以降で使用可能です。
オプションの ignorecase:
キーワード引数の既定値は true です。文字列を含む配列に大文字と小文字を区別する比較を実行するには、この値を false として指定する必要があります。
tolerance:
オプション キーワード引数が指定され、実際の戻り値の数値要素のいずれかが必要な値と異なり、対応する要素が許容差値を超えている場合は、false を返します。
例:
次の場合は、すべて false を返します。
assert_array_equal #(1) #(1.)
assert_array_equal #(1) #(1,2)
assert_array_equal #(1,2) #(1)
assert_array_equal #(1) #(2)
assert_array_equal #(1.) #(2.)
assert_array_equal #([1,2]) #([1,3])
assert_array_equal #([1,2,3]) #([1,2,4])
assert_array_equal #([1,2,3,4]) #([1,2,3,5])
assert_array_equal #(matrix3 1) #(transmatrix [1,1,1])
assert_array_equal #("aa") #("ab")
assert_array_equal #(1.) #(2.) tolerance:0.5
assert_array_equal #("aa") #("AA") ignoreCase:false
<boolean>assert_matchpattern expected actual [message:<string>] [ignoreCase:<boolean>]
2 つ目の引数として渡された式の戻り値が、必要な文字列と異なる場合は false を返します。 2 番目の引数(actual
)が一致パターンになることがあります。ここで、?は 1 文字を表し、* は 1 文字以上を表します。
オプションの ignorecase:
キーワード引数の既定値は true です。文字列に大文字と小文字を区別する比較を実行するには、この値を false として指定する必要があります。
例:
次の場合は、すべて false を返します。
s="text1"
assert_matchpattern "tex?" s
assert_matchpattern "T*" s ignoreCase:false
<boolean>assert_bitarray_equal expected_bitarray actual_bitarray [message:<string>]
2 つ目の引数として渡された式の戻り値が、予想された配列と異なる場合は false を返します。 3ds Max 2021.1 Update 以降で使用可能です。### AssertReporter
構造体
グローバルな AssertReporter
C++ 構造体は、アサートの結果を収集し、テストの実行値に結果を管理したり、結果にアクセスするためのメソッドを提供します。
一般的なメソッド:
<void>AssertReporter.Clear()
AssertReporter
からすべてのアサーション エントリを削除し、すべてのエラーおよび例外の結果をゼロにリセットします。
レポート メソッド:
<string array>AssertReporter.GetAssertFailures()
AssertReporter
に格納されている assert エラーを含む文字列の配列を返します。
<integer>AssertReporter.GetAssertFailuresCount()
AssertReporter
に格納されている assert エラーの数を返します。これは、(AssertReporter.GetAssertFailuresCount()).count
を呼び出すよりも迅速に処理できます。
<string array>AssertReporter.GetExceptionFailures()
AssertReporter
に記録されている例外を含む文字列の配列を返します。
<integer>AssertReporter.GetExceptionFailuresCount()
AssertReporter
に格納されている例外エラーの数を返します。これは、(AsserReporter.GetExceptionFailuresCount()).count
を呼び出すよりも迅速に処理できます。
<array of strings>AssertReporter.GetMessages()
AssertReporter
を通じて記録されているメッセージを含む文字列を、その種類に関係なく返します。
ログ メソッド:
<void>AssertReporter.LogMessage <string>Message
メッセージを AssertReporter
に保存します。このメッセージは、AssertReporter.GetMessages()
を使用して後から取得できます。
<void>AssertReporter.LogException <string>Message
メッセージを例外として AssertReporter
に保存します。例外メッセージは、AssertReporter.GetExceptionFailures()
を使用して後から取得できます。
<void>AssertReporter.LogAssertFailure <string>Message
メッセージを assert エラーとして AssertReporter
に保存します。エラー メッセージは、AssertReporter.GetAssertFailures()
を使用して後から取得できます。
状態メソッド:
次の 2 つのメソッドを使用して、テストの実行中のいくつかの状態を保存できます。また、これらは将来の柔軟性のためにのみ提供されています。
<void>AssertReporter.SetUserData <string>UserData
ユーザ定義のカスタム文字列を AssertReporter
に保存します。
<void>AssertReporter.GetUserData <value>argument
ユーザ定義のカスタム文字列を AssertReporter
から取得します。
例:
次の例は、多くの変数が関数のローカル スコープで定義され、各変数がその値を検証するために 1 つの assert でテストされる人工テスト(これらのテストの多くは実際の assert メッセージを生成するために設定されています)における assert 関数と AssertReporter の機能を示しています。
fn TestAsserts =
(
local undefinedValue
local booleanTrueVariable = true
local booleanFalseVariable = false
local floatVariable = 1.0
local stringVariable = "MAXScript"
local point3Variable = [1,2,3]
local matrix3Variable = matrix3 [1,0,0] [0,1,0] [0,0,1] [100,200,-300]
--this is line 10
AssertReporter.Clear()
AssertReporter.LogMessage "Asserts Demo Start..."
AssertReporter.SetUserData ("Tested Values Were:"+ undefinedValue as string + "," + booleanTrueVariable as string + "," + booleanFalseVariable as string + "," + floatVariable as string + ","+stringVariable+","+point3Variable as string + ","+matrix3Variable as string)
assert_true booleanFalseVariable
assert_false booleanTrueVariable
assert_equal 2.0 floatVariable
assert_not_equal 2.0 floatVariable
assert_defined undefinedValue
assert_undefined floatVariable
assert_float 1.1 floatVariable tolerance:0.01
assert_float 1.1 floatVariable tolerance:0.2
assert_string_equal "Python" stringVariable
assert_string_equal "maxscript" stringVariable ignorecase:false message:(" MAXScript is usually case-insensitive, but this assert isn't!")
assert_point3_equal [1.0,2.0,3.1] point3Variable
assert_point3_equal [1.0,2.0,3.1] point3Variable tolerance:0.1
assert_matrix_equal (matrix3 1) matrix3Variable
if floatVariable > 0.0 do AssertReporter.LogAssertFailure "FloatVariable seems to be positive, I am upset!"
AssertReporter.LogException "Nothing Really Worked!"
AssertReporter.LogMessage "Asserts Demo End."
--this is line 30
format "--All Logged Messages:\n"
print (AssertReporter.GetMessages())
format "--User Data:\n"
print (AssertReporter.GetUserData 0)
format "--Failures: %\n" (AssertReporter.GetAssertFailuresCount())
print (AssertReporter.GetAssertFailures())
format "--Exceptions: %\n" (AssertReporter.GetExceptionFailuresCount())
print (AssertReporter.GetExceptionFailures())
)
TestAsserts()
上記のコードを "c:\temp\TestAsserts.ms" という名前のファイルに保存し、スクリプトを評価すると、次のような出力が生成されます。
TestAsserts()
--All Logged Messages:
"Asserts Demo Start..."
"Assert - Expected true, got false - (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 14"
"Assert - Expected false, got true - (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 15"
"Assert - Expected 2.0, got 1.0 - (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 16"
"Assert - Expected "defined", got undefined - (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 18"
"Assert - Expected undefined, got 1.0 - (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 19"
"Assert - Expected 1.1, got 1.0 - (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 20"
"Assert - Expected "Python", got "MAXScript" - (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 22"
"Assert - MAXScript is usually case-insensitive, but this assert isn't! - Expected "maxscript", got "MAXScript" (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 23"
"Assert - Expected [1,2,3.1], got [1,2,3] - (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 24"
"Assert - Expected (matrix3 [1,0,0] [0,1,0] [0,0,1] [0,0,0]), got (matrix3 [1,0,0] [0,1,0] [0,0,1] [100,200,-300]) - (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 26"
"FloatVariable seems to be positive, I am upset!"
"Nothing Really Worked!"
"Asserts Demo End."
--User Data:
"Tested Values Were:undefined,true,false,1.0,MAXScript,[1,2,3],(matrix3 [1,0,0] [0,1,0] [0,0,1] [100,200,-300])"
--Failures: 11
"Assert - Expected true, got false - (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 14"
"Assert - Expected false, got true - (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 15"
"Assert - Expected 2.0, got 1.0 - (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 16"
"Assert - Expected "defined", got undefined - (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 18"
"Assert - Expected undefined, got 1.0 - (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 19"
"Assert - Expected 1.1, got 1.0 - (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 20"
"Assert - Expected "Python", got "MAXScript" - (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 22"
"Assert - MAXScript is usually case-insensitive, but this assert isn't! - Expected "maxscript", got "MAXScript" (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 23"
"Assert - Expected [1,2,3.1], got [1,2,3] - (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 24"
"Assert - Expected (matrix3 [1,0,0] [0,1,0] [0,0,1] [0,0,0]), got (matrix3 [1,0,0] [0,1,0] [0,0,1] [100,200,-300]) - (C:\Temp\TestAsserts.ms) in frame TestAsserts, at line 26"
"FloatVariable seems to be positive, I am upset!"
--Exceptions: 1
"Nothing Really Worked!"
OK
21 行目の assert はエラーを生成していません。これは、tolerance が 0.2 に設定され、前の 20 行目の Assert で許可されなかった 1.1 に対し、1.0 でテストに成功しているからです。
23 行目では、既定のメッセージの前にカスタム メッセージが追加されています。
25 行目も、許容差の値が大きく設定されているため、成功しています。
このように、これらの assert 関数を使用すると、さまざまな値型の変数の状態に関するデータを収集したり、式の値を返したり、AssertReporter で情報を収集してコードのテスト実行後に分析したり、ログ ファイルにダンプして後から処理することができます。