Skip to content

Commit

Permalink
chore: start run tests
Browse files Browse the repository at this point in the history
  • Loading branch information
aanorbel committed Jul 30, 2024
1 parent c6335b3 commit 0509bbf
Show file tree
Hide file tree
Showing 6 changed files with 321 additions and 9 deletions.
4 changes: 4 additions & 0 deletions ooniprobe.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
79BC192B2C53AD890017B7EC /* InputTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79BC192A2C53AD890017B7EC /* InputTableViewCell.swift */; };
79BC192D2C53ADC20017B7EC /* NettestTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79BC192C2C53ADC20017B7EC /* NettestTableViewCell.swift */; };
79BC192F2C53B3D10017B7EC /* NettestStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79BC192E2C53B3D10017B7EC /* NettestStatus.swift */; };
79BC19312C53C24E0017B7EC /* DashboardTableViewController+Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79BC19302C53C24E0017B7EC /* DashboardTableViewController+Actions.swift */; };
79DB62342C2D8F020076FA0C /* TestOverviewViewController+TableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79DB62332C2D8F020076FA0C /* TestOverviewViewController+TableView.swift */; };
7AED19812A6EC9A2003B265A /* libresolv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 7AED19802A6EC9A2003B265A /* libresolv.tbd */; };
7AED19832A6EC9C7003B265A /* libresolv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 7AED19822A6EC9C7003B265A /* libresolv.tbd */; };
Expand Down Expand Up @@ -240,6 +241,7 @@
79BC192A2C53AD890017B7EC /* InputTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputTableViewCell.swift; sourceTree = "<group>"; };
79BC192C2C53ADC20017B7EC /* NettestTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NettestTableViewCell.swift; sourceTree = "<group>"; };
79BC192E2C53B3D10017B7EC /* NettestStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NettestStatus.swift; sourceTree = "<group>"; };
79BC19302C53C24E0017B7EC /* DashboardTableViewController+Actions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DashboardTableViewController+Actions.swift"; sourceTree = "<group>"; };
79DB62332C2D8F020076FA0C /* TestOverviewViewController+TableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TestOverviewViewController+TableView.swift"; sourceTree = "<group>"; };
7A8CB0932ADDDAC1005AB2BC /* libcrypto.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = libcrypto.xcframework; path = Pods/libcrypto/libcrypto.xcframework; sourceTree = "<group>"; };
7A8CB0942ADDDAC1005AB2BC /* libevent.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = libevent.xcframework; path = Pods/libevent/libevent.xcframework; sourceTree = "<group>"; };
Expand Down Expand Up @@ -767,6 +769,7 @@
ED0A61FF200B52A300235E70 /* OONIRun */,
EDDB0B561FFF32B900EFD9C8 /* Settings */,
EDDB0B631FFF6C8B00EFD9C8 /* Onboarding */,
79BC19302C53C24E0017B7EC /* DashboardTableViewController+Actions.swift */,
);
path = View;
sourceTree = "<group>";
Expand Down Expand Up @@ -1605,6 +1608,7 @@
EDBBB2DF203D2EF200B84F6F /* TestResultTableViewCell.m in Sources */,
ED90A92D2198DE5100204B46 /* Options.m in Sources */,
ED4D1E5D24629A870087B36D /* OONIApi.m in Sources */,
79BC19312C53C24E0017B7EC /* DashboardTableViewController+Actions.swift in Sources */,
D4A2F5DF1A6C3244001B8460 /* main.m in Sources */,
ED5F8A2A1F77C4AA0093C8F5 /* VersionUtility.m in Sources */,
ED4F77F5265E3C5A00C28AC0 /* ProxySettings.m in Sources */,
Expand Down
2 changes: 1 addition & 1 deletion ooniprobe/OONIDescriptor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public class Nettest: NSObject {
/// The class also provides a method to get the OONI descriptors for the OONI dashboard.
/// The class also provides a method to get the test suite for the current descriptor.
@objc(OONIDescriptor)
public class OONIDescriptor: NSObject {
public class OONIDescriptor: NSObject,Identifiable {

// MARK: Initializers
init(name: String,
Expand Down
300 changes: 300 additions & 0 deletions ooniprobe/View/DashboardTableViewController+Actions.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,300 @@
import Foundation
import SwiftUI

extension DashboardTableViewController {
@objc @IBAction private func runAll() {

if let descriptorList = self.items as NSArray as? [OONIDescriptor]{

let hostingController = UIHostingController(
rootView: ModalView(
descriptors: descriptorList.map { descriptor in OONIDescriptorStatus(descriptor: descriptor) },
runTests: { descriptors in
if(TestUtility.checkConnectivity(self) && TestUtility.checkTestRunning(self)){
RunningTest.current().setAndRun(
NSMutableArray(array: descriptors.filter{ descriptor in
descriptor.isSelected
}.map{ descriptor in
descriptor.getTestSuites()
}),
inView: self
)
}
self.dismiss(animated: true, completion: nil)

}
)
)

hostingController.modalPresentationStyle = .formSheet
present(hostingController, animated: true, completion: nil)
}

}
}

// MARK: - OONIDescriptorStatus

/// A struct that represents the status of an OONIDescriptor.
class OONIDescriptorStatus : ObservableObject {
var descriptor: OONIDescriptor
@Published var nettests: [NettestStatus]
@Published var isSelected: Bool = false
@Published var isExpanded: Bool = true

init(descriptor: OONIDescriptor) {
self.descriptor = descriptor
self.nettests = descriptor.nettest.map { nettest in NettestStatus(nettest: nettest) }
}


@objc public func getTestSuites() -> Any {
descriptor.nettest = nettests.filter{ nettest in
nettest.isSelected
}.map{ nettest in
nettest.nettest
}
return DynamicTestSuite(descriptor: descriptor)
}
}


struct ModalView: View {

@State var descriptors: [OONIDescriptorStatus]
var runTests: (([OONIDescriptorStatus]) -> Void) // Event listener closure

var body: some View {
VStack(alignment: .leading,spacing: 10){
Text("Select the tests to run")
Button(action: {
toggleStatusForAll(true)
}, label: {
Text("Select all tests")

.padding(.all,10)
.foregroundColor(Color("color_blue5"))
.overlay(
RoundedRectangle(cornerRadius: 32)
.stroke(Color("color_blue5"), lineWidth: 2)
)
})
.cornerRadius(32)
Button(action: {
toggleStatusForAll(false)
}, label: {
Text("Deselect all tests")

.padding(.all,10)
.foregroundColor(Color("color_blue5"))
.overlay(
RoundedRectangle(cornerRadius: 32)
.stroke(Color("color_blue5"), lineWidth: 2)
)
})
.cornerRadius(32)

RunTestsUITableViewWrapper(
descriptors: $descriptors,
didSelectRow: { indexPath in

})
HStack {
Spacer()

Button(action: {
runTests(descriptors)
}, label: {
Text("Run test")

.padding(.all,10)
.foregroundColor(Color("color_white"))
.background(Color("color_blue5"))
.overlay(
RoundedRectangle(cornerRadius: 32)
.stroke(Color("color_blue5"), lineWidth: 2)
)
})
.cornerRadius(32)
Spacer()

}

}
.padding()
}

func toggleStatusForAll(_ newState: Bool) {
descriptors.forEach({ descriptor in
descriptor.isSelected = newState
descriptor.nettests.forEach({ nettest in
nettest.isSelected = newState
})
})

descriptors = descriptors
}
}


// MARK: - RunTestsUITableViewWrapper

/// A SwiftUI view that wraps a UITableView.
struct RunTestsUITableViewWrapper: UIViewRepresentable {
@Binding var descriptors: [OONIDescriptorStatus]
var didSelectRow: ((IndexPath) -> Void) // Event listener closure


func makeUIView(context: Context) -> UITableView {
let tableView = UITableView()
tableView.dataSource = context.coordinator
tableView.delegate = context.coordinator
tableView.register(DescriptorTableViewCell.self, forCellReuseIdentifier: "descriptor_cell")
tableView.register(NettestTableViewCell.self, forCellReuseIdentifier: "nettests_cell")
tableView.register(InputTableViewCell.self, forCellReuseIdentifier: "inputs_cell")
return tableView
}

func updateUIView(_ uiView: UITableView, context: Context) {
uiView.reloadData()
}

func makeCoordinator() -> Coordinator {
Coordinator(self)
}

/// A class that conforms to the UITableViewDataSource and UITableViewDelegate protocols.
class Coordinator: NSObject, UITableViewDataSource, UITableViewDelegate {
var parent: RunTestsUITableViewWrapper

init(_ parent: RunTestsUITableViewWrapper) {
self.parent = parent
}

func numberOfSections(in tableView: UITableView) -> Int {
parent.descriptors.count
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let section = parent.descriptors[section]
if section.isExpanded {
return section.nettests.count + 1
} else {
return 1 // Return 1 if the section is not expanded (only the section header)
}
}


func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {


if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "descriptor_cell") as! DescriptorTableViewCell

cell.configure(
with: parent.descriptors[indexPath.section],
onToggleChange: { [weak self] newValue in
self?.parent.descriptors[indexPath.section].isSelected = newValue
self?.parent.didSelectRow(indexPath)
tableView.reloadData()
}
)
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "nettests_cell") as! NettestTableViewCell

let inputs = parent.descriptors[indexPath.section].nettests[indexPath.row - 1]
cell.configure(
with: inputs,
isChild: true,
onToggleChange: { [weak self] newValue in
self?.parent.descriptors[indexPath.section].nettests[indexPath.row - 1].isSelected = newValue

self?.parent.didSelectRow(indexPath)
tableView.reloadData()
}
)

return cell
}
}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)

if indexPath.row == 0{
parent.descriptors[indexPath.section].isExpanded = !parent.descriptors[indexPath.section].isExpanded
}

UIView.transition(
with: tableView,
duration: 0.35,
options: .transitionCrossDissolve,
animations: {
tableView.reloadData()
}
)

}
}
}



