mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-11-04 14:18:59 +00:00
Keyed archiving preserves view hierarchies created in code. Decoded views retain their content, subviews and state, and each view class is verified against its own description before archiving. * CPAccordionView: Add CPCoding to CPAccordionView and CPAccordionViewItem. * CPBox: * Encode the content, title and box views unconditionally. * Clear the superviews of the box and title views during decoding. * CPButton: Initialize the value to CPOffState. * CPMapTable: Add CPCoding. * CPPopUpButton: Clear the inherited button value. * CPSearchField: Update the cancel button when the object value changes. * CPSplitView: Return nil from dividerColor when the theme defines no divider image. * CPStepper: Discard the decoded buttons before recreating them. * CPTabView: * Encode the current tab view items. * Exclude the tabs from the encoded subviews. * CPTokenField: * Discard the decoded scroll view before recreating it. * Add the decoded tokens to the new document view. * CPVisualEffectView: Resolve the backdrop filter property only when a DOM is available. * CPBoxTest: Verify preservation of the content view, hierarchy and title, and decoding of an untitled box without warnings. * CPButtonTest: Verify the initial value of a button. * CPMapTableTest: Verify preservation of entries through archiving. * DropInArchiveFixtures: Add populated view fixtures, tree comparison, and round trip and saved archive helpers. * DropInArchiveGenerator: Save cib descriptions and view archives, and write no archive data if any view fails its round trip. * DropInArchiveTest: Verify new archives, saved archives and reference cibs, and treat decoding warnings as failures. * DropInSnapshot: * Describe the view hierarchy through private views, with state and content. * Add DropInWithFixedScrollerStyle. * DropInArchives, DropInCibs: Add saved view archives, cib descriptions and reference cibs.
195 lines
5.8 KiB
Plaintext
195 lines
5.8 KiB
Plaintext
/*
|
|
* DropInArchiveTest.j
|
|
* AppKit
|
|
*
|
|
* Created by David Richardson on 31/10/2026.
|
|
* Copyright David Richardson 2026.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
@import "DropInArchiveFixtures.j"
|
|
|
|
/*
|
|
Every application with an interface built in Xcode depends on cibs, and those
|
|
cibs were written before the application's frameworks were last updated. An
|
|
application that updates its frameworks does not rebuild them first, so the
|
|
frameworks must keep reading what was already written. A new key may be added to
|
|
an archive. Its absence from an older archive must then mean the old behavior,
|
|
and not a new default.
|
|
|
|
The reference for a view is the view before it was archived, so a build cannot
|
|
pass by restoring something else. A warning during decoding is a failure. The
|
|
classes under test are those in the drop-in baseline, so a class cannot leave
|
|
these tests unnoticed.
|
|
|
|
DropInArchiveGenerator.j saves the data these tests read. Each test reports every
|
|
difference it finds.
|
|
*/
|
|
var fs = require("fs"),
|
|
path = require("path");
|
|
|
|
@implementation DropInArchiveTest : OJTestCase
|
|
{
|
|
CPString resources;
|
|
CPArray warnings;
|
|
Function logWarning;
|
|
}
|
|
|
|
- (void)setUp
|
|
{
|
|
// This will init the global var CPApp which are used internally in the AppKit
|
|
[[CPApplication alloc] init];
|
|
|
|
resources = path.join(path.dirname(__filename), "Resources");
|
|
warnings = [];
|
|
logWarning = CPLog.warn;
|
|
|
|
CPLog.warn = function(aMessage)
|
|
{
|
|
warnings.push(String(aMessage));
|
|
};
|
|
}
|
|
|
|
- (void)tearDown
|
|
{
|
|
CPLog.warn = logWarning;
|
|
}
|
|
|
|
- (id)jsonNamed:(CPString)aName
|
|
{
|
|
return JSON.parse(fs.readFileSync(path.join(resources, aName), {encoding: 'utf-8'}));
|
|
}
|
|
|
|
- (CPArray)viewClassNames
|
|
{
|
|
return Object.keys([self jsonNamed:@"DropInBaseline.json"].construction).filter(function(aClassName)
|
|
{
|
|
return !DropInArchiveExclusion(aClassName);
|
|
});
|
|
}
|
|
|
|
- (void)assertNoDifferences:(CPArray)differences
|
|
{
|
|
[self assertTrue:differences.length === 0 message:"\n" + differences.join("\n")];
|
|
}
|
|
|
|
- (void)moveWarningsNamed:(CPString)aName into:(CPArray)differences
|
|
{
|
|
warnings.forEach(function(aWarning)
|
|
{
|
|
differences.push(aName + " warned: " + aWarning);
|
|
});
|
|
|
|
warnings = [];
|
|
}
|
|
|
|
/*
|
|
A view that is archived and read back must be the same view, with the same
|
|
content.
|
|
*/
|
|
- (void)testNewArchivesRestoreTheOriginalView
|
|
{
|
|
var differences = [];
|
|
|
|
[self viewClassNames].forEach(function(aClassName)
|
|
{
|
|
try
|
|
{
|
|
var result = DropInArchiveRoundTrip(objj_getClass(aClassName));
|
|
|
|
DropInTreeDifferences(result.original, result.decoded, aClassName, differences);
|
|
}
|
|
catch (anException)
|
|
{
|
|
differences.push(aClassName + ": " + String(anException));
|
|
}
|
|
|
|
[self moveWarningsNamed:aClassName into:differences];
|
|
});
|
|
|
|
[self assertNoDifferences:differences];
|
|
}
|
|
|
|
/*
|
|
An archive written by main must restore the view it was written from.
|
|
*/
|
|
- (void)testExistingArchivesRestoreTheOriginalView
|
|
{
|
|
var archivePath = path.join(resources, @"DropInArchives.json");
|
|
|
|
[self assertTrue:fs.existsSync(archivePath) message:@"DropInArchives.json has not been generated"];
|
|
|
|
var archives = [self jsonNamed:@"DropInArchives.json"],
|
|
differences = [];
|
|
|
|
[self viewClassNames].forEach(function(aClassName)
|
|
{
|
|
var saved = archives[aClassName];
|
|
|
|
if (!saved)
|
|
return differences.push(aClassName + ": no saved archive");
|
|
|
|
try
|
|
{
|
|
DropInTreeDifferences(saved.state, DropInSavedArchiveTree(saved.archive), aClassName, differences);
|
|
}
|
|
catch (anException)
|
|
{
|
|
differences.push(aClassName + ": " + String(anException));
|
|
}
|
|
|
|
[self moveWarningsNamed:aClassName into:differences];
|
|
});
|
|
|
|
[self assertNoDifferences:differences];
|
|
}
|
|
|
|
/*
|
|
These are fixed copies of real cibs, and they do not follow their sources. They are
|
|
Tests/Manual/SmartFoldersTest/Resources/PredicateEditor.cib and
|
|
Tests/Manual/TextEditor/Resources/DocumentWindow.cib, as of commit 5db5adac0.
|
|
Loading one must produce the same windows, views and frames as main. The MainMenu
|
|
cibs of those applications are not here, because they need application classes
|
|
to load.
|
|
*/
|
|
- (void)testExistingCibsProduceTheSameObjects
|
|
{
|
|
var expected = [self jsonNamed:@"DropInCibs.json"],
|
|
differences = [];
|
|
|
|
for (var cibName in expected)
|
|
{
|
|
var rawString = fs.readFileSync(path.join(resources, "DropInCibs", cibName), {encoding: 'utf-8'}),
|
|
current = DropInCibTree(cibName, rawString),
|
|
expectedTrees = expected[cibName];
|
|
|
|
if (current.length !== expectedTrees.length)
|
|
{
|
|
differences.push(cibName + ": " + expectedTrees.length + " top level objects are now " + current.length);
|
|
continue;
|
|
}
|
|
|
|
for (var index = 0; index < current.length; index++)
|
|
DropInTreeDifferences(JSON.parse(expectedTrees[index]), JSON.parse(current[index]), cibName, differences);
|
|
|
|
[self moveWarningsNamed:cibName into:differences];
|
|
}
|
|
|
|
[self assertNoDifferences:differences];
|
|
}
|
|
|
|
@end
|