// MARK: - Descriptor views and TableCell

/// A SwiftUI view that represents a section in the table view.
struct DescriptorTableCell: View {
var item: OONIDescriptorStatus
@Binding var isSelected: Bool

var body: some View {
HStack {
Text(LocalizationUtility.getNameForTest(item.descriptor.title))
.font(.custom("FiraSans-Regular", size: 14.0))
.foregroundColor(Color("color_gray9"))
.lineLimit(1)
.layoutPriority(1)
Image(systemName: item.isExpanded ? "chevron.up" : "chevron.down")
Toggle(isOn: $isSelected) {}.toggleStyle(iOSCheckboxToggleStyle())
}
}
}

/// A UITableViewCell subclass that displays a section in the table view.
class DescriptorTableViewCell: UITableViewCell {
private var hostingController: UIHostingController<DescriptorTableCell>?

/// Configures the cell with the specified data.
/// - Parameters:
/// - data: The NettestStatus object.
/// - onToggleChange: A closure that is called when the toggle is changed.
func configure(with data: OONIDescriptorStatus, onToggleChange: @escaping (Bool) -> Void) {
// Create a binding to pass the data to the SwiftUI view
let binding = Binding<Bool>(
get: { data.isSelected },
set: { newValue in
data.isSelected = newValue
onToggleChange(newValue)
}
)

let toggleCellView = DescriptorTableCell(item: data, isSelected: binding)

if let hostingController = hostingController {
hostingController.rootView = toggleCellView
} else {
hostingController = UIHostingController(rootView: toggleCellView)
if let hostingView = hostingController?.view {
hostingView.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(hostingView)
NSLayoutConstraint.activate([
hostingView.topAnchor.constraint(equalTo: contentView.topAnchor),
hostingView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
hostingView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
hostingView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
])
}
}
}
}
4 changes: 3 additions & 1 deletion ooniprobe/View/RunTest/Rows/InputTableViewCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ struct InputTableView: View {

var body: some View {
HStack {
Text(item).font(.callout)
Text(item)
.font(.custom("FiraSans-Regular", size: 14.0))
.foregroundColor(Color("color_gray9"))
Spacer()
}
}
Expand Down
19 changes: 12 additions & 7 deletions ooniprobe/View/RunTest/Rows/NettestTableViewCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,23 @@ struct iOSCheckboxToggleStyle: ToggleStyle {
/// A SwiftUI view that represents a section in the table view.
struct NettestTableCell: View {
var item: NettestStatus
var isChild: Bool
@Binding var isSelected: Bool

var body: some View {
HStack {
Text(LocalizationUtility.getNameForTest(item.nettest.name))
.font(.callout)
.font(.custom("FiraSans-Regular", size: 14.0))
.foregroundColor(Color("color_gray9"))
.lineLimit(1)
.layoutPriority(1)
if let inputs = item.nettest.inputs, !inputs.isEmpty {
Image(systemName: item.isExpanded ? "chevron.up" : "chevron.down")
} else {
Spacer()
.padding(EdgeInsets(top: 0, leading: isChild ? 16 : 0, bottom: 0, trailing: 0))
if(!isChild) {
if let inputs = item.nettest.inputs, !inputs.isEmpty {
Image(systemName: item.isExpanded ? "chevron.up" : "chevron.down")
} else {
Spacer()
}
}
Toggle(isOn: $isSelected) {}.toggleStyle(iOSCheckboxToggleStyle())
}
Expand All @@ -47,7 +52,7 @@ class NettestTableViewCell: UITableViewCell {
/// - Parameters:
/// - data: The NettestStatus object.
/// - onToggleChange: A closure that is called when the toggle is changed.
func configure(with data: NettestStatus, onToggleChange: @escaping (Bool) -> Void) {
func configure(with data: NettestStatus, isChild: Bool = false, onToggleChange: @escaping (Bool) -> Void) {
// Create a binding to pass the data to the SwiftUI view
let binding = Binding<Bool>(
get: { data.isSelected },
Expand All @@ -57,7 +62,7 @@ class NettestTableViewCell: UITableViewCell {
}
)

let toggleCellView = NettestTableCell(item: data, isSelected: binding)
let toggleCellView = NettestTableCell(item: data, isChild: isChild, isSelected: binding)

if let hostingController = hostingController {
hostingController.rootView = toggleCellView
Expand Down
Loading

0 comments on commit 0509bbf

Please sign in to comment.